3460e53b4f
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.
49 lines
1.9 KiB
C#
49 lines
1.9 KiB
C#
namespace PalladiumWallet.Core.Storage;
|
|
|
|
/// <summary>
|
|
/// Lettura/scrittura del file wallet su disco (blueprint §8): JSON in chiaro
|
|
/// senza password, contenitore AES-GCM con password. Scrittura atomica
|
|
/// (file temporaneo + rename) per non corrompere il wallet su crash.
|
|
/// </summary>
|
|
public static class WalletStore
|
|
{
|
|
public static bool Exists(string path) => File.Exists(path);
|
|
|
|
/// <summary>True se il file richiede una password per l'apertura.</summary>
|
|
public static bool RequiresPassword(string path) =>
|
|
EncryptedFile.IsEncrypted(File.ReadAllText(path));
|
|
|
|
public static WalletDocument Load(string path, string? password = null)
|
|
{
|
|
var content = File.ReadAllText(path);
|
|
if (EncryptedFile.IsEncrypted(content))
|
|
{
|
|
if (string.IsNullOrEmpty(password))
|
|
throw new WrongPasswordException();
|
|
content = EncryptedFile.Decrypt(content, password);
|
|
}
|
|
return WalletDocument.FromJson(content);
|
|
}
|
|
|
|
/// <param name="password">Null saves in plaintext. Only omit when the user has
|
|
/// explicitly opted out of encryption (UI must show a clear warning).</param>
|
|
public static void Save(WalletDocument doc, string path, string? password = null)
|
|
{
|
|
var content = doc.ToJson();
|
|
if (!string.IsNullOrEmpty(password))
|
|
content = EncryptedFile.Encrypt(content, password);
|
|
|
|
var tmp = path + ".tmp";
|
|
File.WriteAllText(tmp, content);
|
|
File.Move(tmp, path, overwrite: true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Same as <see cref="Save"/> but with the JSON serialization and disk write off the
|
|
/// calling thread — for callers on a UI thread saving a large cache (thousands of cached
|
|
/// transactions/headers), where the synchronous version would block the UI.
|
|
/// </summary>
|
|
public static Task SaveAsync(WalletDocument doc, string path, string? password = null) =>
|
|
Task.Run(() => Save(doc, path, password));
|
|
}
|