Commit Graph
15 Commits
Author SHA1 Message Date
davide 3be761d97e fix(net): bound every request with a timeout
A server that stops answering without closing the socket left a running
sync waiting forever. Requests now fail with TimeoutException after 30 s
(10 s for the handshake, both configurable in ConnectAsync) and the
connection is marked dead so the app reconnects. See ADR 0034.
2026-11-03 12:18:39 +01:00
davide cb93927d15 fix(net): fail fast on a dead Electrum connection instead of hanging
After a protocol error (e.g. a malformed line) the read loop ended but
the client still reported IsConnected and later requests waited forever
for a response that could never arrive. The read loop now marks the
connection closed before failing pending requests, and RequestAsync
throws IOException on a closed connection. Adds regression tests and a
raw-line helper to the fake server.
2026-11-03 11:45:43 +01:00
davide ce8d777c63 chore: point repository URLs to palladium-coin/palladium-wallet
Update checker, in-app issue/guide links, issue template config and
README clone instructions now use the new repository.
2026-11-03 09:45:51 +01:00
davide 6d05a88073 perf(net): make ElectrumClient's in-flight request cap configurable
MaxInFlight was a hardcoded constant (32); different indexing servers
tolerate different levels of request concurrency before throttling, so
expose it as an optional ConnectAsync parameter instead of requiring a
recompile to tune initial-sync throughput against a given server.
2026-07-19 12:16:18 +02:00
davide 3460e53b4f feat(spv): verify Merkle proofs progressively, gate spendability on it
Balance/history now render as soon as tx downloads finish instead of
blocking on every historical Merkle proof, critical for mobile where
proof-checking can take much longer than the download itself. Proofs
continue to be checked in the background and each tx's Verified flag
catches up progressively; header ranges are now fetched in batches
(blockchain.block.headers) instead of one call per header to keep this
fast over high-latency links.

Coin selection (UtxoSpendability.IsSpendable) refuses to spend a UTXO
until its Merkle proof is actually checked, regardless of confirmation
count, so a server that fabricates a confirmed balance can get it
displayed early but never spent before the forgery is caught. The disk
cache only ever persists the fully-verified end state of a sync.

UI surfaces the new PendingVerificationSats/SpendableSats split with a
"verifying..." badge, and the sync save now runs off the UI thread to
avoid freezing on slower hardware.
2026-07-17 19:43:18 +02:00
davide d9c75eaec2 fix(net): ParsePeers must tolerate any JSON shape from the server
server.peers.subscribe is attacker-controlled data: ParsePeers assumed
the standard [ip, hostname, [features...]] shape and threw on anything
else (non-array response, wrong element types), and GetString() on a
JSON string containing invalid UTF-8 bytes threw InvalidOperationException
instead of failing to parse — both found by fuzzing. Any unexpected
shape or unparseable string now degrades to "no usable data" instead of
propagating an exception into the sync/discovery path.
2026-07-07 21:52:00 +02:00
davide 970253cbbe test(net): exercise UpdateChecker.CheckAsync end-to-end via a stub transport
CheckAsync built its own HttpClient inline, so nothing beyond tag
parsing was testable without hitting the real GitHub API. Added an
internal CheckAsync(currentVersion, HttpMessageHandler, ct) overload
(the public method now delegates to it) as a seam for a stub handler,
and tests for the full best-effort matrix: newer/equal/older/unparseable
tag, missing html_url, HTTP error status, malformed JSON, a thrown
HttpRequestException, and an unparseable local version — all of which
must resolve to null or the correct LatestRelease, never throw.
2026-07-07 16:26:06 +02:00
davide af2fdcc894 fix(gui): route runtime status messages through Loc instead of hardcoded Italian
Send/Donate/Sync/Wizard view models wrote status/error strings
directly in Italian ("Importo non valido.", "Errore: …", the TLS
pin-mismatch message, …), so a user running the app in English/German/
etc. still saw them in Italian despite the 6-language Loc system
covering the rest of the UI.

Added the missing Loc keys and routed every occurrence through
Loc.Tr(...). CertificatePinMismatchException (Core) no longer bakes an
Italian message into .Message; it now exposes Host/Port so the UI can
translate it, with an English fallback for any exception type the UI
doesn't specifically handle. Also drops the now-stale USERGUIDE.md
caveat about a few messages staying in Italian regardless of language.
2026-07-07 14:45:43 +02:00
davide e8ff99a768 test: add in-process fake ElectrumX server for network-layer testing
Real loopback TCP socket speaking newline-delimited JSON-RPC 2.0, optionally
TLS with a self-signed certificate, with per-method handlers and call
counters. Lets ElectrumClient, WalletSynchronizer, TransactionInspector, and
CertificatePinStore be exercised against the same code paths used in
production instead of being mocked.

Also exposes UpdateChecker's tag-parsing logic internally so its version
comparison can be tested without a real GitHub API call.
2026-07-02 23:20:32 +02:00
davide 27231c8eec fix(core): stop corrupted state from permanently breaking SSL and wallet loading
CertificatePinStore.Load threw on a corrupted pin file, blocking every SSL
connection until the user manually deleted it; EncryptedFile.IsEncrypted
threw on valid JSON with a non-object root or invalid UTF-16 instead of
returning false. Both now degrade gracefully. Found by property-based tests
while extending the test suite.
2026-07-02 23:19:46 +02:00
davide 34b4313a36 feat(app): check GitHub releases on startup and prompt for updates
Compares the running assembly version against the latest GitHub release
tag on every app launch (desktop and Android) and shows an in-app
overlay with the new version tag when one is available. Best-effort:
network/parse failures are silent, matching the app's existing
non-blocking startup checks.
2026-07-02 21:33:18 +02:00
davide 3d5a226a5a docs: translate all code comments to English (language policy)
Translate every Italian /// XML doc comment, <!-- --> XAML comment, and
// inline comment to English across all source files (Core, App, tests).
Add the language policy to CLAUDE.md (conversation Italian; all code
and docs English). Update one test assertion that checked an Italian
exception message that was also translated.
2026-06-16 14:40:11 +02:00
davideandClaude Opus 4.8 38e0f0a52e perf(net): batched writes, zero-alloc reads, bounded in-flight requests
Rework the ElectrumClient transport to cut latency and allocations
during sync:

- Channel-based single-reader write loop: drains the whole queue into a
  single WriteAsync+FlushAsync, replacing the _writeLock that forced one
  flush per message. N queued requests now travel in one TCP segment.
- PipeReader read loop parsing via Utf8JsonReader over pooled spans: no
  StreamReader/ReadLineAsync and no intermediate string per response.
- TcpClient.NoDelay = true: no Nagle wait on small packets.
- Concurrency gate (SemaphoreSlim, MaxInFlight=32) in RequestAsync:
  caps requests in flight to the server without serializing writes,
  avoiding floods (-101/-102) and connection drops on wallets with large
  history.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:27:40 +02:00
davide 1c2dacc27c feat(net): server registry, bootstrap servers, peer discovery 2026-06-11 11:27:16 +02:00
davide df60763ddd feat(net): ElectrumX client with TLS pinning 2026-06-11 10:46:57 +02:00