Skip to content
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
64fab20
more work
QuantumExplorer Feb 17, 2026
f42b58d
Merge branch 'v1.0-dev' into zk
QuantumExplorer Feb 17, 2026
f8df452
more work
QuantumExplorer Feb 24, 2026
64ca962
Merge branch 'v1.0-dev' into zk
QuantumExplorer Feb 24, 2026
3cbf5ba
Merge remote-tracking branch 'origin/v1.0-dev' into zk
lklimek Feb 24, 2026
0cde65f
fix(spv): zero out stale per-address balances during reconciliation (…
lklimek Feb 24, 2026
0879c45
fix: handle malformed YAML gracefully in load_testnet_nodes_from_yml …
lklimek Feb 24, 2026
4d8b2b2
chore: let Claude write manual test scenarios for PRs (#634)
lklimek Feb 24, 2026
17650e9
build(flatpak): use only-arches for dynamic protoc architecture selec…
lklimek Feb 24, 2026
da00777
Merge branch 'v1.0-dev' into zk-extract/all-merged
lklimek Feb 24, 2026
7668de9
Merge remote-tracking branch 'origin/zk-extract/all-merged' into zk-e…
lklimek Feb 24, 2026
1ec2e7e
fix(ci): remove local path patches, use git deps for platform crates
lklimek Feb 24, 2026
0710295
fix(test): store wallet in DB before registering addresses
lklimek Feb 25, 2026
e078d0b
Merge remote-tracking branch 'origin/v1.0-dev' into zk-extract/all-me…
lklimek Feb 25, 2026
7e95598
Merge remote-tracking branch 'origin/v1.0-dev' into zk-extract/all-me…
lklimek Feb 25, 2026
afd7a4c
fix(build): restore shielded module declaration removed during merge
lklimek Feb 25, 2026
64651c5
fix(test): restore store_wallet calls lost in merge (#663)
Copilot Feb 25, 2026
e2060b2
Merge remote-tracking branch 'origin/v1.0-dev' into zk-extract/all-me…
lklimek Mar 6, 2026
91314ca
Merge remote-tracking branch 'origin/v1.0-dev' into zk-extract/all-me…
lklimek Mar 17, 2026
508817a
chore: update platform dependency to 3.1-dev branch
QuantumExplorer Mar 17, 2026
0cb6d7e
refactor: migrate shielded module from Result<T, String> to typed Tas…
lklimek Mar 17, 2026
a9f6c29
Merge origin/zk and migrate platform dependency to v3.1-dev
lklimek Mar 17, 2026
62961b1
Merge pull request #644 from dashpay/zk-extract/all-merged
QuantumExplorer Mar 22, 2026
d8285fa
Merge remote-tracking branch 'origin/zk' into zk
QuantumExplorer Mar 22, 2026
12b7c53
fix(ui): prevent settings password row from clipping right edge
QuantumExplorer Mar 23, 2026
1d0030d
Merge branch 'zk-fixes' of https://github.com/dashpay/dash-evo-tool i…
lklimek Mar 23, 2026
f0040f4
fix(db): consolidate migrations v28-v32 into v33
lklimek Mar 23, 2026
b29811c
Merge remote-tracking branch 'origin/v1.0-dev' into fix/consolidate-m…
lklimek Mar 23, 2026
19c4934
chore: pin platform dependency to zk-fixes revision
lklimek Mar 23, 2026
ab8a230
fix(db): address PR review — fresh schema, error propagation, rename …
lklimek Mar 23, 2026
f4efd64
fix(db): add foreign key constraints to shielded tables
lklimek Mar 23, 2026
9d4d65a
Merge remote-tracking branch 'origin/v1.0-dev' into fix/consolidate-m…
lklimek Mar 23, 2026
4d47ea4
fix(db): address PR #789 review — doc comments, migration default
lklimek Mar 23, 2026
ddea453
fix(db): remove duplicate shielded methods after v1.0-dev merge
lklimek Mar 23, 2026
0d4e359
chore: simplify shielded helpers comment in initialization.rs
lklimek Mar 23, 2026
89d8a97
fix(test): remove duplicate wallet store in register_test_address
lklimek Mar 23, 2026
875ee14
Merge pull request #789 from dashpay/fix/consolidate-migrations-v33-zk
lklimek Mar 24, 2026
e140c60
Merge remote-tracking branch 'origin/v1.0-dev' into zk
lklimek Mar 26, 2026
f2e8142
fix(mcp): resolve async lifetime errors for Rust 2024 edition
lklimek Mar 26, 2026
46ea490
chore: fix mcp dispatch
lklimek Mar 26, 2026
cfa1dbb
doc: remove obsolete manual teting docs
lklimek Mar 26, 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
601 changes: 471 additions & 130 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ qrcode = "0.14.1"
nix = { version = "0.31.1", features = ["signal"] }
eframe = { version = "0.33.3", features = ["persistence", "wgpu"] }
base64 = "0.22.1"
dash-sdk = { git = "https://github.com/dashpay/platform", rev = "93556aa4b", features = [
dash-sdk = { git = "https://github.com/dashpay/platform", branch = "feat/mempool-support", features = [
"core_key_wallet",
"core_key_wallet_manager",
"core_bincode",
"core_quorum-validation",
"core_verification",
"core_rpc_client",
"core_spv",
"shielded",
] }
zip32 = "0.2.0"
grovestark = { git = "https://www.github.com/dashpay/grovestark", rev = "5b9e289cca54c79b1305d5f4f40bf1148f1eb0e3" }
rayon = "1.8"
thiserror = "2.0.18"
Expand Down Expand Up @@ -107,6 +109,7 @@ debug = "line-tables-only"
level = "warn"
check-cfg = ["cfg(tokio_unstable)", "cfg(feature, values(\"testing\"))"]


[lints.clippy]
uninlined_format_args = "allow"

254 changes: 254 additions & 0 deletions docs/ai-design/2025-02-25-spv-peer-rework/manual-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
# Manual Test Scenarios: SPV Peer Status Rework

**Feature:** Replace SPV auto-stop with Connecting state and degraded-state warning
**Branch:** `fix/spv-peer-timeout`
**Date:** 2025-02-25

## Overview

These scenarios verify the reworked SPV peer connection lifecycle:

- SPV **no longer auto-stops** on peer timeout -- it keeps running and retrying peer discovery.
- New **four-state** connection indicator: Red (Disconnected), Orange/fast-pulse (Connecting), Orange/slow-pulse (Syncing), Green (Synced).
- After ~30 seconds with zero peers, a **degraded warning** appears in the tooltip ("Having trouble finding peers...") but SPV stays running.

---

## Global Preconditions

1. Dash Evo Tool is installed and launches successfully.
2. The application is configured for **SPV mode** unless stated otherwise.
3. At least one network (Testnet or Mainnet) is configured with valid DAPI endpoints.
4. Tester has access to network controls (firewall rules, VPN toggle) to simulate peer availability.

---

## Scenario 1: Fresh SPV Start on Good Network

**Goal:** Verify the Connecting -> Syncing -> Synced progression.

### Steps

1. Launch the application with normal network connectivity.
2. Observe the connection indicator immediately after SPV starts.
3. Hover over the indicator to read the tooltip.
4. Wait for peers to connect (usually within a few seconds).
5. Observe the indicator transition during sync phases.
6. Wait for sync to complete.

### Expected Results

- **Step 2:** Orange circle with **fast pulse** (`time * 2.5`). Tooltip header: "Connecting...".
- **Step 4:** Once peers connect, indicator remains orange but pulse slows (`time * 1.2`). Tooltip header changes to "Syncing". SPV label shows phase progress (e.g., "SPV: Headers: 12345 / 27000 (45%)").
- **Step 6:** Indicator turns **green** with normal pulse. Tooltip: "Ready\nSPV: Synced\nDAPI: Available (N unbanned / M total endpoints)".

---

## Scenario 2: Fresh SPV Start on Bad Network (No Peers)

**Goal:** Verify SPV stays running and shows degraded warning instead of stopping.

### Steps

1. Block outbound P2P peer connections (firewall on port 9999/19999).
2. Launch the application. Ensure DAPI endpoints are reachable.
3. Observe the indicator -- should show orange (Connecting).
4. Wait approximately 30 seconds.
5. Hover over the indicator to read the tooltip.
6. Continue waiting 1-2 minutes.

### Expected Results

- **Step 3:** Orange indicator with fast pulse. Tooltip: "Connecting...\nSPV: Starting\nDAPI: Available (...)".
- **Step 5:** After ~30s, tooltip adds: "\nHaving trouble finding peers. Check your connection." A **warning banner** also appears with the same text.
- **Step 6:** SPV **remains running** (does NOT stop). Indicator stays orange. SPV continues trying DNS lookups and peer discovery in the background.
- **Critical:** Verify NO "SPV disconnected" error banner. Verify `stop_spv()` is NOT called (check logs -- no "stopping SPV" message).
- **Recovery:** If you restore connectivity and peers connect, the warning banner **automatically clears** and the indicator transitions to Syncing/Synced.

---

## Scenario 3: Peers Disconnect Mid-Sync

**Goal:** Verify state transitions back to Connecting (not Disconnected) when peers drop.

### Steps

1. Start SPV and wait for it to begin syncing with peers (orange, slow pulse).
2. Block all peer connections via firewall.
3. Observe the indicator over the next 5-10 seconds.

### Expected Results

- **Step 2:** Peer count drops to 0. The `spv_no_peers_since` timer starts.
- **Step 3:** Indicator changes from slow-pulse orange (Syncing) to **fast-pulse orange (Connecting)**. SPV status remains `Syncing` but with 0 peers, `refresh_state()` maps this to `Connecting`.
- SPV does NOT stop. No error banner.
- After 30s of no peers, tooltip adds "Having trouble finding peers...".

---

## Scenario 4: Peers Reconnect After Disconnect

**Goal:** Verify seamless recovery when peers become available again.

### Steps

1. Complete Scenario 3 (SPV is in Connecting state, no peers).
2. Restore network connectivity (remove firewall rule).
3. Observe the indicator.

### Expected Results

- **Step 2-3:** Peers reconnect via SPV's internal discovery. `spv_no_peers_since` is cleared (`peers > 0` resets to `None`).
- Indicator transitions from fast-pulse orange (Connecting) to slow-pulse orange (Syncing) as peers connect and sync resumes.
- Eventually reaches green (Synced) once sync completes.
- No manual restart needed -- SPV recovered on its own.

---

## Scenario 5: Network Switch

**Goal:** Verify connection state resets cleanly on network switch.

### Steps

1. Confirm SPV is synced on current network (green indicator).
2. Switch to a different network via the network chooser.
3. Observe the indicator immediately after switch.
4. Wait for SPV to start on the new network.

### Expected Results

- **Step 2:** `ConnectionStatus::reset()` clears all state: `spv_status` -> Idle, `spv_connected_peers` -> 0, `spv_no_peers_since` -> None, `overall_state` -> Disconnected.
- **Step 3:** Indicator turns **red** momentarily.
- **Step 4:** Transitions to orange/Connecting, then Syncing, then green/Synced.

---

## Scenario 6: All DAPI Endpoints Banned

**Goal:** Verify that losing DAPI forces Disconnected even with SPV peers.

### Steps

1. Confirm SPV is synced (green indicator).
2. Cause all DAPI endpoints to become banned.
3. Observe the indicator after the next refresh cycle (within 1-4 seconds).

### Expected Results

- `refresh_state()` returns `Disconnected` because `dapi_available()` is false.
- Indicator turns **red**, regardless of SPV peer status.
- Tooltip: "Disconnected\nSPV: Synced\nDAPI: All M endpoints banned".

---

## Scenario 7: Connection Indicator Visual States

**Goal:** Verify all four visual states render correctly.

### Expected Results

| State | Color | Pulse | Background glow |
|---|---|---|---|
| Disconnected | Red (`error_color`) | None (`scale = 1.0`) | Same radius as main circle |
| Connecting | Orange (`warning_color`) | Fast pulse (`1.0 + 0.2 * sin(t*2.5)`) | Pulsating with 0.3 opacity |
| Syncing | Orange (`warning_color`) | Slow pulse (`1.0 + 0.15 * sin(t*1.2)`) | Pulsating with 0.3 opacity |
| Synced | Green (`success_color`) | Normal pulse (`1.0 + 0.2 * sin(t*2.0)`) | Pulsating with 0.3 opacity |

- Connecting and Syncing use the same orange color but differ in pulse rate.
- Only Disconnected does NOT call `repaint_animation`.

---

## Scenario 8: Tooltip Text for Each State

**Goal:** Verify tooltip accuracy across all SPV states.

| SPV Status | Peers | Overall State | Tooltip line 1 | Tooltip line 2 | Extra |
|---|---|---|---|---|---|
| Idle | 0 | Disconnected | "Disconnected" | "SPV: Idle" | -- |
| Starting | 0 | Connecting | "Connecting..." | "SPV: Starting" | After 30s: "Having trouble finding peers..." |
| Syncing | >0 | Syncing | "Syncing" | "SPV: Headers: X / Y (Z%)" | Phase progress shown |
| Syncing | 0 | Connecting | "Connecting..." | "SPV: <phase>" | After 30s: degraded warning |
| Running | >0 | Synced | "Ready" | "SPV: Synced" | -- |
| Running | 0 | Connecting | "Connecting..." | "SPV: Synced" | After 30s: degraded warning |
| Stopping | 0 | Connecting | "Connecting..." | "SPV: Stopping" | -- |
| Stopped | 0 | Disconnected | "Disconnected" | "SPV: Stopped" | -- |

---

## Scenario 9: Running State with Peers Dropping to Zero

**Goal:** Verify Running (Synced) transitions correctly when peers vanish.

### Steps

1. Confirm green indicator (SPV Running, peers connected).
2. Block peer connections.
3. Observe the indicator over 30+ seconds.

### Expected Results

- Once peer count drops to 0, `refresh_state()` maps active SPV with zero peers to `Connecting` (fast orange pulse).
- **Wait** -- `Running` status means sync finished. The SPV library may transition to a different status internally if peers drop. Observe actual SpvStatus transitions.
- If SPV stays `Running` with 0 peers: indicator should remain **orange** (`Connecting`), and the `spv_no_peers_since` timer continues without calling `stop_spv()`.
- After 30s with 0 peers, degraded warning banner and tooltip appear.

---

## Scenario 10: Long-Running Stability

**Goal:** Verify no resource leaks from peer tracking.

### Steps

1. Launch and sync SPV fully.
2. Note memory usage (RSS).
3. Run for 1+ hour with occasional peer churn (toggle connectivity 2-3 times).
4. Check memory every 15 minutes.

### Expected Results

- Memory stable (no unbounded growth).
- `spv_no_peers_since` is `Option<Instant>` (fixed size), `spv_connected_peers` is `AtomicU16`.
- After peer churn, returns to Synced without stale state.
- No Mutex poisoning or deadlock warnings in logs.

---

## Scenario 11: RPC Mode Unaffected

**Goal:** Verify SPV peer logic doesn't interfere with RPC mode.

### Steps

1. Launch in RPC mode (Dash Core wallet connected).
2. Verify indicator follows RPC/ZMQ status.
3. Stop Dash Core.
4. Observe indicator.

### Expected Results

- No SPV timeout logic is involved.
- Green when RPC online + ZMQ connected + DAPI available; red otherwise.
- Tooltip shows RPC-specific content.
- No "Having trouble finding peers..." or SPV-related messages.

---

## Scenario 12: Connecting State vs Syncing Pulse Differentiation

**Goal:** Verify the visual difference between Connecting and Syncing is noticeable.

### Steps

1. Start SPV with peers blocked -- observe Connecting state pulse.
2. Unblock peers -- observe transition to Syncing state pulse.
3. Compare the two pulse rates side by side (or record video).

### Expected Results

- **Connecting** pulse is noticeably faster (2.5 Hz base) with slightly larger amplitude.
- **Syncing** pulse is calmer (1.2 Hz base) with smaller amplitude.
- Both are orange -- the pulse rate is the primary visual differentiator.
- Transition between states should be smooth (no flicker or jump).
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Manual Test Scenarios: SPV Sync Error Status

## Context

When SPV sync encounters a fatal error (e.g., masternode sync failure), the app
should transition from "Syncing" to a distinct Error state, with the connectivity
icon turning **magenta** (with "!" glyph and slow pulse) and the tooltip showing
the specific error message.

## Prerequisites

- Dash Evo Tool built with the fix applied
- Access to Testnet (or a network where SPV sync can be triggered)
- SPV backend mode enabled (not RPC mode)

## Scenario 1: Verify error state on sync failure

**Goal:** Confirm the connectivity icon transitions to Error (magenta) when
SPV sync fails, distinct from Disconnected (red).

### Steps

1. Launch Dash Evo Tool and connect to Testnet in SPV mode.
2. Observe the top-left connectivity icon during sync — it should pulse orange
(Syncing state).
3. If sync completes successfully, the icon should turn green (Running state).
4. If sync fails (e.g., masternode QRInfo failure visible in logs), observe:
- The connectivity icon turns **magenta** with a slow pulsation and a white
**"!"** glyph in the center.
- Hovering over the icon shows tooltip: **"SPV sync error: {detail}"** with
the specific error message (e.g., "Sync manager Masternode failed: ...").
- Below that: **"SPV: Error"** detail line.
5. Open the Network Chooser screen and check the SPV status detail — it should
display the error message.

### Expected Result

- Icon transitions from orange (Syncing) to magenta (Error) on sync failure.
- Error icon is visually distinct from red (Disconnected) — magenta color,
slow pulse, "!" glyph.
- Tooltip shows "SPV sync error: ..." with the specific error message.
- Error message is visible in the status detail panel.

## Scenario 2: Verify normal sync still works

**Goal:** Confirm the fix doesn't break the happy path.

### Steps

1. Launch Dash Evo Tool and connect to Testnet in SPV mode.
2. Wait for sync to complete (may take several minutes on first sync).
3. Observe the connectivity icon transitions:
- Orange (Syncing) during sync.
- Green (Running) after sync completes.
4. Hover over the icon — tooltip should show "SPV synced" with "SPV: Running".

### Expected Result

- Sync completes normally, icon turns green.
- No false error transitions during normal sync.

## Scenario 3: Verify error message content

**Goal:** Confirm the error message stored in `last_error` contains useful
diagnostic information.

### Steps

1. Trigger an SPV sync that fails (e.g., by connecting to a network with
known chain lock propagation issues).
2. Check application logs for the error:
- Look for `SPV manager ... reported error: ...` log line.
3. Hover over the connectivity icon and verify the tooltip shows the same
error message (not a generic "Sync failed" without context).

### Expected Result

- Log contains `SPV manager "Masternode" reported error: Masternode sync failed: ...`.
- Tooltip shows the specific error from the sync manager, including
the block hash reference.

## Scenario 4: Verify Error state is distinct from Disconnected

**Goal:** Confirm the user can visually distinguish Error from Disconnected.

### Steps

1. With the app in SPV mode, trigger a sync error (Scenario 1).
2. Note the icon appearance: magenta, pulsating, "!" glyph.
3. Switch to a network with no connectivity (e.g., disconnect network).
4. Note the icon appearance: red, static, no glyph.

### Expected Result

- Error state: magenta circle, slow pulse, white "!" glyph.
- Disconnected state: red circle, static (no pulse), no glyph.
- The two states are clearly visually distinguishable.

## Notes

- The actual QRInfo chain lock error is an upstream issue
(dashpay/rust-dashcore#470). This fix ensures the app **reports** the error
correctly rather than silently staying stuck in "Syncing".
- A separate upstream issue (dashpay/rust-dashcore#469) tracks the missing
`try_emit_progress()` call on error paths in dash-spv.
Loading