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.
This commit is contained in:
@@ -5,10 +5,10 @@ using System.Text.Json;
|
||||
namespace PalladiumWallet.Core.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Pinning TLS "trust on first use" (blueprint §9): al primo contatto la
|
||||
/// fingerprint SHA-256 del certificato del server viene salvata; ai successivi
|
||||
/// viene confrontata. Se cambia, la connessione va rifiutata e l'utente può
|
||||
/// sbloccare con un reset esplicito (caso tipico: server self-signed rinnovato).
|
||||
/// TLS "trust on first use" pinning (blueprint §9): on the first contact the
|
||||
/// server certificate's SHA-256 fingerprint is saved; on subsequent ones it is
|
||||
/// compared. If it changes, the connection must be rejected and the user can
|
||||
/// unlock with an explicit reset (typical case: renewed self-signed server).
|
||||
/// </summary>
|
||||
public sealed class CertificatePinStore(string filePath)
|
||||
{
|
||||
@@ -18,8 +18,8 @@ public sealed class CertificatePinStore(string filePath)
|
||||
Convert.ToHexString(SHA256.HashData(certificate.GetRawCertData())).ToLowerInvariant();
|
||||
|
||||
/// <summary>
|
||||
/// Verifica TOFU: true se il certificato è quello già visto (o se è il primo
|
||||
/// contatto, nel qual caso viene salvato). False = certificato cambiato.
|
||||
/// TOFU check: true if the certificate is the one already seen (or if it is the
|
||||
/// first contact, in which case it is saved). False = certificate changed.
|
||||
/// </summary>
|
||||
public bool VerifyOrPin(string host, int port, X509Certificate certificate)
|
||||
{
|
||||
@@ -36,7 +36,7 @@ public sealed class CertificatePinStore(string filePath)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Reset del certificato salvato per un server ("reset certificati SSL", §9).</summary>
|
||||
/// <summary>Reset the saved certificate for a server ("reset SSL certificates", §9).</summary>
|
||||
public bool Reset(string host, int port)
|
||||
{
|
||||
lock (_lock)
|
||||
|
||||
+13
-13
@@ -2,24 +2,24 @@ using System.Text.Json;
|
||||
|
||||
namespace PalladiumWallet.Core.Net;
|
||||
|
||||
/// <summary>Voce di storico di uno scripthash (blockchain.scripthash.get_history).</summary>
|
||||
/// <summary>History entry for a scripthash (blockchain.scripthash.get_history).</summary>
|
||||
public readonly record struct HistoryItem(string TxHash, int Height, long FeeSats);
|
||||
|
||||
/// <summary>UTXO riportato dal server (blockchain.scripthash.listunspent).</summary>
|
||||
/// <summary>UTXO reported by the server (blockchain.scripthash.listunspent).</summary>
|
||||
public readonly record struct UnspentItem(string TxHash, int TxPos, long ValueSats, int Height);
|
||||
|
||||
/// <summary>Prova di Merkle (blockchain.transaction.get_merkle).</summary>
|
||||
/// <summary>Merkle proof (blockchain.transaction.get_merkle).</summary>
|
||||
public sealed record MerkleProofResponse(int BlockHeight, int Pos, IReadOnlyList<string> Merkle);
|
||||
|
||||
/// <summary>Tip della catena notificato da blockchain.headers.subscribe.</summary>
|
||||
/// <summary>Chain tip notified by blockchain.headers.subscribe.</summary>
|
||||
public readonly record struct ChainTip(int Height, string HeaderHex);
|
||||
|
||||
/// <summary>Peer annunciato da server.peers.subscribe (porte null = non offerte).</summary>
|
||||
/// <summary>Peer announced by server.peers.subscribe (null ports = not offered).</summary>
|
||||
public sealed record PeerInfo(string Host, int? TcpPort, int? SslPort, string? Version);
|
||||
|
||||
/// <summary>
|
||||
/// Helper tipizzati sui metodi del protocollo (blueprint §10), sopra il
|
||||
/// trasporto JSON-RPC generico di <see cref="ElectrumClient"/>.
|
||||
/// Typed helpers over the protocol methods (blueprint §10), on top of the
|
||||
/// generic JSON-RPC transport of <see cref="ElectrumClient"/>.
|
||||
/// </summary>
|
||||
public static class ElectrumApi
|
||||
{
|
||||
@@ -29,7 +29,7 @@ public static class ElectrumApi
|
||||
return new ChainTip(r.GetProperty("height").GetInt32(), r.GetProperty("hex").GetString()!);
|
||||
}
|
||||
|
||||
/// <summary>Status corrente dello scripthash (null = mai usato).</summary>
|
||||
/// <summary>Current status of the scripthash (null = never used).</summary>
|
||||
public static async Task<string?> SubscribeScripthashAsync(this ElectrumClient c, string scripthash,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
@@ -89,7 +89,7 @@ public static class ElectrumApi
|
||||
return r.GetString()!;
|
||||
}
|
||||
|
||||
/// <summary>Fee stimata in coin/kB per il target dato; -1 se il server non sa stimare.</summary>
|
||||
/// <summary>Estimated fee in coin/kB for the given target; -1 if the server cannot estimate.</summary>
|
||||
public static async Task<decimal> EstimateFeeAsync(this ElectrumClient c, int targetBlocks,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
@@ -112,7 +112,7 @@ public static class ElectrumApi
|
||||
public static Task PingAsync(this ElectrumClient c, CancellationToken ct = default) =>
|
||||
c.RequestAsync("server.ping", ct);
|
||||
|
||||
/// <summary>Peer annunciati dal server (scoperta di altri server, §9).</summary>
|
||||
/// <summary>Peers announced by the server (discovery of other servers, §9).</summary>
|
||||
public static async Task<IReadOnlyList<PeerInfo>> GetPeersAsync(this ElectrumClient c,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
@@ -121,9 +121,9 @@ public static class ElectrumApi
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parsa la risposta di server.peers.subscribe: lista di
|
||||
/// [ip, hostname, ["v1.4.2", "pN", "tPORTA", "sPORTA", ...]];
|
||||
/// "t"/"s" senza numero = porta di default della rete (risolta dal chiamante).
|
||||
/// Parses the server.peers.subscribe response: a list of
|
||||
/// [ip, hostname, ["v1.4.2", "pN", "tPORT", "sPORT", ...]];
|
||||
/// "t"/"s" without a number = network default port (resolved by the caller).
|
||||
/// </summary>
|
||||
public static IReadOnlyList<PeerInfo> ParsePeers(JsonElement response)
|
||||
{
|
||||
|
||||
@@ -9,9 +9,9 @@ using System.Threading.Channels;
|
||||
namespace PalladiumWallet.Core.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Client del protocollo del server di indicizzazione (blueprint §10):
|
||||
/// JSON-RPC 2.0 newline-delimited su TCP, opzionalmente TLS con pinning TOFU.
|
||||
/// Le notifiche (subscription) arrivano sull'evento <see cref="NotificationReceived"/>.
|
||||
/// Client for the indexing server protocol (blueprint §10):
|
||||
/// newline-delimited JSON-RPC 2.0 over TCP, optionally TLS with TOFU pinning.
|
||||
/// Notifications (subscriptions) arrive on the <see cref="NotificationReceived"/> event.
|
||||
/// </summary>
|
||||
public sealed class ElectrumClient : IAsyncDisposable
|
||||
{
|
||||
@@ -25,17 +25,17 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
private readonly Task _readLoop;
|
||||
private readonly Task _writeLoop;
|
||||
|
||||
// Channel single-reader: le task scrivono i payload senza lock;
|
||||
// il write loop drena tutto in un unico WriteAsync+FlushAsync —
|
||||
// identico al buffered writer asyncio di Electrum.
|
||||
// Single-reader channel: tasks write the payloads without a lock;
|
||||
// the write loop drains everything in a single WriteAsync+FlushAsync —
|
||||
// identical to Electrum's asyncio buffered writer.
|
||||
private readonly Channel<byte[]> _outgoing = Channel.CreateUnbounded<byte[]>(
|
||||
new UnboundedChannelOptions { SingleReader = true, AllowSynchronousContinuations = false });
|
||||
|
||||
// Tetto alle richieste in volo (non in coda di scrittura, ma in attesa di
|
||||
// risposta sul server). Il write-loop batcha già l'invio in un solo segmento;
|
||||
// questo gate evita di sommergere il server con migliaia di richieste
|
||||
// simultanee su wallet grandi → niente -101/-102 a raffica né drop della
|
||||
// connessione. Le scritture restano comunque pipelinate fino a questo grado.
|
||||
// Cap on in-flight requests (not in the write queue, but awaiting a
|
||||
// response from the server). The write loop already batches the send into a
|
||||
// single segment; this gate avoids flooding the server with thousands of
|
||||
// simultaneous requests on large wallets → no bursts of -101/-102 nor
|
||||
// connection drops. Writes still stay pipelined up to this degree.
|
||||
private const int MaxInFlight = 32;
|
||||
private readonly SemaphoreSlim _inFlight = new(MaxInFlight, MaxInFlight);
|
||||
|
||||
@@ -104,8 +104,8 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
public async Task<JsonElement> RequestAsync(string method, CancellationToken ct = default,
|
||||
params object?[] parameters)
|
||||
{
|
||||
// Gate prima di mettere in volo: oltre MaxInFlight richieste in attesa
|
||||
// si attende che una risposta liberi uno slot, invece di sommergere il server.
|
||||
// Gate before going in-flight: beyond MaxInFlight pending requests
|
||||
// we wait for a response to free a slot, instead of flooding the server.
|
||||
await _inFlight.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
@@ -137,9 +137,9 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drain loop: svuota il channel in un unico buffer → un solo WriteAsync+FlushAsync
|
||||
/// per tutti i messaggi in coda. Quando N richieste sono in coda, vengono
|
||||
/// trasmesse in un singolo segmento TCP invece di N flush seriali.
|
||||
/// Drain loop: empties the channel into a single buffer → one WriteAsync+FlushAsync
|
||||
/// for all queued messages. When N requests are queued, they are
|
||||
/// transmitted in a single TCP segment instead of N serial flushes.
|
||||
/// </summary>
|
||||
private async Task WriteLoopAsync()
|
||||
{
|
||||
@@ -166,8 +166,8 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read loop con PipeReader: buffer pooled, zero allocazioni per-risposta
|
||||
/// (nessuna stringa intermedia), parsing JSON direttamente da byte span.
|
||||
/// Read loop with PipeReader: pooled buffers, zero per-response allocations
|
||||
/// (no intermediate string), JSON parsing directly from a byte span.
|
||||
/// </summary>
|
||||
private async Task ReadLoopAsync()
|
||||
{
|
||||
@@ -190,8 +190,8 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
}
|
||||
finally
|
||||
{
|
||||
// consumed = tutto ciò che abbiamo consumato (fino all'ultimo \n)
|
||||
// examined = tutto ciò che abbiamo guardato (fino alla fine del buffer)
|
||||
// consumed = everything we have consumed (up to the last \n)
|
||||
// examined = everything we have looked at (up to the end of the buffer)
|
||||
pipe.AdvanceTo(buffer.Start, buffer.End);
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
{
|
||||
await pipe.CompleteAsync();
|
||||
foreach (var (_, tcs) in _pending)
|
||||
tcs.TrySetException(failure ?? new IOException("Connessione al server chiusa."));
|
||||
tcs.TrySetException(failure ?? new IOException("Connection to the server closed."));
|
||||
_pending.Clear();
|
||||
Disconnected?.Invoke(failure);
|
||||
}
|
||||
@@ -229,7 +229,7 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
DispatchSpan(line.FirstSpan);
|
||||
return;
|
||||
}
|
||||
// Multi-segmento (risposta molto lunga): copia su ArrayPool poi parsa.
|
||||
// Multi-segment (very long response): copy to ArrayPool then parse.
|
||||
var len = (int)line.Length;
|
||||
var buf = ArrayPool<byte>.Shared.Rent(len);
|
||||
try
|
||||
@@ -242,8 +242,8 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
|
||||
private void DispatchSpan(ReadOnlySpan<byte> utf8)
|
||||
{
|
||||
// JsonDocument.Parse via Utf8JsonReader: nessuna stringa intermedia,
|
||||
// parsing direttamente dallo span pooled.
|
||||
// JsonDocument.Parse via Utf8JsonReader: no intermediate string,
|
||||
// parsing directly from the pooled span.
|
||||
var reader = new Utf8JsonReader(utf8);
|
||||
using var doc = JsonDocument.ParseValue(ref reader);
|
||||
var root = doc.RootElement;
|
||||
@@ -276,12 +276,12 @@ public sealed class ElectrumClient : IAsyncDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Errore restituito dal server (campo "error" della risposta JSON-RPC).</summary>
|
||||
/// <summary>Error returned by the server ("error" field of the JSON-RPC response).</summary>
|
||||
public sealed class ElectrumServerException(string error) : Exception(error);
|
||||
|
||||
/// <summary>
|
||||
/// Il certificato del server è cambiato rispetto a quello salvato (TOFU, §9).
|
||||
/// Si sblocca con il reset esplicito dei certificati.
|
||||
/// The server certificate changed with respect to the saved one (TOFU, §9).
|
||||
/// It is unlocked with an explicit reset of the certificates.
|
||||
/// </summary>
|
||||
public sealed class CertificatePinMismatchException(string host, int port) : Exception(
|
||||
$"Il certificato TLS di {host}:{port} è cambiato rispetto a quello salvato. " +
|
||||
|
||||
@@ -3,7 +3,7 @@ using PalladiumWallet.Core.Chain;
|
||||
|
||||
namespace PalladiumWallet.Core.Net;
|
||||
|
||||
/// <summary>Server di indicizzazione noto (bootstrap o scoperto dai peer).</summary>
|
||||
/// <summary>Known indexing server (bootstrap or discovered from peers).</summary>
|
||||
public sealed record KnownServer(string Host, int TcpPort, int SslPort, string? Version = null)
|
||||
{
|
||||
public int PortFor(bool useSsl) => useSsl ? SslPort : TcpPort;
|
||||
@@ -13,9 +13,9 @@ public sealed record KnownServer(string Host, int TcpPort, int SslPort, string?
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registro dei server (blueprint §9): parte dai bootstrap del profilo (§3),
|
||||
/// si arricchisce con i peer annunciati via server.peers.subscribe e persiste
|
||||
/// le scoperte su file per le sessioni successive.
|
||||
/// Server registry (blueprint §9): starts from the profile bootstrap list (§3),
|
||||
/// is enriched with peers announced via server.peers.subscribe, and persists
|
||||
/// discovered servers to file for subsequent sessions.
|
||||
/// </summary>
|
||||
public sealed class ServerRegistry
|
||||
{
|
||||
@@ -42,7 +42,7 @@ public sealed class ServerRegistry
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
// File corrotto: si riparte dai soli bootstrap.
|
||||
// Corrupted file: fall back to bootstrap servers only.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,15 +52,15 @@ public sealed class ServerRegistry
|
||||
get { lock (_lock) return [.. _servers]; }
|
||||
}
|
||||
|
||||
/// <summary>Primo server noto: default quando l'utente non ne indica uno.</summary>
|
||||
/// <summary>First known server: default when the user does not specify one.</summary>
|
||||
public KnownServer? Default
|
||||
{
|
||||
get { lock (_lock) return _servers.FirstOrDefault(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chiede al server connesso i peer che annuncia e integra i nuovi nel
|
||||
/// registro (porte mancanti → default del profilo). Ritorna quanti sono nuovi.
|
||||
/// Queries the connected server for its announced peers and adds new ones to the
|
||||
/// registry (missing ports fall back to the profile defaults). Returns the count of new entries.
|
||||
/// </summary>
|
||||
public async Task<int> DiscoverAsync(ElectrumClient client, CancellationToken ct = default)
|
||||
{
|
||||
@@ -95,7 +95,7 @@ public sealed class ServerRegistry
|
||||
private void Save()
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(_filePath)!);
|
||||
// Si salvano solo gli scoperti: i bootstrap vengono dal profilo.
|
||||
// Only discovered servers are saved; bootstrap servers come from the profile.
|
||||
var discovered = _servers
|
||||
.Where(s => !_profile.BootstrapServers.Any(b =>
|
||||
string.Equals(b.Host, s.Host, StringComparison.OrdinalIgnoreCase)))
|
||||
|
||||
Reference in New Issue
Block a user