diff --git a/Directory.Build.props b/Directory.Build.props
index b8f181485f..ef7b979c48 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,21 +1,21 @@
-
- net8.0
- win-x64;linux-x64;linux-arm64;osx-x64;osx-arm64
- latest
- 12
- enable
- true
- false
+
+ net8.0
+ win-x64;linux-x64;linux-arm64;osx-x64;osx-arm64
+ latest
+ 12
+ enable
+ true
+ false
-
-
- all
- low
-
+
+
+ all
+ low
+
-
-
-
-
+
+
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index de242e6a0f..dfeb759df2 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,37 +1,38 @@
true
- 11.3.2
+ 11.3.2
-
+
-
-
+
+
+
-
+
-
+
-
+
-
+
-
+
@@ -56,10 +57,10 @@
-
+
-
+
\ No newline at end of file
diff --git a/GingerCommon/GingerCommon.csproj b/GingerCommon/GingerCommon.csproj
index f01cce64fa..5dd15b1e60 100644
--- a/GingerCommon/GingerCommon.csproj
+++ b/GingerCommon/GingerCommon.csproj
@@ -26,6 +26,7 @@
+
diff --git a/GingerCommon/Logging/DiscordLogger.cs b/GingerCommon/Logging/DiscordLogger.cs
index 9a08750c6e..e83e031c5e 100644
--- a/GingerCommon/Logging/DiscordLogger.cs
+++ b/GingerCommon/Logging/DiscordLogger.cs
@@ -52,7 +52,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except
{
try
{
- var content = new { content = message };
+ var content = new { content = message, flags = 4 };
var json = JsonSerializer.Serialize(content);
using var data = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = await _httpClient.PostAsync(_webhook, data);
diff --git a/GingerCommon/Logging/Logger.cs b/GingerCommon/Logging/Logger.cs
index 9454916b5b..8c475f7deb 100644
--- a/GingerCommon/Logging/Logger.cs
+++ b/GingerCommon/Logging/Logger.cs
@@ -3,6 +3,7 @@
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Logging.Debug;
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
using System.Runtime.CompilerServices;
@@ -52,23 +53,33 @@ public static void CreateLogger(LogLevel? consoleLogLevel = null, LogLevel? debu
LoggerInstance = logger;
}
- public static void CreateDiscordLogger(LogLevel? logLevel, IHttpClientFactory httpClientFactory, string webhook)
+ public static void CreateDiscordLogger(LogLevel? logLevel, IHttpClientFactory httpClientFactory, string[]? webhooks)
{
- if (logLevel == LogLevel.None || string.IsNullOrEmpty(webhook))
+ if (logLevel == LogLevel.None || webhooks is null || webhooks.Length == 0)
{
return;
}
logLevel ??= LogLevel.Error;
- using ILoggerFactory factory = LoggerFactory.Create(builder =>
+ foreach (var webhookTarget in webhooks)
{
- builder.ClearProviders();
- builder.AddFilter(null, (LogLevel)logLevel);
- builder.AddProvider(new DiscordLoggerProvider(httpClientFactory, webhook));
- });
- ILogger logger = factory.CreateLogger("Discord");
- DiscordLogger = logger;
+ var split = webhookTarget.Split("|");
+ var name = split.Length > 1 ? split[0] : "main";
+ var webhook = split.Length > 1 ? split[1] : webhookTarget;
+
+ if (!DiscordLoggers.ContainsKey(name))
+ {
+ using ILoggerFactory factory = LoggerFactory.Create(builder =>
+ {
+ builder.ClearProviders();
+ builder.AddFilter(null, (LogLevel)logLevel);
+ builder.AddProvider(new DiscordLoggerProvider(httpClientFactory, webhook));
+ });
+ ILogger logger = factory.CreateLogger(name);
+ DiscordLoggers.Add(name, logger);
+ }
+ }
}
public static void FinishFileLogging()
@@ -83,7 +94,7 @@ public static void FinishFileLogging()
private static ILogger? LoggerInstance = null;
private static string[]? LogLevelStrings = null;
- private static ILogger? DiscordLogger = null;
+ private static Dictionary DiscordLoggers = [];
private static void InitLevelStrings()
{
@@ -117,9 +128,12 @@ public void Dispose()
}
}
- public static void LogDiscord(LogLevel level, string message, [CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1, LogLevel normalLogLevel = LogLevel.None)
+ public static void LogDiscord(string channel, LogLevel level, string message, [CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1, LogLevel normalLogLevel = LogLevel.None, bool rawMessage = false)
{
- Log(DiscordLogger, level, message, callerFilePath, callerMemberName, callerLineNumber);
+ if (DiscordLoggers.TryGetValue(channel, out var discordLogger))
+ {
+ Log(discordLogger, level, message, callerFilePath, callerMemberName, callerLineNumber, rawMessage);
+ }
if (normalLogLevel != LogLevel.None)
{
Log(LoggerInstance, normalLogLevel, message, callerFilePath, callerMemberName, callerLineNumber);
@@ -132,7 +146,7 @@ public static void Log(LogLevel level, string message, [CallerFilePath] string c
Log(LoggerInstance, level, message, callerFilePath, callerMemberName, callerLineNumber);
}
- private static void Log(ILogger? loggerInstance, LogLevel level, string message, [CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
+ private static void Log(ILogger? loggerInstance, LogLevel level, string message, [CallerFilePath] string callerFilePath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1, bool rawMessage = false)
{
try
{
@@ -142,19 +156,22 @@ private static void Log(ILogger? loggerInstance, LogLevel level, string message,
}
message = message.SafeTrim();
- var category = string.IsNullOrWhiteSpace(callerFilePath) ? "" : $"{callerFilePath.ExtractFileName()}.{callerMemberName} ({callerLineNumber})";
+ var finalMessage = message;
- var messageBuilder = new StringBuilder();
- messageBuilder.Append(CultureInfo.InvariantCulture, $"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss.fff} [{Environment.CurrentManagedThreadId,2}] {GetLevelString(level)} ");
-
- messageBuilder.Append(category);
- if (message.Length > 0 && category.Length > 0)
+ if (!rawMessage)
{
- messageBuilder.Append('\t');
+ var messageBuilder = new StringBuilder();
+ messageBuilder.Append(CultureInfo.InvariantCulture, $"{DateTime.UtcNow.ToLocalTime():yyyy-MM-dd HH:mm:ss.fff} [{Environment.CurrentManagedThreadId,2}] {GetLevelString(level)} ");
+
+ var category = string.IsNullOrWhiteSpace(callerFilePath) ? "" : $"{callerFilePath.ExtractFileName()}.{callerMemberName} ({callerLineNumber})";
+ messageBuilder.Append(category);
+ if (message.Length > 0 && category.Length > 0)
+ {
+ messageBuilder.Append('\t');
+ }
+ messageBuilder.Append(message);
+ finalMessage = messageBuilder.ToString();
}
- messageBuilder.Append(message);
-
- var finalMessage = messageBuilder.ToString();
loggerInstance.Log(level, finalMessage);
}
catch (Exception ex)
diff --git a/GingerCommon/packages.lock.json b/GingerCommon/packages.lock.json
index 8a90a04591..d15fe2c691 100644
--- a/GingerCommon/packages.lock.json
+++ b/GingerCommon/packages.lock.json
@@ -10,16 +10,16 @@
},
"Microsoft.Extensions.Http": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "kDYeKJUzh0qeg/AI+nSr3ffthmXYQTEb0nS9qRC7YhSbbuN4M4NPbaB77AJwtkTnCV9XZ7qYj3dkZaNcyl73EA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics": "8.0.0",
- "Microsoft.Extensions.Logging": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics": "8.0.1",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.Logging.Console": {
@@ -48,14 +48,20 @@
},
"NBitcoin": {
"type": "Direct",
- "requested": "[7.0.42.2, )",
- "resolved": "7.0.42.2",
- "contentHash": "U9kvuVxKJ/xZs0ttF0ddVbkTLMZogWejYLYysuNz1n0MfjxR3diOnN2lE9pulgVclIieRRMOgZmIDB2MASIqxA==",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "29o3gYqYehyelNs54jbvcGfOvmyx9Gr1SEN/WDqky54qpxB2U+SCs0k4ppihr5h5Sbf+NwyrHrrjiYqmIoMycQ==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
"Newtonsoft.Json": "13.0.1"
}
},
+ "Newtonsoft.Json": {
+ "type": "Direct",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "8.0.0",
@@ -96,22 +102,21 @@
},
"Microsoft.Extensions.Diagnostics": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==",
+ "resolved": "8.0.1",
+ "contentHash": "doVPCUUCY7c6LhBsEfiy3W1bvS7Mi6LkfQMS8nlC22jZWNxBv8VO8bdfeyvpYFst6Kxqk7HBC6lytmEoBssvSQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
}
},
"Microsoft.Extensions.Diagnostics.Abstractions": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==",
+ "resolved": "8.0.1",
+ "contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "System.Diagnostics.DiagnosticSource": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.Logging": {
@@ -172,16 +177,6 @@
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
- },
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
- "System.Diagnostics.DiagnosticSource": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ=="
}
},
"net8.0/linux-arm64": {},
diff --git a/WalletWasabi.Backend/Config.cs b/WalletWasabi.Backend/Config.cs
index f2715c0278..99c7536e6a 100644
--- a/WalletWasabi.Backend/Config.cs
+++ b/WalletWasabi.Backend/Config.cs
@@ -75,9 +75,8 @@ public Config(
[JsonProperty(PropertyName = "EnableNostrCoordinatorPublisher", DefaultValueHandling = DefaultValueHandling.Populate)]
public bool EnableNostrCoordinatorPublisher { get; internal set; }
- [DefaultValue("")]
- [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
- public string DiscordLoggerWebhook { get; internal set; } = "";
+ [JsonProperty]
+ public string[] DiscordLoggers { get; internal set; } = [];
public EndPoint GetBitcoinP2pEndPoint()
{
diff --git a/WalletWasabi.Backend/Controllers/BatchController.cs b/WalletWasabi.Backend/Controllers/BatchController.cs
index de2c14bf64..3472e0822a 100644
--- a/WalletWasabi.Backend/Controllers/BatchController.cs
+++ b/WalletWasabi.Backend/Controllers/BatchController.cs
@@ -67,6 +67,7 @@ public async Task GetSynchronizeAsync(
try
{
+ // We still provide it, but the client never should read it
response.AllFeeEstimate = await BlockchainController.GetAllFeeEstimateAsync(EstimateSmartFeeMode.Conservative, cancellationToken);
}
catch (Exception ex)
diff --git a/WalletWasabi.Backend/Global.cs b/WalletWasabi.Backend/Global.cs
index c257684fdb..19fd43325a 100644
--- a/WalletWasabi.Backend/Global.cs
+++ b/WalletWasabi.Backend/Global.cs
@@ -65,11 +65,7 @@ public Global(string dataDir, IRPCClient rpcClient, Config config, IHttpClientFa
public void CreateDiscordLogger()
{
- string discordWebhook = Config.DiscordLoggerWebhook;
- if (!string.IsNullOrEmpty(discordWebhook))
- {
- Logger.CreateDiscordLogger(LogLevel.Information, HttpClientFactory, discordWebhook);
- }
+ Logger.CreateDiscordLogger(LogLevel.Information, HttpClientFactory, Config.DiscordLoggers);
}
public string DataDir { get; }
@@ -160,7 +156,7 @@ public async Task InitializeAsync(CancellationToken cancel)
private void BlockNotifier_ExceptionThrown(object? sender, Exception e)
{
- Logger.LogDiscord(LogLevel.Error, $"BlockNotifier had an exception: '{e.Message}'.", normalLogLevel: LogLevel.Error);
+ Logger.LogDiscord("main", LogLevel.Error, $"BlockNotifier had an exception: '{e.Message}'.", normalLogLevel: LogLevel.Error);
}
[MemberNotNull(nameof(WabiSabiCoordinator))]
diff --git a/WalletWasabi.Backend/InitConfigStartupTask.cs b/WalletWasabi.Backend/InitConfigStartupTask.cs
index 8e2aca539c..9b8af4ed01 100644
--- a/WalletWasabi.Backend/InitConfigStartupTask.cs
+++ b/WalletWasabi.Backend/InitConfigStartupTask.cs
@@ -21,7 +21,7 @@ public async Task ExecuteAsync(CancellationToken cancellationToken)
Global.CreateDiscordLogger();
Logger.LogSoftwareStarted("Ginger Backend");
- Logger.LogDiscord(LogLevel.Information, "Ginger Backend started");
+ Logger.LogDiscord("main", LogLevel.Information, "Ginger Backend started");
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
diff --git a/WalletWasabi.Daemon/FeeRateProviders/BlockstreamInfoFeeRateProvider.cs b/WalletWasabi.Daemon/FeeRateProviders/BlockstreamInfoFeeRateProvider.cs
index 4b08b1acde..81169ab5fb 100644
--- a/WalletWasabi.Daemon/FeeRateProviders/BlockstreamInfoFeeRateProvider.cs
+++ b/WalletWasabi.Daemon/FeeRateProviders/BlockstreamInfoFeeRateProvider.cs
@@ -65,7 +65,7 @@ private AllFeeEstimate ParseFeeEstimates(string json)
{
using var document = JsonDocument.Parse(json);
var root = document.RootElement;
- var feeEstimates = new Dictionary();
+ var feeEstimates = new Dictionary();
// Blockstream.info returns a JSON object where each property name is the target confirmation block
// (e.g., "2", "3", "6", "12", etc.) and its value is the estimated fee rate.
@@ -73,7 +73,7 @@ private AllFeeEstimate ParseFeeEstimates(string json)
{
if (int.TryParse(property.Name, out int target))
{
- feeEstimates[target] = (int)Math.Ceiling(property.Value.GetDouble());
+ feeEstimates[target] = new FeeRate(property.Value.GetDecimal());
}
}
diff --git a/WalletWasabi.Daemon/FeeRateProviders/MempoolSpaceFeeRateProvider.cs b/WalletWasabi.Daemon/FeeRateProviders/MempoolSpaceFeeRateProvider.cs
index a6b636501a..53a1f1a9bc 100644
--- a/WalletWasabi.Daemon/FeeRateProviders/MempoolSpaceFeeRateProvider.cs
+++ b/WalletWasabi.Daemon/FeeRateProviders/MempoolSpaceFeeRateProvider.cs
@@ -62,7 +62,7 @@ private AllFeeEstimate ParseFeeEstimates(string json)
{
using var document = JsonDocument.Parse(json);
var root = document.RootElement;
- var feeEstimates = new Dictionary();
+ var feeEstimates = new Dictionary();
// According to mempool.space docs, the JSON response is similar to:
// {
@@ -80,11 +80,11 @@ private AllFeeEstimate ParseFeeEstimates(string json)
// Check if the property exists and is a number
if (root.TryGetProperty(mapping.JsonKey, out var jsonElement) &&
jsonElement.ValueKind == JsonValueKind.Number && // Ensure it's a number type
- jsonElement.TryGetDouble(out double feeValue)) // Try to parse it as double
+ jsonElement.TryGetDecimal(out decimal feeValue)) // Try to parse it as decimal
{
// Calculate fee rate in sat/vB (rounding up) and add to the dictionary
// using the target block confirmation time as the key.
- feeEstimates[mapping.TargetBlocks] = (int)Math.Ceiling(feeValue);
+ feeEstimates[mapping.TargetBlocks] = new FeeRate(feeValue);
}
// If the property doesn't exist or isn't a valid number, it's skipped.
}
diff --git a/WalletWasabi.Daemon/FeeRateProviders/RegTestFeeRateProvider.cs b/WalletWasabi.Daemon/FeeRateProviders/RegTestFeeRateProvider.cs
index f7800929d4..dc1b82ba8f 100644
--- a/WalletWasabi.Daemon/FeeRateProviders/RegTestFeeRateProvider.cs
+++ b/WalletWasabi.Daemon/FeeRateProviders/RegTestFeeRateProvider.cs
@@ -1,3 +1,4 @@
+using NBitcoin;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -16,12 +17,12 @@ public RegTestFeeRateProvider()
private static AllFeeEstimate GetFakeRegTestFeeRatesAsync()
{
- var feeEstimations = new Dictionary
+ var feeEstimations = new Dictionary
{
- { 2, 100 }, // For confirmation target 1, fee rate is 100 sats/vByte
- { 3, 70 },
- { 6, 40 },
- { 72, 10 }
+ { 2, new FeeRate(100m) }, // For confirmation target 1, fee rate is 100 sats/vByte
+ { 3, new FeeRate(70m) },
+ { 6, new FeeRate(40m) },
+ { 72, new FeeRate(10m) }
};
// Initialize the AllFeeEstimate instance with the dictionary.
diff --git a/WalletWasabi.Daemon/Rpc/WasabiJsonRpcService.cs b/WalletWasabi.Daemon/Rpc/WasabiJsonRpcService.cs
index bcacd2f1e7..99c0f180b9 100644
--- a/WalletWasabi.Daemon/Rpc/WasabiJsonRpcService.cs
+++ b/WalletWasabi.Daemon/Rpc/WasabiJsonRpcService.cs
@@ -526,7 +526,7 @@ public object GetFeeRate()
return nonNullFeeRates.Estimations;
}
- return new Dictionary();
+ return new Dictionary();
}
[JsonRpcMethod("listwallets", initializable: false)]
diff --git a/WalletWasabi.Daemon/packages.lock.json b/WalletWasabi.Daemon/packages.lock.json
index 7c9db17cae..0cc7477daf 100644
--- a/WalletWasabi.Daemon/packages.lock.json
+++ b/WalletWasabi.Daemon/packages.lock.json
@@ -23,9 +23,9 @@
},
"System.Text.Json": {
"type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
+ "requested": "[8.0.6, )",
+ "resolved": "8.0.6",
+ "contentHash": "BvSpVBsVN9b+Y+wONbvJOHd1HjXQf33+XiC28ZMOwRsYb42mz3Q8YHnpTSwpwJLqYCMqM+0UUVC3V+pi25XfkQ=="
},
"LinqKit.Core": {
"type": "Transitive",
@@ -39,8 +39,8 @@
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "pujbzfszX7jAl7oTbHhqx7pxd9jibeyHHl8zy1gd55XMaKWjDtc5XhhNYwQnrwWYCInNdVoArbaaAvLgW7TwuA==",
+ "resolved": "8.0.19",
+ "contentHash": "ugQbXR+SwaFHXkfMW+Q6Dn9VSQn6uUoaFp49Zqe+EQGDNMb8dviFCratqnRiBXZKAqt2aFRsV+Cj5gqcTWU/dA==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.6"
}
@@ -85,22 +85,21 @@
},
"Microsoft.Extensions.Diagnostics": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==",
+ "resolved": "8.0.1",
+ "contentHash": "doVPCUUCY7c6LhBsEfiy3W1bvS7Mi6LkfQMS8nlC22jZWNxBv8VO8bdfeyvpYFst6Kxqk7HBC6lytmEoBssvSQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
}
},
"Microsoft.Extensions.Diagnostics.Abstractions": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==",
+ "resolved": "8.0.1",
+ "contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "System.Diagnostics.DiagnosticSource": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.FileProviders.Abstractions": {
@@ -172,8 +171,8 @@
},
"Microsoft.Net.Http.Headers": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "YlHqL8oWBX3H1LmdKUOxEMW8cVD8nUACEnE2Fu3Ze4k7mYf8yJ1o/uLqoequQV0GDupXyCBEzYhn7Zxdz7pqYQ==",
+ "resolved": "8.0.19",
+ "contentHash": "f2hSRVq5rR97YlfGcScVMXJvQpNpbbpnZjwsZ4kmN5/T3xk9DBVt1SPZDJIPrp/sSfdjz8aQtD8jKLXHyoHVng==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
@@ -183,11 +182,6 @@
"resolved": "3.1.4",
"contentHash": "23N1DCusSRCx1hoNiIMl3JnMZrdY78a/WcsiN1LIAg6sq8MiC7mszDiUgHKD6txm+m9PxJBigBLH7MPBQCRCDQ=="
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.6",
@@ -218,11 +212,6 @@
"SQLitePCLRaw.core": "2.1.6"
}
},
- "System.Diagnostics.DiagnosticSource": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ=="
- },
"System.Interactive.Async": {
"type": "Transitive",
"resolved": "6.0.1",
@@ -252,46 +241,47 @@
"gingercommon": {
"type": "Project",
"dependencies": {
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Extensions.Logging.Console": "[8.0.1, )",
"Microsoft.Extensions.Logging.Debug": "[8.0.1, )",
- "NBitcoin": "[7.0.42.2, )"
+ "NBitcoin": "[9.0.0, )",
+ "Newtonsoft.Json": "[13.0.3, )"
}
},
"walletwasabi": {
"type": "Project",
"dependencies": {
"GingerCommon": "[1.0.0, )",
- "Microsoft.AspNetCore.WebUtilities": "[8.0.0, )",
- "Microsoft.Data.Sqlite": "[8.0.0, )",
+ "Microsoft.AspNetCore.WebUtilities": "[8.0.19, )",
+ "Microsoft.Data.Sqlite": "[8.0.19, )",
"Microsoft.Extensions.Caching.Abstractions": "[8.0.0, )",
- "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )",
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Hosting.Abstractions": "[8.0.1, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Win32.SystemEvents": "[8.0.0, )",
- "NBitcoin": "[7.0.42.2, )",
+ "NBitcoin": "[9.0.0, )",
"NNostr.Client": "[0.0.49, )",
"System.IO.Pipelines": "[8.0.0, )",
- "System.Text.Json": "[8.0.5, )",
+ "System.Text.Json": "[8.0.6, )",
"WabiSabi": "[1.0.1.2, )"
}
},
"Microsoft.AspNetCore.WebUtilities": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "z1SXKg5Bk02VmrrOab1TO2yxkZIfL4RyrS+yCpwxcLTqJwImYhEttz3LYbl1gQebkAAvx2Fm4NVXmopxXeLZgw==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "fB3ikXAlz6yQuy029zDAS3J4qW3o6HQYL+kqsTjhiog1JwgpfkRTELCTGxMv7fL6VljFtfNJIQ/2684soCuI9A==",
"dependencies": {
- "Microsoft.Net.Http.Headers": "8.0.0",
+ "Microsoft.Net.Http.Headers": "8.0.19",
"System.IO.Pipelines": "8.0.0"
}
},
"Microsoft.Data.Sqlite": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "H+iC5IvkCCKSNHXzL3JARvDn7VpkvuJM91KVB89sKjeTF/KX/BocNNh93ZJtX5MCQKb/z4yVKgkU2sVIq+xKfg==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "GcYP5qUdpnF3FPoVZ6EewQ7EESRWuX79pTBYxRo/KCCiz9HTDtTka0FH+h3fUGJqk21nc0Q9BApThywO1enFaw==",
"dependencies": {
- "Microsoft.Data.Sqlite.Core": "8.0.0",
+ "Microsoft.Data.Sqlite.Core": "8.0.19",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.6"
}
},
@@ -306,29 +296,29 @@
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AG7HWwVRdCHlaA++1oKDxLsXIBxmDpMPb3VoyOoAghEWnkUvEAdYQUwnV4jJbAaa/nMYNiEh5ByoLauZBEiovg==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "nHwq9aPBdBPYXPti6wYEEfgXddfBrYC+CQLn+qISiwQq5tpfaqDZSKOJNxoe9rfQxGf1c+2wC/qWFe1QYJPYqw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0"
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2"
}
},
"Microsoft.Extensions.Http": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "kDYeKJUzh0qeg/AI+nSr3ffthmXYQTEb0nS9qRC7YhSbbuN4M4NPbaB77AJwtkTnCV9XZ7qYj3dkZaNcyl73EA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics": "8.0.0",
- "Microsoft.Extensions.Logging": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics": "8.0.1",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.Logging.Console": {
@@ -363,14 +353,20 @@
},
"NBitcoin": {
"type": "CentralTransitive",
- "requested": "[7.0.42.2, )",
- "resolved": "7.0.42.2",
- "contentHash": "U9kvuVxKJ/xZs0ttF0ddVbkTLMZogWejYLYysuNz1n0MfjxR3diOnN2lE9pulgVclIieRRMOgZmIDB2MASIqxA==",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "29o3gYqYehyelNs54jbvcGfOvmyx9Gr1SEN/WDqky54qpxB2U+SCs0k4ppihr5h5Sbf+NwyrHrrjiYqmIoMycQ==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
"Newtonsoft.Json": "13.0.1"
}
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"NNostr.Client": {
"type": "CentralTransitive",
"requested": "[0.0.49, )",
diff --git a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo.ico b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo.ico
index 3dbbee309c..9bdf00b675 100644
Binary files a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo.ico and b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo.ico differ
diff --git a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo16.png b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo16.png
index 329fe16835..98c0f923a7 100644
Binary files a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo16.png and b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo16.png differ
diff --git a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo24.png b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo24.png
index 63f4d56aa5..3207c34c6c 100644
Binary files a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo24.png and b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo24.png differ
diff --git a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo256.png b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo256.png
index 70e12e4069..cf92f7a05e 100644
Binary files a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo256.png and b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo256.png differ
diff --git a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo32.png b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo32.png
index cd67fddfa7..91e829cf77 100644
Binary files a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo32.png and b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo32.png differ
diff --git a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo48.png b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo48.png
index 73ff64d1dd..4cbe7ba706 100644
Binary files a/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo48.png and b/WalletWasabi.Fluent.Desktop/Assets/WasabiLogo48.png differ
diff --git a/WalletWasabi.Fluent.Desktop/Program.cs b/WalletWasabi.Fluent.Desktop/Program.cs
index 6291561798..87bd3e1d24 100644
--- a/WalletWasabi.Fluent.Desktop/Program.cs
+++ b/WalletWasabi.Fluent.Desktop/Program.cs
@@ -182,7 +182,7 @@ public static async Task RunAsGuiAsync(this WasabiApplication app)
RxApp.MainThreadScheduler.Schedule(() => throw new ApplicationException("Exception has been thrown in unobserved ThrownExceptions", ex));
});
- Logger.LogInfo("Wasabi GUI started.");
+ Logger.LogInfo("Ginger GUI started.");
bool runGuiInBackground = app.AppConfig.Arguments.Any(arg => arg.Contains(StartupHelper.SilentArgument));
UiConfig uiConfig = app.Global!.UiConfig;
uiConfig
diff --git a/WalletWasabi.Fluent.Desktop/packages.lock.json b/WalletWasabi.Fluent.Desktop/packages.lock.json
index 7dcec03f18..b2c2533155 100644
--- a/WalletWasabi.Fluent.Desktop/packages.lock.json
+++ b/WalletWasabi.Fluent.Desktop/packages.lock.json
@@ -34,9 +34,9 @@
},
"System.Text.Json": {
"type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
+ "requested": "[8.0.6, )",
+ "resolved": "8.0.6",
+ "contentHash": "BvSpVBsVN9b+Y+wONbvJOHd1HjXQf33+XiC28ZMOwRsYb42mz3Q8YHnpTSwpwJLqYCMqM+0UUVC3V+pi25XfkQ=="
},
"Avalonia.Angle.Windows.Natives": {
"type": "Transitive",
@@ -315,8 +315,8 @@
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "pujbzfszX7jAl7oTbHhqx7pxd9jibeyHHl8zy1gd55XMaKWjDtc5XhhNYwQnrwWYCInNdVoArbaaAvLgW7TwuA==",
+ "resolved": "8.0.19",
+ "contentHash": "ugQbXR+SwaFHXkfMW+Q6Dn9VSQn6uUoaFp49Zqe+EQGDNMb8dviFCratqnRiBXZKAqt2aFRsV+Cj5gqcTWU/dA==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.6"
}
@@ -361,22 +361,21 @@
},
"Microsoft.Extensions.Diagnostics": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==",
+ "resolved": "8.0.1",
+ "contentHash": "doVPCUUCY7c6LhBsEfiy3W1bvS7Mi6LkfQMS8nlC22jZWNxBv8VO8bdfeyvpYFst6Kxqk7HBC6lytmEoBssvSQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
}
},
"Microsoft.Extensions.Diagnostics.Abstractions": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==",
+ "resolved": "8.0.1",
+ "contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "System.Diagnostics.DiagnosticSource": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.FileProviders.Abstractions": {
@@ -448,8 +447,8 @@
},
"Microsoft.Net.Http.Headers": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "YlHqL8oWBX3H1LmdKUOxEMW8cVD8nUACEnE2Fu3Ze4k7mYf8yJ1o/uLqoequQV0GDupXyCBEzYhn7Zxdz7pqYQ==",
+ "resolved": "8.0.19",
+ "contentHash": "f2hSRVq5rR97YlfGcScVMXJvQpNpbbpnZjwsZ4kmN5/T3xk9DBVt1SPZDJIPrp/sSfdjz8aQtD8jKLXHyoHVng==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
@@ -469,11 +468,6 @@
"resolved": "3.1.4",
"contentHash": "23N1DCusSRCx1hoNiIMl3JnMZrdY78a/WcsiN1LIAg6sq8MiC7mszDiUgHKD6txm+m9PxJBigBLH7MPBQCRCDQ=="
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
"ReactiveUI": {
"type": "Transitive",
"resolved": "20.1.1",
@@ -607,11 +601,6 @@
"System.Runtime": "4.3.0"
}
},
- "System.Diagnostics.DiagnosticSource": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ=="
- },
"System.Globalization": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -756,26 +745,27 @@
"gingercommon": {
"type": "Project",
"dependencies": {
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Extensions.Logging.Console": "[8.0.1, )",
"Microsoft.Extensions.Logging.Debug": "[8.0.1, )",
- "NBitcoin": "[7.0.42.2, )"
+ "NBitcoin": "[9.0.0, )",
+ "Newtonsoft.Json": "[13.0.3, )"
}
},
"walletwasabi": {
"type": "Project",
"dependencies": {
"GingerCommon": "[1.0.0, )",
- "Microsoft.AspNetCore.WebUtilities": "[8.0.0, )",
- "Microsoft.Data.Sqlite": "[8.0.0, )",
+ "Microsoft.AspNetCore.WebUtilities": "[8.0.19, )",
+ "Microsoft.Data.Sqlite": "[8.0.19, )",
"Microsoft.Extensions.Caching.Abstractions": "[8.0.0, )",
- "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )",
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Hosting.Abstractions": "[8.0.1, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Win32.SystemEvents": "[8.0.0, )",
- "NBitcoin": "[7.0.42.2, )",
+ "NBitcoin": "[9.0.0, )",
"NNostr.Client": "[0.0.49, )",
"System.IO.Pipelines": "[8.0.0, )",
- "System.Text.Json": "[8.0.5, )",
+ "System.Text.Json": "[8.0.6, )",
"WabiSabi": "[1.0.1.2, )"
}
},
@@ -795,7 +785,7 @@
"QRackers": "[1.1.0, )",
"System.Private.Uri": "[4.3.2, )",
"System.Runtime": "[4.3.1, )",
- "System.Text.Json": "[8.0.5, )",
+ "System.Text.Json": "[8.0.6, )",
"Wasabi Wallet Daemon": "[1.0.0, )"
}
},
@@ -803,7 +793,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Caching.Memory": "[8.0.1, )",
- "System.Text.Json": "[8.0.5, )",
+ "System.Text.Json": "[8.0.6, )",
"WalletWasabi": "[1.0.0, )"
}
},
@@ -912,21 +902,21 @@
},
"Microsoft.AspNetCore.WebUtilities": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "z1SXKg5Bk02VmrrOab1TO2yxkZIfL4RyrS+yCpwxcLTqJwImYhEttz3LYbl1gQebkAAvx2Fm4NVXmopxXeLZgw==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "fB3ikXAlz6yQuy029zDAS3J4qW3o6HQYL+kqsTjhiog1JwgpfkRTELCTGxMv7fL6VljFtfNJIQ/2684soCuI9A==",
"dependencies": {
- "Microsoft.Net.Http.Headers": "8.0.0",
+ "Microsoft.Net.Http.Headers": "8.0.19",
"System.IO.Pipelines": "8.0.0"
}
},
"Microsoft.Data.Sqlite": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "H+iC5IvkCCKSNHXzL3JARvDn7VpkvuJM91KVB89sKjeTF/KX/BocNNh93ZJtX5MCQKb/z4yVKgkU2sVIq+xKfg==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "GcYP5qUdpnF3FPoVZ6EewQ7EESRWuX79pTBYxRo/KCCiz9HTDtTka0FH+h3fUGJqk21nc0Q9BApThywO1enFaw==",
"dependencies": {
- "Microsoft.Data.Sqlite.Core": "8.0.0",
+ "Microsoft.Data.Sqlite.Core": "8.0.19",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.6"
}
},
@@ -954,29 +944,29 @@
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AG7HWwVRdCHlaA++1oKDxLsXIBxmDpMPb3VoyOoAghEWnkUvEAdYQUwnV4jJbAaa/nMYNiEh5ByoLauZBEiovg==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "nHwq9aPBdBPYXPti6wYEEfgXddfBrYC+CQLn+qISiwQq5tpfaqDZSKOJNxoe9rfQxGf1c+2wC/qWFe1QYJPYqw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0"
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2"
}
},
"Microsoft.Extensions.Http": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "kDYeKJUzh0qeg/AI+nSr3ffthmXYQTEb0nS9qRC7YhSbbuN4M4NPbaB77AJwtkTnCV9XZ7qYj3dkZaNcyl73EA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics": "8.0.0",
- "Microsoft.Extensions.Logging": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics": "8.0.1",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.Logging.Console": {
@@ -1011,14 +1001,20 @@
},
"NBitcoin": {
"type": "CentralTransitive",
- "requested": "[7.0.42.2, )",
- "resolved": "7.0.42.2",
- "contentHash": "U9kvuVxKJ/xZs0ttF0ddVbkTLMZogWejYLYysuNz1n0MfjxR3diOnN2lE9pulgVclIieRRMOgZmIDB2MASIqxA==",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "29o3gYqYehyelNs54jbvcGfOvmyx9Gr1SEN/WDqky54qpxB2U+SCs0k4ppihr5h5Sbf+NwyrHrrjiYqmIoMycQ==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
"Newtonsoft.Json": "13.0.1"
}
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"NNostr.Client": {
"type": "CentralTransitive",
"requested": "[0.0.49, )",
diff --git a/WalletWasabi.Fluent.Generators/WalletWasabi.Fluent.Generators.csproj b/WalletWasabi.Fluent.Generators/WalletWasabi.Fluent.Generators.csproj
index bf4ddcfe99..cafce5ecbf 100644
--- a/WalletWasabi.Fluent.Generators/WalletWasabi.Fluent.Generators.csproj
+++ b/WalletWasabi.Fluent.Generators/WalletWasabi.Fluent.Generators.csproj
@@ -14,7 +14,6 @@
-
diff --git a/WalletWasabi.Fluent.Generators/packages.lock.json b/WalletWasabi.Fluent.Generators/packages.lock.json
index 6ea73da3cd..4cc1daf8da 100644
--- a/WalletWasabi.Fluent.Generators/packages.lock.json
+++ b/WalletWasabi.Fluent.Generators/packages.lock.json
@@ -2,12 +2,6 @@
"version": 2,
"dependencies": {
".NETStandard,Version=v2.0": {
- "Microsoft.CodeAnalysis.Analyzers": {
- "type": "Direct",
- "requested": "[3.3.4, )",
- "resolved": "3.3.4",
- "contentHash": "AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g=="
- },
"Microsoft.CodeAnalysis.BannedApiAnalyzers": {
"type": "Direct",
"requested": "[3.3.4, )",
@@ -16,11 +10,20 @@
},
"Microsoft.CodeAnalysis.CSharp": {
"type": "Direct",
- "requested": "[4.6.0, )",
- "resolved": "4.6.0",
- "contentHash": "9pyFZUN2Lyu3C0Xfs49kezfH+CzQHMibGsQeQPu0P+GWyH2XXDwmyZ6jAaKQGNUXOJfC2OK01hWMJTJY315uDQ==",
+ "requested": "[4.11.0, )",
+ "resolved": "4.11.0",
+ "contentHash": "6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==",
"dependencies": {
- "Microsoft.CodeAnalysis.Common": "[4.6.0]"
+ "Microsoft.CodeAnalysis.Analyzers": "3.3.4",
+ "Microsoft.CodeAnalysis.Common": "[4.11.0]",
+ "System.Buffers": "4.5.1",
+ "System.Collections.Immutable": "8.0.0",
+ "System.Memory": "4.5.5",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Reflection.Metadata": "8.0.0",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0",
+ "System.Text.Encoding.CodePages": "7.0.0",
+ "System.Threading.Tasks.Extensions": "4.5.4"
}
},
"NETStandard.Library": {
@@ -44,8 +47,8 @@
},
"System.Collections.Immutable": {
"type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==",
+ "resolved": "8.0.0",
+ "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==",
"dependencies": {
"System.Memory": "4.5.5",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
@@ -63,15 +66,15 @@
},
"System.Numerics.Vectors": {
"type": "Transitive",
- "resolved": "4.4.0",
- "contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ=="
+ "resolved": "4.5.0",
+ "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
},
"System.Reflection.Metadata": {
"type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "MclTG61lsD9sYdpNz9xsKBzjsmsfCtcMZYXz/IUr2zlhaTaABonlr1ESeompTgM+Xk+IwtGYU7/voh3YWB/fWw==",
+ "resolved": "8.0.0",
+ "contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==",
"dependencies": {
- "System.Collections.Immutable": "7.0.0",
+ "System.Collections.Immutable": "8.0.0",
"System.Memory": "4.5.5"
}
},
@@ -97,16 +100,24 @@
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
},
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "CentralTransitive",
+ "requested": "[3.3.4, )",
+ "resolved": "3.3.4",
+ "contentHash": "AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g=="
+ },
"Microsoft.CodeAnalysis.Common": {
"type": "CentralTransitive",
"requested": "[4.6.0, )",
- "resolved": "4.6.0",
- "contentHash": "N3uLvekc7DjvE1BX8YW7UH7ldjA4ps/Tun2YmOoSIItJrh1gnQIMKUbK1c3uQUx2NHbLibVZI4o/VB9xb4B7tA==",
+ "resolved": "4.11.0",
+ "contentHash": "djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==",
"dependencies": {
"Microsoft.CodeAnalysis.Analyzers": "3.3.4",
- "System.Collections.Immutable": "7.0.0",
+ "System.Buffers": "4.5.1",
+ "System.Collections.Immutable": "8.0.0",
"System.Memory": "4.5.5",
- "System.Reflection.Metadata": "7.0.0",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Reflection.Metadata": "8.0.0",
"System.Runtime.CompilerServices.Unsafe": "6.0.0",
"System.Text.Encoding.CodePages": "7.0.0",
"System.Threading.Tasks.Extensions": "4.5.4"
diff --git a/WalletWasabi.Fluent/Assets/WasabiLogo.ico b/WalletWasabi.Fluent/Assets/WasabiLogo.ico
index 3dbbee309c..9bdf00b675 100644
Binary files a/WalletWasabi.Fluent/Assets/WasabiLogo.ico and b/WalletWasabi.Fluent/Assets/WasabiLogo.ico differ
diff --git a/WalletWasabi.Fluent/Assets/WasabiLogo_white.ico b/WalletWasabi.Fluent/Assets/WasabiLogo_white.ico
index 6df7283964..6f3b246371 100644
Binary files a/WalletWasabi.Fluent/Assets/WasabiLogo_white.ico and b/WalletWasabi.Fluent/Assets/WasabiLogo_white.ico differ
diff --git a/WalletWasabi.Fluent/Controls/TreeDataGrid.axaml b/WalletWasabi.Fluent/Controls/TreeDataGrid.axaml
index b72225ee51..20b9164e8a 100644
--- a/WalletWasabi.Fluent/Controls/TreeDataGrid.axaml
+++ b/WalletWasabi.Fluent/Controls/TreeDataGrid.axaml
@@ -45,7 +45,6 @@
diff --git a/WalletWasabi.Fluent/Controls/WalletIconControl.axaml b/WalletWasabi.Fluent/Controls/WalletIconControl.axaml
index d1a5f28c88..552adc15f2 100644
--- a/WalletWasabi.Fluent/Controls/WalletIconControl.axaml
+++ b/WalletWasabi.Fluent/Controls/WalletIconControl.axaml
@@ -8,75 +8,80 @@
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
diff --git a/WalletWasabi.Fluent/Controls/WalletIconControl.axaml.cs b/WalletWasabi.Fluent/Controls/WalletIconControl.axaml.cs
index 6f657e0d6f..bb52f50a53 100644
--- a/WalletWasabi.Fluent/Controls/WalletIconControl.axaml.cs
+++ b/WalletWasabi.Fluent/Controls/WalletIconControl.axaml.cs
@@ -8,9 +8,32 @@ public class WalletIconControl : TemplatedControl
{
public static readonly StyledProperty WalletTypeProperty = AvaloniaProperty.Register(nameof(WalletType));
+ public static readonly StyledProperty IsNormalProperty = AvaloniaProperty.Register(nameof(IsNormal));
+
public WalletType WalletType
{
get => GetValue(WalletTypeProperty);
set => SetValue(WalletTypeProperty, value);
}
+
+ public bool IsNormal
+ {
+ get => GetValue(IsNormalProperty);
+ set => SetValue(IsNormalProperty, value);
+ }
+
+ public WalletIconControl()
+ {
+ SetValue(IsNormalProperty, WalletType == WalletType.Normal);
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == WalletTypeProperty)
+ {
+ SetValue(IsNormalProperty, (WalletType)change.NewValue == WalletType.Normal);
+ }
+ }
}
diff --git a/WalletWasabi.Fluent/Extensions/ObservableExtensions.cs b/WalletWasabi.Fluent/Extensions/ObservableExtensions.cs
index 07c14dba98..bb82e6a216 100644
--- a/WalletWasabi.Fluent/Extensions/ObservableExtensions.cs
+++ b/WalletWasabi.Fluent/Extensions/ObservableExtensions.cs
@@ -111,7 +111,8 @@ public static IObservable ReplayLastActive(this IObservable observable)
public static IObservableCache Fetch(this IObservable signal, Func> source, Func keySelector, IEqualityComparer? equalityComparer = null)
where TKey : notnull where TObject : notnull
{
- return signal.Select(_ => source())
+ return signal
+ .Select(_ => source())
.EditDiff(keySelector, equalityComparer)
.DisposeMany()
.AsObservableCache();
diff --git a/WalletWasabi.Fluent/Helpers/TransactionFeeHelper.cs b/WalletWasabi.Fluent/Helpers/TransactionFeeHelper.cs
index ea1e5c7763..40723ccfaf 100644
--- a/WalletWasabi.Fluent/Helpers/TransactionFeeHelper.cs
+++ b/WalletWasabi.Fluent/Helpers/TransactionFeeHelper.cs
@@ -15,18 +15,18 @@ namespace WalletWasabi.Fluent.Helpers;
public static class TransactionFeeHelper
{
private static readonly AllFeeEstimate TestNetFeeEstimates = new(
- new Dictionary
+ new Dictionary
{
- [1] = 17,
- [2] = 12,
- [3] = 9,
- [6] = 9,
- [18] = 2,
- [36] = 2,
- [72] = 2,
- [144] = 2,
- [432] = 1,
- [1008] = 1
+ [1] = new FeeRate(17m),
+ [2] = new FeeRate(12m),
+ [3] = new FeeRate(9m),
+ [6] = new FeeRate(9m),
+ [18] = new FeeRate(2m),
+ [36] = new FeeRate(2m),
+ [72] = new FeeRate(2m),
+ [144] = new FeeRate(2m),
+ [432] = new FeeRate(1m),
+ [1008] = new FeeRate(1m)
});
public static bool TryEstimateConfirmationTime(IWalletFeeRateProvider feeProvider, Network network, SmartTransaction tx, UnconfirmedTransactionChainProvider unconfirmedTxChainProvider, [NotNullWhen(true)] out TimeSpan? estimate)
diff --git a/WalletWasabi.Fluent/HomeScreen/History/ViewModels/HistoryViewModel.cs b/WalletWasabi.Fluent/HomeScreen/History/ViewModels/HistoryViewModel.cs
index 238a7ea327..d4d43f23b0 100644
--- a/WalletWasabi.Fluent/HomeScreen/History/ViewModels/HistoryViewModel.cs
+++ b/WalletWasabi.Fluent/HomeScreen/History/ViewModels/HistoryViewModel.cs
@@ -2,6 +2,7 @@
using System.ComponentModel;
using System.Linq;
using System.Reactive.Disposables;
+using System.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Controls.Templates;
@@ -180,6 +181,7 @@ protected override void OnActivated(CompositeDisposable disposables)
}
Wallet.Transactions.Cache.Connect()
+ .SkipWhile(_ => !Wallet.IsLoaded)
.Transform(x => CreateViewModel(x))
.Sort(
SortExpressionComparer
diff --git a/WalletWasabi.Fluent/HomeScreen/Send/ViewModels/FeeChartViewModel.cs b/WalletWasabi.Fluent/HomeScreen/Send/ViewModels/FeeChartViewModel.cs
index 5c8aa23c67..5bbf833a6b 100644
--- a/WalletWasabi.Fluent/HomeScreen/Send/ViewModels/FeeChartViewModel.cs
+++ b/WalletWasabi.Fluent/HomeScreen/Send/ViewModels/FeeChartViewModel.cs
@@ -260,8 +260,8 @@ public void UpdateFeeEstimates(IEnumerable<(TimeSpan timeSpan, FeeRate feeRate)>
var minY = 1; // If values are not the same, it will be always rendered starting from 1.
SatoshiPerByteLabels = areAllValuesEqual
- ? new[] { "", "", maxY.ToString("F0", Resources.Culture.NumberFormat) }
- : new[] { minY.ToString("F0", Resources.Culture.NumberFormat), ((maxY + minY) / 2).ToString("F0", Resources.Culture.NumberFormat), maxY.ToString("F0", Resources.Culture.NumberFormat) };
+ ? new[] { "", "", maxY.ToString("F2", Resources.Culture.NumberFormat) }
+ : new[] { minY.ToString("F2", Resources.Culture.NumberFormat), ((maxY + minY) / 2).ToString("F2", Resources.Culture.NumberFormat), maxY.ToString("F2", Resources.Culture.NumberFormat) };
}
else
{
diff --git a/WalletWasabi.Fluent/HomeScreen/WalletSettings/ViewModels/CoinjoinCoinSelectorSettingsViewModel.cs b/WalletWasabi.Fluent/HomeScreen/WalletSettings/ViewModels/CoinjoinCoinSelectorSettingsViewModel.cs
index c59b3d4c53..483f967983 100644
--- a/WalletWasabi.Fluent/HomeScreen/WalletSettings/ViewModels/CoinjoinCoinSelectorSettingsViewModel.cs
+++ b/WalletWasabi.Fluent/HomeScreen/WalletSettings/ViewModels/CoinjoinCoinSelectorSettingsViewModel.cs
@@ -15,6 +15,7 @@ public partial class CoinjoinCoinSelectorSettingsViewModel : DialogViewModelBase
private readonly WalletModel _wallet;
[AutoNotify] private bool _forceUsingLowPrivacyCoins;
+ [AutoNotify] private bool _canSelectPrivateCoins;
[AutoNotify] private string _weightedAnonymityLossNormal;
[AutoNotify] private string _valueLossRateNormal;
[AutoNotify] private string _targetCoinCountPerBucket;
@@ -34,6 +35,7 @@ public CoinjoinCoinSelectorSettingsViewModel(WalletModel wallet)
this.ValidateProperty(x => x.TargetCoinCountPerBucket, x => ValidateDouble(x, TargetCoinCountPerBucket, 1.0, 30.0));
_forceUsingLowPrivacyCoins = _wallet.Settings.ForceUsingLowPrivacyCoins;
+ _canSelectPrivateCoins = _wallet.Settings.CanSelectPrivateCoins;
_weightedAnonymityLossNormal = _wallet.Settings.WeightedAnonymityLossNormal.ToString(Resources.Culture.NumberFormat);
_valueLossRateNormal = _wallet.Settings.ValueLossRateNormal.ToString(Resources.Culture.NumberFormat);
_targetCoinCountPerBucket = _wallet.Settings.TargetCoinCountPerBucket.ToString(Resources.Culture.NumberFormat);
@@ -48,6 +50,15 @@ public CoinjoinCoinSelectorSettingsViewModel(WalletModel wallet)
_wallet.Settings.Save();
});
+ this.WhenAnyValue(x => x.CanSelectPrivateCoins)
+ .Skip(1)
+ .ObserveOn(RxApp.TaskpoolScheduler)
+ .Subscribe(x =>
+ {
+ _wallet.Settings.CanSelectPrivateCoins = x;
+ _wallet.Settings.Save();
+ });
+
this.WhenAnyValue(x => x.WeightedAnonymityLossNormal)
.Skip(1)
.Where(_ => !HasError(nameof(WeightedAnonymityLossNormal)))
diff --git a/WalletWasabi.Fluent/HomeScreen/WalletSettings/Views/CoinjoinCoinSelectorSettingsView.axaml b/WalletWasabi.Fluent/HomeScreen/WalletSettings/Views/CoinjoinCoinSelectorSettingsView.axaml
index 19e3d723dd..62e778ca7f 100644
--- a/WalletWasabi.Fluent/HomeScreen/WalletSettings/Views/CoinjoinCoinSelectorSettingsView.axaml
+++ b/WalletWasabi.Fluent/HomeScreen/WalletSettings/Views/CoinjoinCoinSelectorSettingsView.axaml
@@ -20,6 +20,11 @@
+
+
+
+
+
diff --git a/WalletWasabi.Fluent/Icons/Icons.axaml b/WalletWasabi.Fluent/Icons/Icons.axaml
index d15aa58713..9004cb29e7 100644
--- a/WalletWasabi.Fluent/Icons/Icons.axaml
+++ b/WalletWasabi.Fluent/Icons/Icons.axaml
@@ -706,6 +706,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -765,14 +797,6 @@
-
-
-
-
@@ -853,1025 +877,78 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WalletWasabi.Fluent/Models/TransactionBroadcasterModel.cs b/WalletWasabi.Fluent/Models/TransactionBroadcasterModel.cs
index 9e55d99838..22f2ca453d 100644
--- a/WalletWasabi.Fluent/Models/TransactionBroadcasterModel.cs
+++ b/WalletWasabi.Fluent/Models/TransactionBroadcasterModel.cs
@@ -5,7 +5,6 @@
using WalletWasabi.Extensions;
using WalletWasabi.Fluent.Extensions;
using WalletWasabi.Fluent.Helpers;
-using WalletWasabi.Lang;
using WalletWasabi.Models;
namespace WalletWasabi.Fluent.Models;
@@ -43,59 +42,20 @@ public Task LoadFromFileAsync(string filePath)
public TransactionBroadcastInfo GetBroadcastInfo(SmartTransaction transaction)
{
- var nullMoney = new Money(-1L);
- var nullOutput = new TxOut(nullMoney, Script.Empty);
+ var tx = transaction.Transaction;
- var psbt = PSBT.FromTransaction(transaction.Transaction, _network);
+ Money spendingSum = tx.Inputs
+ .Select(x => Services.BitcoinStore.TransactionStore.TryGetTransaction(x.PrevOut.Hash, out var prevTxn) ? prevTxn.Transaction.Outputs[x.PrevOut.N].Value : Money.Zero)
+ .Sum();
- TxOut GetOutput(OutPoint outpoint) =>
- Services.BitcoinStore.TransactionStore.TryGetTransaction(outpoint.Hash, out var prevTxn)
- ? prevTxn.Transaction.Outputs[outpoint.N]
- : nullOutput;
-
- var inputAddressAmount = psbt.Inputs
- .Select(x => x.PrevOut)
- .Select(GetOutput)
- .ToArray();
-
- var outputAddressAmount = psbt.Outputs
- .Select(x => x.GetCoin().TxOut)
- .ToArray();
-
- var psbtTxn = psbt.GetOriginalTransaction();
-
- var transactionId = psbtTxn.GetHash().ToString();
-
- var inputCount = inputAddressAmount.Length;
- var totalInputValue =
- inputAddressAmount.Any(x => x.Value == nullMoney)
- ? null
- : inputAddressAmount.Select(x => x.Value).Sum();
-
- var inputAmountString =
- totalInputValue is null
- ? Resources.Unknown
- : $"{totalInputValue.ToFormattedString()} BTC";
-
- var outputCount = outputAddressAmount.Length;
-
- var totalOutputValue =
- outputAddressAmount.Any(x => x.Value == nullMoney)
- ? null
- : outputAddressAmount.Select(x => x.Value).Sum();
-
- var outputAmountString =
- totalOutputValue is null
- ? Resources.Unknown
- : $"{totalOutputValue.ToFormattedString()} BTC";
-
- var networkFee = totalInputValue is null || totalOutputValue is null
- ? null
- : totalInputValue - totalOutputValue;
+ Money outputSum = tx.Outputs.Select(x => x.Value).Sum();
+ var networkFee = spendingSum - outputSum;
+ var inputAmountString = $"{spendingSum.ToFormattedString()} BTC";
+ var outputAmountString = $"{outputSum.ToFormattedString()} BTC";
var feeString = networkFee.ToFeeDisplayUnitFormattedString();
- return new TransactionBroadcastInfo(transactionId, inputCount, outputCount, inputAmountString, outputAmountString, feeString);
+ return new TransactionBroadcastInfo(tx.GetHash().ToString(), tx.Inputs.Count, tx.Outputs.Count, inputAmountString, outputAmountString, feeString);
}
public Task SendAsync(SmartTransaction transaction)
diff --git a/WalletWasabi.Fluent/Models/Wallets/WalletSettingsModel.cs b/WalletWasabi.Fluent/Models/Wallets/WalletSettingsModel.cs
index 39aae3b4d2..694dc83b01 100644
--- a/WalletWasabi.Fluent/Models/Wallets/WalletSettingsModel.cs
+++ b/WalletWasabi.Fluent/Models/Wallets/WalletSettingsModel.cs
@@ -31,6 +31,7 @@ public partial class WalletSettingsModel : ReactiveObject
[AutoNotify] private bool _useExperimentalCoinSelector;
[AutoNotify] private bool _forceUsingLowPrivacyCoins;
+ [AutoNotify] private bool _canSelectPrivateCoins;
[AutoNotify] private double _weightedAnonymityLossNormal;
[AutoNotify] private double _valueLossRateNormal;
[AutoNotify] private double _targetCoinCountPerBucket;
@@ -58,6 +59,7 @@ public WalletSettingsModel(KeyManager keyManager, bool isNewWallet = false, bool
var coinJoinSelectionSettings = _keyManager.Attributes.CoinJoinCoinSelectionSettings;
_useExperimentalCoinSelector = coinJoinSelectionSettings.UseExperimentalCoinSelector;
_forceUsingLowPrivacyCoins = coinJoinSelectionSettings.ForceUsingLowPrivacyCoins;
+ _canSelectPrivateCoins = coinJoinSelectionSettings.CanSelectPrivateCoins;
_weightedAnonymityLossNormal = coinJoinSelectionSettings.WeightedAnonymityLossNormal;
_valueLossRateNormal = coinJoinSelectionSettings.ValueLossRateNormal;
_targetCoinCountPerBucket = coinJoinSelectionSettings.TargetCoinCountPerBucket;
@@ -90,11 +92,12 @@ public WalletSettingsModel(KeyManager keyManager, bool isNewWallet = false, bool
x => x.SafeMiningFeeRate,
x => x.UseExperimentalCoinSelector,
x => x.ForceUsingLowPrivacyCoins,
+ x => x.CanSelectPrivateCoins,
x => x.WeightedAnonymityLossNormal,
x => x.ValueLossRateNormal,
x => x.TargetCoinCountPerBucket,
x => x.UseOldCoinSelectorAsFallback,
- (_, _, _, _, _, _, _, _) => Unit.Default)
+ (_, _, _, _, _, _, _, _, _) => Unit.Default)
.Skip(1)
.Do(_ => SetValues())
.Subscribe();
@@ -140,6 +143,7 @@ private void SetValues()
_keyManager.SetFeeRateMedianTimeFrame(FeeRateMedianTimeFrameHours);
_keyManager.Attributes.CoinJoinCoinSelectionSettings.UseExperimentalCoinSelector = UseExperimentalCoinSelector;
_keyManager.Attributes.CoinJoinCoinSelectionSettings.ForceUsingLowPrivacyCoins = ForceUsingLowPrivacyCoins;
+ _keyManager.Attributes.CoinJoinCoinSelectionSettings.CanSelectPrivateCoins = CanSelectPrivateCoins;
_keyManager.Attributes.CoinJoinCoinSelectionSettings.WeightedAnonymityLossNormal = WeightedAnonymityLossNormal;
_keyManager.Attributes.CoinJoinCoinSelectionSettings.ValueLossRateNormal = ValueLossRateNormal;
_keyManager.Attributes.CoinJoinCoinSelectionSettings.TargetCoinCountPerBucket = TargetCoinCountPerBucket;
diff --git a/WalletWasabi.Fluent/SearchBar/ViewModels/Sources/TransactionsSearchSource.cs b/WalletWasabi.Fluent/SearchBar/ViewModels/Sources/TransactionsSearchSource.cs
index 16f553cfab..876100fa3a 100644
--- a/WalletWasabi.Fluent/SearchBar/ViewModels/Sources/TransactionsSearchSource.cs
+++ b/WalletWasabi.Fluent/SearchBar/ViewModels/Sources/TransactionsSearchSource.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
@@ -34,8 +35,14 @@ public TransactionsSearchSource(IObservable queries)
#pragma warning restore CA2000 // Dispose objects before losing scope
var results = queries
- .Select(query => query.Length >= MinQueryLength ? Search(query) : Enumerable.Empty())
- .ObserveOn(RxApp.MainThreadScheduler);
+ .Throttle(TimeSpan.FromMilliseconds(180)) // rate-limit while typing
+ .DistinctUntilChanged(StringComparer.Ordinal)
+ .Select(q =>
+ string.IsNullOrWhiteSpace(q) || q.Length < MinQueryLength
+ ? Observable.Return(Enumerable.Empty())
+ : Observable.Start(() => Search(q).ToList(), RxApp.TaskpoolScheduler)) // heavy work off UI thread
+ .Switch() // cancel stale searches
+ .ObserveOn(RxApp.MainThreadScheduler); // update cache on UI thread
sourceCache
.RefillFrom(results)
@@ -53,7 +60,8 @@ public void Dispose()
private static bool ContainsId(HistoryItemViewModelBase historyItemViewModelBase, string queryStr)
{
- return historyItemViewModelBase.Transaction.Id.ToString().Contains(queryStr, StringComparison.CurrentCultureIgnoreCase);
+ return historyItemViewModelBase.Transaction.Id.ToString()
+ .Contains(queryStr, StringComparison.OrdinalIgnoreCase);
}
private static Task NavigateTo(WalletViewModel wallet, HistoryItemViewModelBase item)
@@ -77,7 +85,7 @@ private static string GetIcon(HistoryItemViewModelBase historyItemViewModelBase)
return historyItemViewModelBase switch
{
CoinJoinHistoryItemViewModel => "shield_regular",
- CoinJoinsHistoryItemViewModel => "shield_regular",
+ CoinJoinsHistoryItemViewModel => "double_shield_regular",
TransactionHistoryItemViewModel => "normal_transaction",
_ => ""
};
@@ -88,19 +96,6 @@ private static string GetIcon(HistoryItemViewModelBase historyItemViewModelBase)
return walletTransactions.SelectMany(t => t.Transactions.Select(item => (t.Wallet, HistoryItem: item)));
}
- private static ISearchItem ToSearchItem(WalletViewModel wallet, HistoryItemViewModelBase item)
- {
- return new ActionableItem(
- item.Transaction.Id.ToString(),
- Resources.FoundIn.SafeInject(wallet.WalletModel.Name),
- () => NavigateTo(wallet, item),
- Resources.WalletTransactions,
- new List())
- {
- Icon = GetIcon(item)
- };
- }
-
private static IEnumerable<(WalletViewModel Wallet, IEnumerable Transactions)> GetTransactionsByWallet()
{
// TODO: This is a workaround to get all the transactions from currently loaded wallets. REMOVE after UIDecoupling #26
@@ -113,22 +108,77 @@ private static ISearchItem ToSearchItem(WalletViewModel wallet, HistoryItemViewM
x.History.Transactions.Concat(x.History.Transactions.OfType().SelectMany(y => y.Children))));
}
- private static IEnumerable Search(string query)
+ private static List<(WalletViewModel Wallet, HistoryItemViewModelBase Item)> SnapshotTransactions()
{
- return Filter(query)
- .Take(MaxResultCount)
- .Select(tuple => ToSearchItem(tuple.Item1, tuple.Item2));
+ // materialize once per query to avoid repeated enumeration / UI access
+ return Flatten(GetTransactionsByWallet()).ToList();
}
- private static IEnumerable<(WalletViewModel, HistoryItemViewModelBase)> Filter(string queryStr)
+ private static IEnumerable Search(string query)
{
- return Flatten(GetTransactionsByWallet())
- .Where(tuple => NBitcoinHelpers.TryParseBitcoinAddress(tuple.Item1.WalletModel.Network, queryStr, out var address) ? ContainsDestinationAddress(tuple.Item1, tuple.Item2, address) : ContainsId(tuple.Item2, queryStr));
+ var snapshot = SnapshotTransactions();
+
+ if (!snapshot.Any())
+ {
+ return Enumerable.Empty();
+ }
+
+ // cache destination addresses per tx within a single search
+ var destCache = new Dictionary>();
+
+ var results = new List(Math.Min(MaxResultCount, 16));
+
+ // parse address at most once per wallet/network
+ foreach (var group in snapshot.GroupBy(t => t.Wallet))
+ {
+ BitcoinAddress? parsedAddr = null;
+ if (NBitcoinHelpers.TryParseBitcoinAddress(group.Key.WalletModel.Network, query, out var addr))
+ {
+ parsedAddr = addr;
+ }
+
+ foreach (var (wallet, item) in group)
+ {
+ bool isMatch;
+ if (parsedAddr is null)
+ {
+ isMatch = ContainsId(item, query);
+ }
+ else
+ {
+ var txid = item.Transaction.Id;
+ if (!destCache.TryGetValue(txid, out var dests))
+ {
+ dests = wallet.WalletModel.Transactions.GetDestinationAddresses(txid).ToList();
+ destCache[txid] = dests;
+ }
+ isMatch = dests.Contains(parsedAddr);
+ }
+
+ if (isMatch)
+ {
+ results.Add(ToSearchItem(wallet, item));
+ if (results.Count >= MaxResultCount)
+ {
+ return results;
+ }
+ }
+ }
+ }
+
+ return results;
}
- private static bool ContainsDestinationAddress(WalletViewModel walletViewModel, HistoryItemViewModelBase historyItem, BitcoinAddress address)
+ private static ISearchItem ToSearchItem(WalletViewModel wallet, HistoryItemViewModelBase item)
{
- var txid = historyItem.Transaction.Id;
- return walletViewModel.WalletModel.Transactions.GetDestinationAddresses(txid).Contains(address);
+ return new ActionableItem(
+ item.Transaction.Id.ToString(),
+ Resources.FoundIn.SafeInject(wallet.WalletModel.Name),
+ () => NavigateTo(wallet, item),
+ Resources.WalletTransactions,
+ new List())
+ {
+ Icon = GetIcon(item)
+ };
}
}
diff --git a/WalletWasabi.Fluent/Styles/Themes/Dark.axaml b/WalletWasabi.Fluent/Styles/Themes/Dark.axaml
index edbd2f154a..4befe3324e 100644
--- a/WalletWasabi.Fluent/Styles/Themes/Dark.axaml
+++ b/WalletWasabi.Fluent/Styles/Themes/Dark.axaml
@@ -4,7 +4,7 @@
- #FFA68D67
+ #FFAB8C5F
#FF000000
#FF000000
#FF000000
@@ -12,51 +12,51 @@
#FF000000
#FFFFFFFF
#FF414141
- #FF949494
- #FFAFAFAF
- #FF5D5D5D
- #FFAFAFAF
+ #FF909090
+ #FFACACAC
+ #FF575757
+ #FFACACAC
#FF000000
- #FFAFAFAF
+ #FFACACAC
#FF000000
#FF000000
- #FF262626
- #FF949494
- #FF787878
+ #1F1F1F
+ #FF909090
+ #FF747474
#323232
#3F3F3F
- #262626
- #FF202020
+ #1F1F1F
+ #FF1A1A1A
#FFFFFFFF
- #262626
- #FF262626
- #CC1F1F1F
- #FF262626
- #262626
- #FF262626
- #FF947A52
- #FF83683E
- #FF715529
- #FFB29B78
- #FFBFA989
- #FFCBB899
+ #1F1F1F
+ #1F1F1F
+ #CC191919
+ #FF1F1F1F
+ #FF1F1F1F
+ #FF1F1F1F
+ #FF997A4C
+ #FF876739
+ #FF755526
+ #FFB79A71
+ #FFC3A883
+ #FFCEB794
#FFB29B78
#FF947A52
#26A68D67
#40B29B78
#36947A52
- #1F1F1F
+ #191919
- #1F1F1F
+ #191919
- #262626
- #FF414141
- #FF5D5D5D
- #FF787878
- #FF202020
- #FF1B1B1B
- #FF151515
+ #1F1F1F
+ #FF3B3B3B
+ #FF575757
+ #FF747474
+ #FF1A1A1A
+ #FF161616
+ #FF111111
#333333
#FF4D4D4D
@@ -82,7 +82,7 @@
- #262626
+ #1F1F1F
#66757575
#FFFFFFFF
diff --git a/WalletWasabi.Fluent/packages.lock.json b/WalletWasabi.Fluent/packages.lock.json
index 30b1002098..b0fc7fb590 100644
--- a/WalletWasabi.Fluent/packages.lock.json
+++ b/WalletWasabi.Fluent/packages.lock.json
@@ -153,9 +153,9 @@
},
"System.Text.Json": {
"type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
+ "requested": "[8.0.6, )",
+ "resolved": "8.0.6",
+ "contentHash": "BvSpVBsVN9b+Y+wONbvJOHd1HjXQf33+XiC28ZMOwRsYb42mz3Q8YHnpTSwpwJLqYCMqM+0UUVC3V+pi25XfkQ=="
},
"Avalonia.AvaloniaEdit": {
"type": "Transitive",
@@ -393,8 +393,8 @@
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "pujbzfszX7jAl7oTbHhqx7pxd9jibeyHHl8zy1gd55XMaKWjDtc5XhhNYwQnrwWYCInNdVoArbaaAvLgW7TwuA==",
+ "resolved": "8.0.19",
+ "contentHash": "ugQbXR+SwaFHXkfMW+Q6Dn9VSQn6uUoaFp49Zqe+EQGDNMb8dviFCratqnRiBXZKAqt2aFRsV+Cj5gqcTWU/dA==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.6"
}
@@ -439,22 +439,21 @@
},
"Microsoft.Extensions.Diagnostics": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==",
+ "resolved": "8.0.1",
+ "contentHash": "doVPCUUCY7c6LhBsEfiy3W1bvS7Mi6LkfQMS8nlC22jZWNxBv8VO8bdfeyvpYFst6Kxqk7HBC6lytmEoBssvSQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
}
},
"Microsoft.Extensions.Diagnostics.Abstractions": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==",
+ "resolved": "8.0.1",
+ "contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "System.Diagnostics.DiagnosticSource": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.FileProviders.Abstractions": {
@@ -526,8 +525,8 @@
},
"Microsoft.Net.Http.Headers": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "YlHqL8oWBX3H1LmdKUOxEMW8cVD8nUACEnE2Fu3Ze4k7mYf8yJ1o/uLqoequQV0GDupXyCBEzYhn7Zxdz7pqYQ==",
+ "resolved": "8.0.19",
+ "contentHash": "f2hSRVq5rR97YlfGcScVMXJvQpNpbbpnZjwsZ4kmN5/T3xk9DBVt1SPZDJIPrp/sSfdjz8aQtD8jKLXHyoHVng==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
@@ -547,11 +546,6 @@
"resolved": "3.1.4",
"contentHash": "23N1DCusSRCx1hoNiIMl3JnMZrdY78a/WcsiN1LIAg6sq8MiC7mszDiUgHKD6txm+m9PxJBigBLH7MPBQCRCDQ=="
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
"ReactiveUI": {
"type": "Transitive",
"resolved": "20.1.1",
@@ -685,11 +679,6 @@
"System.Runtime": "4.3.0"
}
},
- "System.Diagnostics.DiagnosticSource": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ=="
- },
"System.Globalization": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -826,26 +815,27 @@
"gingercommon": {
"type": "Project",
"dependencies": {
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Extensions.Logging.Console": "[8.0.1, )",
"Microsoft.Extensions.Logging.Debug": "[8.0.1, )",
- "NBitcoin": "[7.0.42.2, )"
+ "NBitcoin": "[9.0.0, )",
+ "Newtonsoft.Json": "[13.0.3, )"
}
},
"walletwasabi": {
"type": "Project",
"dependencies": {
"GingerCommon": "[1.0.0, )",
- "Microsoft.AspNetCore.WebUtilities": "[8.0.0, )",
- "Microsoft.Data.Sqlite": "[8.0.0, )",
+ "Microsoft.AspNetCore.WebUtilities": "[8.0.19, )",
+ "Microsoft.Data.Sqlite": "[8.0.19, )",
"Microsoft.Extensions.Caching.Abstractions": "[8.0.0, )",
- "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )",
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Hosting.Abstractions": "[8.0.1, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Win32.SystemEvents": "[8.0.0, )",
- "NBitcoin": "[7.0.42.2, )",
+ "NBitcoin": "[9.0.0, )",
"NNostr.Client": "[0.0.49, )",
"System.IO.Pipelines": "[8.0.0, )",
- "System.Text.Json": "[8.0.5, )",
+ "System.Text.Json": "[8.0.6, )",
"WabiSabi": "[1.0.1.2, )"
}
},
@@ -853,27 +843,27 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Caching.Memory": "[8.0.1, )",
- "System.Text.Json": "[8.0.5, )",
+ "System.Text.Json": "[8.0.6, )",
"WalletWasabi": "[1.0.0, )"
}
},
"Microsoft.AspNetCore.WebUtilities": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "z1SXKg5Bk02VmrrOab1TO2yxkZIfL4RyrS+yCpwxcLTqJwImYhEttz3LYbl1gQebkAAvx2Fm4NVXmopxXeLZgw==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "fB3ikXAlz6yQuy029zDAS3J4qW3o6HQYL+kqsTjhiog1JwgpfkRTELCTGxMv7fL6VljFtfNJIQ/2684soCuI9A==",
"dependencies": {
- "Microsoft.Net.Http.Headers": "8.0.0",
+ "Microsoft.Net.Http.Headers": "8.0.19",
"System.IO.Pipelines": "8.0.0"
}
},
"Microsoft.Data.Sqlite": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "H+iC5IvkCCKSNHXzL3JARvDn7VpkvuJM91KVB89sKjeTF/KX/BocNNh93ZJtX5MCQKb/z4yVKgkU2sVIq+xKfg==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "GcYP5qUdpnF3FPoVZ6EewQ7EESRWuX79pTBYxRo/KCCiz9HTDtTka0FH+h3fUGJqk21nc0Q9BApThywO1enFaw==",
"dependencies": {
- "Microsoft.Data.Sqlite.Core": "8.0.0",
+ "Microsoft.Data.Sqlite.Core": "8.0.19",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.6"
}
},
@@ -901,29 +891,29 @@
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AG7HWwVRdCHlaA++1oKDxLsXIBxmDpMPb3VoyOoAghEWnkUvEAdYQUwnV4jJbAaa/nMYNiEh5ByoLauZBEiovg==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "nHwq9aPBdBPYXPti6wYEEfgXddfBrYC+CQLn+qISiwQq5tpfaqDZSKOJNxoe9rfQxGf1c+2wC/qWFe1QYJPYqw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0"
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2"
}
},
"Microsoft.Extensions.Http": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "kDYeKJUzh0qeg/AI+nSr3ffthmXYQTEb0nS9qRC7YhSbbuN4M4NPbaB77AJwtkTnCV9XZ7qYj3dkZaNcyl73EA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics": "8.0.0",
- "Microsoft.Extensions.Logging": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics": "8.0.1",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.Logging.Console": {
@@ -958,14 +948,20 @@
},
"NBitcoin": {
"type": "CentralTransitive",
- "requested": "[7.0.42.2, )",
- "resolved": "7.0.42.2",
- "contentHash": "U9kvuVxKJ/xZs0ttF0ddVbkTLMZogWejYLYysuNz1n0MfjxR3diOnN2lE9pulgVclIieRRMOgZmIDB2MASIqxA==",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "29o3gYqYehyelNs54jbvcGfOvmyx9Gr1SEN/WDqky54qpxB2U+SCs0k4ppihr5h5Sbf+NwyrHrrjiYqmIoMycQ==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
"Newtonsoft.Json": "13.0.1"
}
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"NNostr.Client": {
"type": "CentralTransitive",
"requested": "[0.0.49, )",
diff --git a/WalletWasabi.Packager/Content/Osx/App/Contents/Resources/WasabiLogo.icns b/WalletWasabi.Packager/Content/Osx/App/Contents/Resources/WasabiLogo.icns
index 54b98dc65a..6138d43d55 100644
Binary files a/WalletWasabi.Packager/Content/Osx/App/Contents/Resources/WasabiLogo.icns and b/WalletWasabi.Packager/Content/Osx/App/Contents/Resources/WasabiLogo.icns differ
diff --git a/WalletWasabi.Packager/Content/Osx/WasabiLogo.icns b/WalletWasabi.Packager/Content/Osx/WasabiLogo.icns
index 54b98dc65a..6138d43d55 100644
Binary files a/WalletWasabi.Packager/Content/Osx/WasabiLogo.icns and b/WalletWasabi.Packager/Content/Osx/WasabiLogo.icns differ
diff --git a/WalletWasabi.Packager/packages.lock.json b/WalletWasabi.Packager/packages.lock.json
index 393b848ea5..f6eb41f8c5 100644
--- a/WalletWasabi.Packager/packages.lock.json
+++ b/WalletWasabi.Packager/packages.lock.json
@@ -10,9 +10,9 @@
},
"System.Text.Json": {
"type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
+ "requested": "[8.0.6, )",
+ "resolved": "8.0.6",
+ "contentHash": "BvSpVBsVN9b+Y+wONbvJOHd1HjXQf33+XiC28ZMOwRsYb42mz3Q8YHnpTSwpwJLqYCMqM+0UUVC3V+pi25XfkQ=="
},
"LinqKit.Core": {
"type": "Transitive",
@@ -26,8 +26,8 @@
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "pujbzfszX7jAl7oTbHhqx7pxd9jibeyHHl8zy1gd55XMaKWjDtc5XhhNYwQnrwWYCInNdVoArbaaAvLgW7TwuA==",
+ "resolved": "8.0.19",
+ "contentHash": "ugQbXR+SwaFHXkfMW+Q6Dn9VSQn6uUoaFp49Zqe+EQGDNMb8dviFCratqnRiBXZKAqt2aFRsV+Cj5gqcTWU/dA==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.6"
}
@@ -72,22 +72,21 @@
},
"Microsoft.Extensions.Diagnostics": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==",
+ "resolved": "8.0.1",
+ "contentHash": "doVPCUUCY7c6LhBsEfiy3W1bvS7Mi6LkfQMS8nlC22jZWNxBv8VO8bdfeyvpYFst6Kxqk7HBC6lytmEoBssvSQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
}
},
"Microsoft.Extensions.Diagnostics.Abstractions": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==",
+ "resolved": "8.0.1",
+ "contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "System.Diagnostics.DiagnosticSource": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.FileProviders.Abstractions": {
@@ -159,8 +158,8 @@
},
"Microsoft.Net.Http.Headers": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "YlHqL8oWBX3H1LmdKUOxEMW8cVD8nUACEnE2Fu3Ze4k7mYf8yJ1o/uLqoequQV0GDupXyCBEzYhn7Zxdz7pqYQ==",
+ "resolved": "8.0.19",
+ "contentHash": "f2hSRVq5rR97YlfGcScVMXJvQpNpbbpnZjwsZ4kmN5/T3xk9DBVt1SPZDJIPrp/sSfdjz8aQtD8jKLXHyoHVng==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
@@ -170,11 +169,6 @@
"resolved": "3.1.4",
"contentHash": "23N1DCusSRCx1hoNiIMl3JnMZrdY78a/WcsiN1LIAg6sq8MiC7mszDiUgHKD6txm+m9PxJBigBLH7MPBQCRCDQ=="
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.6",
@@ -205,11 +199,6 @@
"SQLitePCLRaw.core": "2.1.6"
}
},
- "System.Diagnostics.DiagnosticSource": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ=="
- },
"System.Interactive.Async": {
"type": "Transitive",
"resolved": "6.0.1",
@@ -239,46 +228,47 @@
"gingercommon": {
"type": "Project",
"dependencies": {
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Extensions.Logging.Console": "[8.0.1, )",
"Microsoft.Extensions.Logging.Debug": "[8.0.1, )",
- "NBitcoin": "[7.0.42.2, )"
+ "NBitcoin": "[9.0.0, )",
+ "Newtonsoft.Json": "[13.0.3, )"
}
},
"walletwasabi": {
"type": "Project",
"dependencies": {
"GingerCommon": "[1.0.0, )",
- "Microsoft.AspNetCore.WebUtilities": "[8.0.0, )",
- "Microsoft.Data.Sqlite": "[8.0.0, )",
+ "Microsoft.AspNetCore.WebUtilities": "[8.0.19, )",
+ "Microsoft.Data.Sqlite": "[8.0.19, )",
"Microsoft.Extensions.Caching.Abstractions": "[8.0.0, )",
- "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )",
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Hosting.Abstractions": "[8.0.1, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Win32.SystemEvents": "[8.0.0, )",
- "NBitcoin": "[7.0.42.2, )",
+ "NBitcoin": "[9.0.0, )",
"NNostr.Client": "[0.0.49, )",
"System.IO.Pipelines": "[8.0.0, )",
- "System.Text.Json": "[8.0.5, )",
+ "System.Text.Json": "[8.0.6, )",
"WabiSabi": "[1.0.1.2, )"
}
},
"Microsoft.AspNetCore.WebUtilities": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "z1SXKg5Bk02VmrrOab1TO2yxkZIfL4RyrS+yCpwxcLTqJwImYhEttz3LYbl1gQebkAAvx2Fm4NVXmopxXeLZgw==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "fB3ikXAlz6yQuy029zDAS3J4qW3o6HQYL+kqsTjhiog1JwgpfkRTELCTGxMv7fL6VljFtfNJIQ/2684soCuI9A==",
"dependencies": {
- "Microsoft.Net.Http.Headers": "8.0.0",
+ "Microsoft.Net.Http.Headers": "8.0.19",
"System.IO.Pipelines": "8.0.0"
}
},
"Microsoft.Data.Sqlite": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "H+iC5IvkCCKSNHXzL3JARvDn7VpkvuJM91KVB89sKjeTF/KX/BocNNh93ZJtX5MCQKb/z4yVKgkU2sVIq+xKfg==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "GcYP5qUdpnF3FPoVZ6EewQ7EESRWuX79pTBYxRo/KCCiz9HTDtTka0FH+h3fUGJqk21nc0Q9BApThywO1enFaw==",
"dependencies": {
- "Microsoft.Data.Sqlite.Core": "8.0.0",
+ "Microsoft.Data.Sqlite.Core": "8.0.19",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.6"
}
},
@@ -293,29 +283,29 @@
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AG7HWwVRdCHlaA++1oKDxLsXIBxmDpMPb3VoyOoAghEWnkUvEAdYQUwnV4jJbAaa/nMYNiEh5ByoLauZBEiovg==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "nHwq9aPBdBPYXPti6wYEEfgXddfBrYC+CQLn+qISiwQq5tpfaqDZSKOJNxoe9rfQxGf1c+2wC/qWFe1QYJPYqw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0"
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2"
}
},
"Microsoft.Extensions.Http": {
"type": "CentralTransitive",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "kDYeKJUzh0qeg/AI+nSr3ffthmXYQTEb0nS9qRC7YhSbbuN4M4NPbaB77AJwtkTnCV9XZ7qYj3dkZaNcyl73EA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics": "8.0.0",
- "Microsoft.Extensions.Logging": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics": "8.0.1",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.Logging.Console": {
@@ -350,14 +340,20 @@
},
"NBitcoin": {
"type": "CentralTransitive",
- "requested": "[7.0.42.2, )",
- "resolved": "7.0.42.2",
- "contentHash": "U9kvuVxKJ/xZs0ttF0ddVbkTLMZogWejYLYysuNz1n0MfjxR3diOnN2lE9pulgVclIieRRMOgZmIDB2MASIqxA==",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "29o3gYqYehyelNs54jbvcGfOvmyx9Gr1SEN/WDqky54qpxB2U+SCs0k4ppihr5h5Sbf+NwyrHrrjiYqmIoMycQ==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
"Newtonsoft.Json": "13.0.1"
}
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"NNostr.Client": {
"type": "CentralTransitive",
"requested": "[0.0.49, )",
diff --git a/WalletWasabi.Tests/AcceptanceTests/HwiKatas.cs b/WalletWasabi.Tests/AcceptanceTests/HwiKatas.cs
index 1e5fb813fc..751d0dd87a 100644
--- a/WalletWasabi.Tests/AcceptanceTests/HwiKatas.cs
+++ b/WalletWasabi.Tests/AcceptanceTests/HwiKatas.cs
@@ -97,8 +97,8 @@ public async Task TrezorTKataAsync()
// USER: Hold to confirm
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
@@ -169,8 +169,8 @@ public async Task TrezorSafe3KataAsync()
// USER: Hold to confirm
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
@@ -241,8 +241,8 @@ public async Task TrezorSafe5KataAsync()
// USER: Hold to confirm
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
@@ -335,8 +335,8 @@ public async Task ColdCardKataAsync()
// USER: CONFIRM
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
@@ -431,8 +431,8 @@ public async Task LedgerNanoSKataAsync()
// USER: CONFIRM
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
@@ -515,8 +515,8 @@ public async Task LedgerNanoSPlusKataAsync()
// USER: CONFIRM
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
@@ -600,8 +600,8 @@ public async Task LedgerNanoXKataAsync()
// USER: CONFIRM
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
@@ -682,8 +682,8 @@ public async Task JadeKataAsync()
// USER: CONFIRM CONFIRM
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
@@ -767,8 +767,8 @@ public async Task BitBox02BtcOnlyKataAsync()
// USER: CONFIRM CONFIRM
PSBT signedPsbt = await client.SignTxAsync(deviceType, devicePath, Psbt, cts.Token);
- Transaction signedTx = signedPsbt.GetOriginalTransaction();
- Assert.Equal(Psbt.GetOriginalTransaction().GetHash(), signedTx.GetHash());
+ Transaction signedTx = signedPsbt.ExtractTransaction();
+ Assert.Equal(Psbt.ExtractTransaction().GetHash(), signedTx.GetHash());
var checkResult = signedTx.Check();
Assert.Equal(TransactionCheckResult.Success, checkResult);
diff --git a/WalletWasabi.Tests/RegressionTests/ReplaceByFeeTxTest.cs b/WalletWasabi.Tests/RegressionTests/ReplaceByFeeTxTest.cs
index 7c954edfbe..d4945e6f5f 100644
--- a/WalletWasabi.Tests/RegressionTests/ReplaceByFeeTxTest.cs
+++ b/WalletWasabi.Tests/RegressionTests/ReplaceByFeeTxTest.cs
@@ -105,20 +105,20 @@ public async Task ReplaceByFeeTxTestAsync()
}
Assert.Single(wallet.Coins);
- Assert.True(wallet.Coins.First().Transaction.IsRBF);
+ Assert.False(wallet.Coins.First().Transaction.Confirmed);
var bfr = await rpc.BumpFeeAsync(tx0Id);
var tx1Id = bfr.TransactionId;
await Task.Delay(2000); // Waits for the replacement transaction get to the mempool.
Assert.Single(wallet.Coins);
- Assert.True(wallet.Coins.First().Transaction.IsRBF);
+ Assert.False(wallet.Coins.First().Transaction.Confirmed);
Assert.Equal(tx1Id, wallet.Coins.First().TransactionId);
bfr = await rpc.BumpFeeAsync(tx1Id);
var tx2Id = bfr.TransactionId;
await Task.Delay(2000); // Waits for the replacement transaction get to the mempool.
Assert.Single(wallet.Coins);
- Assert.True(wallet.Coins.First().Transaction.IsRBF);
+ Assert.False(wallet.Coins.First().Transaction.Confirmed);
Assert.Equal(tx2Id, wallet.Coins.First().TransactionId);
Interlocked.Exchange(ref setup.FiltersProcessedByWalletCount, 0);
@@ -127,7 +127,7 @@ public async Task ReplaceByFeeTxTestAsync()
var coin = Assert.Single(wallet.Coins);
Assert.True(coin.Confirmed);
- Assert.False(coin.Transaction.IsRBF);
+ Assert.True(coin.Transaction.Confirmed);
Assert.Equal(tx2Id, coin.TransactionId);
}
finally
diff --git a/WalletWasabi.Tests/UnitTests/AllFeeEstimateTests.cs b/WalletWasabi.Tests/UnitTests/AllFeeEstimateTests.cs
index 922b08bf14..43eb0a3dd5 100644
--- a/WalletWasabi.Tests/UnitTests/AllFeeEstimateTests.cs
+++ b/WalletWasabi.Tests/UnitTests/AllFeeEstimateTests.cs
@@ -20,11 +20,11 @@ public class AllFeeEstimateTests
[Fact]
public void Serialization()
{
- var estimations = new Dictionary
+ var estimations = new Dictionary
{
- { 2, 102 },
- { 3, 20 },
- { 19, 1 }
+ { 2, new FeeRate(102m) },
+ { 3, new FeeRate(20m) },
+ { 19, new FeeRate(1m) }
};
var allFee = new AllFeeEstimate(estimations);
var serialized = JsonConvert.SerializeObject(allFee);
@@ -39,12 +39,12 @@ public void Serialization()
[Fact]
public void OrdersByTarget()
{
- var estimations = new Dictionary
+ var estimations = new Dictionary
{
- { 3, 20 },
- { 2, 102 },
- { 19, 1 },
- { 20, 1 }
+ { 3, new FeeRate(20m) },
+ { 2, new FeeRate(102m) },
+ { 19, new FeeRate(1m) },
+ { 20, new FeeRate(1m) }
};
var allFee = new AllFeeEstimate(estimations);
@@ -56,10 +56,10 @@ public void OrdersByTarget()
[Fact]
public void HandlesDuplicate()
{
- var estimations = new Dictionary
+ var estimations = new Dictionary
{
- { 2, 20 },
- { 3, 20 }
+ { 2, new FeeRate(20m) },
+ { 3, new FeeRate(20m) }
};
var allFee = new AllFeeEstimate(estimations);
@@ -71,9 +71,9 @@ public void HandlesDuplicate()
public void HandlesOne()
{
// If there's no 2, this'll be 2.
- var estimations = new Dictionary
+ var estimations = new Dictionary
{
- { 1, 20 }
+ { 1, new FeeRate(20m) }
};
var allFees = new AllFeeEstimate(estimations);
@@ -81,10 +81,10 @@ public void HandlesOne()
Assert.Equal(estimations[1], allFees.Estimations[2]);
// If there's 2, 1 is dismissed.
- estimations = new Dictionary
+ estimations = new Dictionary
{
- { 1, 20 },
- { 2, 21 }
+ { 1, new FeeRate(20m) },
+ { 2, new FeeRate(21m) }
};
allFees = new AllFeeEstimate(estimations);
@@ -95,9 +95,9 @@ public void HandlesOne()
[Fact]
public void EndOfTheRange()
{
- var estimations = new Dictionary
+ var estimations = new Dictionary
{
- { 1007, 20 }
+ { 1007, new FeeRate(20m) }
};
var allFees = new AllFeeEstimate(estimations);
@@ -108,23 +108,23 @@ public void EndOfTheRange()
[Fact]
public void HandlesInconsistentData()
{
- var estimations = new Dictionary
+ var estimations = new Dictionary
{
- { 2, 20 },
- { 3, 21 }
+ { 2, new FeeRate(20m) },
+ { 3, new FeeRate(21m) }
};
var allFee = new AllFeeEstimate(estimations);
Assert.Single(allFee.Estimations);
Assert.Equal(estimations[2], allFee.Estimations[2]);
- estimations = new Dictionary
+ estimations = new Dictionary
{
- { 18, 1000 },
- { 3, 21 },
- { 2, 20 },
- { 100, 100 },
- { 6, 4 },
+ { 18, new FeeRate(1000m) },
+ { 3, new FeeRate(21m) },
+ { 2, new FeeRate(20m) },
+ { 100, new FeeRate(100m) },
+ { 6, new FeeRate(4m) },
};
allFee = new AllFeeEstimate(estimations);
@@ -225,9 +225,9 @@ public async Task AccurateEstimationsAsync()
var allFee = await mockRpc.EstimateAllFeeAsync();
Assert.Equal(3, allFee.Estimations.Count);
- Assert.Equal(99, allFee.Estimations[2]);
- Assert.Equal(75, allFee.Estimations[6]);
- Assert.Equal(31, allFee.Estimations[1008]);
+ Assert.Equal(99, allFee.Estimations[2].SatoshiPerByte);
+ Assert.Equal(75, allFee.Estimations[6].SatoshiPerByte);
+ Assert.Equal(31, allFee.Estimations[1008].SatoshiPerByte);
}
[Fact]
@@ -266,9 +266,9 @@ public async Task FixObviouslyWrongEstimationsAsync()
};
var allFee = await mockRpc.EstimateAllFeeAsync();
- Assert.Equal(140, allFee.Estimations[2]);
- Assert.Equal(124, allFee.Estimations[144]);
- Assert.True(allFee.Estimations[1008] > 1);
+ Assert.Equal(140, allFee.Estimations[2].SatoshiPerByte);
+ Assert.Equal(124, allFee.Estimations[144].SatoshiPerByte);
+ Assert.True(allFee.Estimations[1008].SatoshiPerByte > 1);
}
[Fact]
@@ -302,7 +302,7 @@ public async Task ExhaustiveMempoolEstimationsAsync()
Assert.Subset(Constants.ConfirmationTargets.ToHashSet(), estimations.Keys.ToHashSet());
Assert.Equal(estimations.Keys, estimations.Keys.OrderBy(x => x));
Assert.Equal(estimations.Values, estimations.Values.OrderByDescending(x => x));
- Assert.All(estimations, (e) => Assert.True(e.Value >= mempoolInfo.MemPoolMinFee * 100_000));
+ Assert.All(estimations, (e) => Assert.True(e.Value.SatoshiPerByte >= (decimal)mempoolInfo.MemPoolMinFee * 100_000));
}
}
@@ -317,7 +317,7 @@ public async Task RealWorldMempoolSpaceMinFeeAsync()
var estimations = feeRates.Estimations;
var minFee = estimations.Min(x => x.Value);
- Assert.Equal(15, minFee); // this is the calculated MempoolMinFee needed to be in the top 200MB
+ Assert.Equal(15, minFee.SatoshiPerByte); // this is the calculated MempoolMinFee needed to be in the top 200MB
}
[Theory]
@@ -334,7 +334,7 @@ public async Task RealWorldMempoolRpcMinFeeAsync(string filePath, int expectedMi
var estimations = feeRates.Estimations;
var minFee = estimations.Min(x => x.Value);
- Assert.Equal(expectedMinFee, minFee);
+ Assert.Equal(expectedMinFee, minFee.SatoshiPerByte);
}
[Theory]
@@ -361,18 +361,18 @@ public async Task RealWorldMempoolRpcMaxFeeAsync(string filePath, int expectedMa
var estimations = feeRates.Estimations;
var maxFee = estimations.Max(x => x.Value);
- Assert.Equal(expectedMaxFee, maxFee);
+ Assert.Equal(expectedMaxFee, maxFee.SatoshiPerByte);
}
[Fact]
public void WildEstimations()
{
- var estimations = new Dictionary
+ var estimations = new Dictionary
{
- { 2, 102 }, // 20m
- { 3, 20 }, // 30m
- { 6, 10 }, // 1h
- { 18, 1 } // 3h
+ { 2, new FeeRate(102m) }, // 20m
+ { 3, new FeeRate(20m) }, // 30m
+ { 6, new FeeRate(10m) }, // 1h
+ { 18, new FeeRate(1m) } // 3h
};
var allFee = new AllFeeEstimate(estimations);
diff --git a/WalletWasabi.Tests/UnitTests/Blockchain/Keys/WpkhOutputDescriptorHelperTests.cs b/WalletWasabi.Tests/UnitTests/Blockchain/Keys/WpkhOutputDescriptorHelperTests.cs
index 86e8448aee..b30c084b53 100644
--- a/WalletWasabi.Tests/UnitTests/Blockchain/Keys/WpkhOutputDescriptorHelperTests.cs
+++ b/WalletWasabi.Tests/UnitTests/Blockchain/Keys/WpkhOutputDescriptorHelperTests.cs
@@ -12,7 +12,7 @@ public void BasicTest()
{
Network testNet = Network.TestNet;
BitcoinEncryptedSecretNoEC encryptedSecret = new(wif: "6PYJxoa2SLZdYADFyMp3wo41RKaKGNedC3vviix4VdjFfrt1LkKDmXmYTM", Network.Main);
- byte[]? chainCode = ByteHelpers.FromHex("D9DAD5377AB84A44815403FF57B0ABC6825701560DAA0F0FCDDB5A52EBE12A6E");
+ byte[]? chainCode = Convert.FromHexString("D9DAD5377AB84A44815403FF57B0ABC6825701560DAA0F0FCDDB5A52EBE12A6E");
ExtKey accountPrivateKey = new(encryptedSecret.GetKey(password: "123456"), chainCode);
KeyPath keyPath = new("84'/0'/0'");
HDFingerprint masterFingerprint = new(0x2fc4a4f3);
diff --git a/WalletWasabi.Tests/UnitTests/Blockchain/TransactionOutputs/CoinsRegistryTests.cs b/WalletWasabi.Tests/UnitTests/Blockchain/TransactionOutputs/CoinsRegistryTests.cs
index ff35f75c1a..08e783d019 100644
--- a/WalletWasabi.Tests/UnitTests/Blockchain/TransactionOutputs/CoinsRegistryTests.cs
+++ b/WalletWasabi.Tests/UnitTests/Blockchain/TransactionOutputs/CoinsRegistryTests.cs
@@ -153,8 +153,8 @@ public void UndoTransaction_PrevOutCache()
SmartCoin unconfirmedCoin1 = Assert.Single(Coins, coin => coin.HdPubKey.Labels == "B");
SmartCoin unconfirmedCoin2 = Assert.Single(Coins, coin => coin.HdPubKey.Labels == "C");
- Assert.True(unconfirmedCoin1.Transaction.IsRBF);
- Assert.True(unconfirmedCoin2.Transaction.IsRBF);
+ Assert.False(unconfirmedCoin1.Transaction.Confirmed);
+ Assert.False(unconfirmedCoin2.Transaction.Confirmed);
Assert.True(Coins.IsKnown(tx0.GetHash()));
Assert.True(Coins.IsKnown(tx1.GetHash()));
diff --git a/WalletWasabi.Tests/UnitTests/Crypto/HashingTests.cs b/WalletWasabi.Tests/UnitTests/Crypto/HashingTests.cs
deleted file mode 100644
index 4492db6ec5..0000000000
--- a/WalletWasabi.Tests/UnitTests/Crypto/HashingTests.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using NBitcoin.Secp256k1;
-using WalletWasabi.Crypto;
-using Xunit;
-
-namespace WalletWasabi.Tests.UnitTests.Crypto;
-
-public class HashingTests
-{
- [Fact]
- public void HashCodeSameForSameByteArrays()
- {
- var array1 = Array.Empty();
- var array2 = Array.Empty();
- var hashCode1 = HashHelpers.ComputeHashCode(array1);
- var hashCode2 = HashHelpers.ComputeHashCode(array1);
- var hashCode3 = HashHelpers.ComputeHashCode(array2);
- Assert.Equal(hashCode1, hashCode2);
- Assert.Equal(hashCode1, hashCode3);
-
- array1 = new byte[] { 0 };
- array2 = new byte[] { 0 };
- hashCode1 = HashHelpers.ComputeHashCode(array1);
- hashCode2 = HashHelpers.ComputeHashCode(array1);
- hashCode3 = HashHelpers.ComputeHashCode(array2);
- Assert.Equal(hashCode1, hashCode2);
- Assert.Equal(hashCode1, hashCode3);
-
- array1 = new byte[] { 1 };
- array2 = new byte[] { 1 };
- hashCode1 = HashHelpers.ComputeHashCode(array1);
- hashCode2 = HashHelpers.ComputeHashCode(array1);
- hashCode3 = HashHelpers.ComputeHashCode(array2);
- Assert.Equal(hashCode1, hashCode2);
- Assert.Equal(hashCode1, hashCode3);
-
- array1 = new byte[] { 2 };
- array2 = new byte[] { 2 };
- hashCode1 = HashHelpers.ComputeHashCode(array1);
- hashCode2 = HashHelpers.ComputeHashCode(array1);
- hashCode3 = HashHelpers.ComputeHashCode(array2);
- Assert.Equal(hashCode1, hashCode2);
- Assert.Equal(hashCode1, hashCode3);
-
- array1 = new byte[] { 0, 1 };
- array2 = new byte[] { 0, 1 };
- hashCode1 = HashHelpers.ComputeHashCode(array1);
- hashCode2 = HashHelpers.ComputeHashCode(array1);
- hashCode3 = HashHelpers.ComputeHashCode(array2);
- Assert.Equal(hashCode1, hashCode2);
- Assert.Equal(hashCode1, hashCode3);
-
- array1 = new byte[] { 0, 1, 2 };
- array2 = new byte[] { 0, 1, 2 };
- hashCode1 = HashHelpers.ComputeHashCode(array1);
- hashCode2 = HashHelpers.ComputeHashCode(array1);
- hashCode3 = HashHelpers.ComputeHashCode(array2);
- Assert.Equal(hashCode1, hashCode2);
- Assert.Equal(hashCode1, hashCode3);
-
- array1 = new Scalar(int.MaxValue, int.MaxValue - 1, int.MaxValue - 3, int.MaxValue - 7, int.MaxValue - 11, int.MaxValue - 13, int.MaxValue - 17, int.MaxValue - 21).ToBytes();
- array2 = new Scalar(int.MaxValue, int.MaxValue - 1, int.MaxValue - 3, int.MaxValue - 7, int.MaxValue - 11, int.MaxValue - 13, int.MaxValue - 17, int.MaxValue - 21).ToBytes();
- hashCode1 = HashHelpers.ComputeHashCode(array1);
- hashCode2 = HashHelpers.ComputeHashCode(array1);
- hashCode3 = HashHelpers.ComputeHashCode(array2);
- Assert.Equal(hashCode1, hashCode2);
- Assert.Equal(hashCode1, hashCode3);
- }
-}
diff --git a/WalletWasabi.Tests/UnitTests/MockRpcClient.cs b/WalletWasabi.Tests/UnitTests/MockRpcClient.cs
index eee259a42d..65bdfd07db 100644
--- a/WalletWasabi.Tests/UnitTests/MockRpcClient.cs
+++ b/WalletWasabi.Tests/UnitTests/MockRpcClient.cs
@@ -102,11 +102,21 @@ public Task GetRawTransactionAsync(uint256 txid, bool throwIfNotFou
return OnGetRawTransactionAsync?.Invoke(txid, throwIfNotFound) ?? NotImplementedTask(nameof(GetRawTransactionAsync));
}
+ public Task GetRawTransactionInfoAsync(uint256 txid, bool throwIfNotFound = true, CancellationToken cancellationToken = default)
+ {
+ throw new NotImplementedException();
+ }
+
public Task> GetRawTransactionsAsync(IEnumerable txids, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
+ public Task> GetRawTransactionInfosAsync(IEnumerable txids, CancellationToken cancellationToken = default)
+ {
+ throw new NotImplementedException();
+ }
+
public Task GetTxOutAsync(uint256 txid, int index, bool includeMempool = true, CancellationToken cancellationToken = default)
{
return OnGetTxOutAsync switch
@@ -170,11 +180,6 @@ public Task StopAsync(CancellationToken cancellationToken = default)
throw new NotImplementedException();
}
- public Task TestMempoolAcceptAsync(Transaction transaction, CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
-
public Task UptimeAsync(CancellationToken cancellationToken = default)
{
return OnUptimeAsync?.Invoke() ?? NotImplementedTask(nameof(UptimeAsync));
diff --git a/WalletWasabi.Tests/UnitTests/StandaloneTests/ConfigTests.cs b/WalletWasabi.Tests/UnitTests/StandaloneTests/ConfigTests.cs
index 5a9302bdc9..816b9bd4bf 100644
--- a/WalletWasabi.Tests/UnitTests/StandaloneTests/ConfigTests.cs
+++ b/WalletWasabi.Tests/UnitTests/StandaloneTests/ConfigTests.cs
@@ -127,8 +127,6 @@ public static string GetWasabiConfigString(decimal coordinationFeeRate = 0.003m)
"CoinVerifierRequiredConfirmationAmount": "1.00",
"ReleaseFromWhitelistAfter": "31d 0h 0m 0s",
"RoundParallelization": 1,
- "WW200CompatibleLoadBalancing": false,
- "WW200CompatibleLoadBalancingInputSplit": 0.75,
"CoordinatorIdentifier": "CoinJoinCoordinatorIdentifier",
"AllowP2wpkhInputs": true,
"AllowP2trInputs": true,
diff --git a/WalletWasabi.Tests/UnitTests/Tor/Control/TorControlFactoryTests.cs b/WalletWasabi.Tests/UnitTests/Tor/Control/TorControlFactoryTests.cs
index e50f5f5086..ee8a8b9561 100644
--- a/WalletWasabi.Tests/UnitTests/Tor/Control/TorControlFactoryTests.cs
+++ b/WalletWasabi.Tests/UnitTests/Tor/Control/TorControlFactoryTests.cs
@@ -30,7 +30,7 @@ public async Task SafeCookieAuthenticationAsync()
Mock mockRandom = new(MockBehavior.Strict);
mockRandom.Setup(c => c.GetBytes(It.IsAny()))
- .Callback((byte[] dest) => Array.Copy(sourceArray: ByteHelpers.FromHex(clientNonce), dest, 32));
+ .Callback((byte[] dest) => Array.Copy(sourceArray: Convert.FromHexString(clientNonce), dest, 32));
TorControlClientFactory clientFactory = new(mockRandom.Object);
diff --git a/WalletWasabi.Tests/UnitTests/Tor/TorSettingsTests.cs b/WalletWasabi.Tests/UnitTests/Tor/TorSettingsTests.cs
index c569f5953f..2c52f0fe9b 100644
--- a/WalletWasabi.Tests/UnitTests/Tor/TorSettingsTests.cs
+++ b/WalletWasabi.Tests/UnitTests/Tor/TorSettingsTests.cs
@@ -33,6 +33,10 @@ public void GetCmdArgumentsTest()
$"--DataDirectory \"{Path.Combine("temp", "tempDataDir", "tordata2")}\"",
$"--GeoIPFile \"{Path.Combine("tempDistributionDir", "Tor", "Geoip", "geoip")}\"",
$"--GeoIPv6File \"{Path.Combine("tempDistributionDir", "Tor", "Geoip", "geoip6")}\"",
+ $"--NumEntryGuards 3",
+ $"--NumPrimaryGuards 3",
+ $"--ConfluxEnabled 1",
+ $"--ConfluxClientUX throughput",
$"--Log \"notice file {Path.Combine("temp", "tempDataDir", "TorLogs.txt")}\"",
$"__OwningControllerProcess 7");
diff --git a/WalletWasabi.Tests/UnitTests/Transactions/TransactionProcessorTests.cs b/WalletWasabi.Tests/UnitTests/Transactions/TransactionProcessorTests.cs
index 8ad2d29887..1a622129c1 100644
--- a/WalletWasabi.Tests/UnitTests/Transactions/TransactionProcessorTests.cs
+++ b/WalletWasabi.Tests/UnitTests/Transactions/TransactionProcessorTests.cs
@@ -393,8 +393,8 @@ public async Task HandlesRbfAsync()
var unconfirmedCoin1 = Assert.Single(transactionProcessor.Coins, coin => coin.HdPubKey.Labels == "B");
var unconfirmedCoin2 = Assert.Single(transactionProcessor.Coins, coin => coin.HdPubKey.Labels == "C");
- Assert.True(unconfirmedCoin1.Transaction.IsRBF);
- Assert.True(unconfirmedCoin2.Transaction.IsRBF);
+ Assert.False(unconfirmedCoin1.Transaction.Confirmed);
+ Assert.False(unconfirmedCoin2.Transaction.Confirmed);
// Spend the received coin
var tx2 = CreateSpendingTransaction(unconfirmedCoin1.Coin, transactionProcessor.NewKey("D").P2wpkhScript);
@@ -411,7 +411,7 @@ public async Task HandlesRbfAsync()
Assert.True(relevant3.IsNews);
Assert.Equal(1, replaceTransactionReceivedCalled);
var finalCoin = Assert.Single(transactionProcessor.Coins);
- Assert.True(finalCoin.Transaction.IsRBF);
+ Assert.False(finalCoin.Transaction.Confirmed);
Assert.Equal("E", finalCoin.HdPubKey.Labels);
Assert.DoesNotContain(unconfirmedCoin1, transactionProcessor.Coins.AsAllCoinsView());
@@ -514,9 +514,9 @@ public async Task RecognizeReplaceableCoinsCorrectlyAsync()
var coinD = Assert.Single(transactionProcessor.Coins, coin => coin.HdPubKey.Labels == "D");
- Assert.True(coinB.Transaction.IsRBF);
- Assert.True(coinC.Transaction.IsRBF);
- Assert.True(coinD.Transaction.IsRBF);
+ Assert.False(coinB.Transaction.Confirmed);
+ Assert.False(coinC.Transaction.Confirmed);
+ Assert.False(coinD.Transaction.Confirmed);
// Now it is confirmed
var blockHeight = new Height(77551);
@@ -526,8 +526,8 @@ public async Task RecognizeReplaceableCoinsCorrectlyAsync()
coinC = Assert.Single(transactionProcessor.Coins, coin => coin.HdPubKey.Labels == "C");
coinD = Assert.Single(transactionProcessor.Coins, coin => coin.HdPubKey.Labels == "D");
- Assert.False(coinC.Transaction.IsRBF);
- Assert.False(coinD.Transaction.IsRBF);
+ Assert.True(coinC.Transaction.Confirmed);
+ Assert.False(coinD.Transaction.Confirmed);
}
[Fact]
@@ -654,7 +654,7 @@ public async Task HandlesBumpFeeAsync()
Assert.True(relevant2.IsNews);
var coin = Assert.Single(transactionProcessor.Coins);
- Assert.True(coin.Transaction.IsRBF);
+ Assert.False(coin.Transaction.Confirmed);
// Transaction store assertions
var mempool = transactionProcessor.TransactionStore.MempoolStore.GetTransactions();
@@ -708,10 +708,10 @@ public async Task HandlesRbfWithLessCoinsAsync()
relevant = transactionProcessor.Process(tx3);
Assert.True(relevant.IsNews);
- var replaceableCoin = Assert.Single(transactionProcessor.Coins, c => c.Transaction.IsRBF);
+ var replaceableCoin = Assert.Single(transactionProcessor.Coins, c => !c.Transaction.Confirmed);
Assert.Equal(tx3.Transaction.GetHash(), replaceableCoin.TransactionId);
- var nonReplaceableCoin = Assert.Single(transactionProcessor.Coins, c => !c.Transaction.IsRBF);
+ var nonReplaceableCoin = Assert.Single(transactionProcessor.Coins, c => c.Transaction.Confirmed);
Assert.Equal(tx1.Transaction.GetHash(), nonReplaceableCoin.TransactionId);
// Transaction store assertions
diff --git a/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepOutputRegistrationTests.cs b/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepOutputRegistrationTests.cs
index 448c3e2004..a90a905da6 100644
--- a/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepOutputRegistrationTests.cs
+++ b/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepOutputRegistrationTests.cs
@@ -222,7 +222,7 @@ await bobClient.RegisterOutputAsync(
var task1 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin1, keyChain, roundStateUpdater, token, token, token, silentLeaveToken);
var task2 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin2, keyChain, roundStateUpdater, token, token, token, silentLeaveToken);
- while (Phase.ConnectionConfirmation != round.Phase)
+ while (round.Phase < Phase.ConnectionConfirmation)
{
await arena.TriggerAndWaitRoundAsync(token);
}
@@ -283,7 +283,7 @@ public async Task SomeBobsReusingAddressAsync()
var task1a = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round1), arenaClient1, coin1a, keyChain1, roundStateUpdater, token, token, token, silentLeaveToken);
var task1b = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round1), arenaClient1, coin1b, keyChain1, roundStateUpdater, token, token, token, silentLeaveToken);
- while (Phase.ConnectionConfirmation != round1.Phase)
+ while (round1.Phase < Phase.ConnectionConfirmation)
{
await arena.TriggerAndWaitRoundAsync(token);
}
@@ -299,7 +299,7 @@ public async Task SomeBobsReusingAddressAsync()
var task2a = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round2), arenaClient2, coin2a, keyChain2, roundStateUpdater, token, token, token, silentLeaveToken);
var task2b = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round2), arenaClient2, coin2b, keyChain2, roundStateUpdater, token, token, token, silentLeaveToken);
- while (Phase.ConnectionConfirmation != round2.Phase)
+ while (round2.Phase < Phase.ConnectionConfirmation)
{
await arena.TriggerAndWaitRoundAsync(token);
}
@@ -307,7 +307,7 @@ public async Task SomeBobsReusingAddressAsync()
var aliceClient2a = await task2a;
var aliceClient2b = await task2b;
- while (Phase.OutputRegistration != round1.Phase || Phase.OutputRegistration != round2.Phase)
+ while (round1.Phase < Phase.OutputRegistration || round2.Phase < Phase.OutputRegistration)
{
await arena.TriggerAndWaitRoundAsync(token);
}
@@ -377,7 +377,7 @@ await bobClient2.RegisterOutputAsync(
await aliceClient1a.ReadyToSignAsync(token);
await aliceClient1b.ReadyToSignAsync(token);
- while (Phase.TransactionSigning != round1.Phase)
+ while (round1.Phase < Phase.TransactionSigning)
{
await arena.TriggerAndWaitRoundAsync(token);
}
diff --git a/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs b/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
index 294f4b5b39..0b0b984b30 100644
--- a/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
+++ b/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PhaseStepping/StepTransactionSigningTests.cs
@@ -80,7 +80,7 @@ public async Task TransactionBroadcastErrorsAsync()
await aliceClient1.SignTransactionAsync(signedCoinJoin, keyChain, token);
await aliceClient2.SignTransactionAsync(signedCoinJoin, keyChain, token);
await arena.TriggerAndWaitRoundAsync(token);
- Assert.DoesNotContain(round, arena.Rounds.Where(x => x.Phase != Phase.Ended));
+ Assert.DoesNotContain(round, arena.Rounds.Where(x => x.Phase < Phase.Ended));
Assert.Equal(Phase.Ended, round.Phase);
Assert.Equal(EndRoundState.TransactionBroadcastFailed, round.EndRoundState);
@@ -118,7 +118,7 @@ public async Task AlicesSpentAsync()
await aliceClient1.SignTransactionAsync(signedCoinJoin, keyChain, token);
await aliceClient2.SignTransactionAsync(signedCoinJoin, keyChain, token);
await arena.TriggerAndWaitRoundAsync(token);
- Assert.DoesNotContain(round, arena.Rounds.Where(x => x.Phase != Phase.Ended));
+ Assert.DoesNotContain(round, arena.Rounds.Where(x => x.Phase < Phase.Ended));
Assert.Equal(Phase.Ended, round.Phase);
Assert.Equal(EndRoundState.TransactionBroadcastFailed, round.EndRoundState);
@@ -159,7 +159,7 @@ public async Task TimeoutInsufficientPeersAsync()
var signedCoinJoin = round.Assert().CreateUnsignedTransactionWithPrecomputedData();
await aliceClient2.SignTransactionAsync(signedCoinJoin, keyChain, token);
await arena.TriggerAndWaitRoundAsync(token);
- Assert.DoesNotContain(round, arena.Rounds.Where(x => x.Phase != Phase.Ended));
+ Assert.DoesNotContain(round, arena.Rounds.Where(x => x.Phase < Phase.Ended));
Assert.Equal(Phase.Ended, round.Phase);
Assert.Equal(EndRoundState.AbortedNotEnoughAlicesSigned, round.EndRoundState);
Assert.Empty(arena.Rounds.Where(x => x is BlameRound));
@@ -203,7 +203,7 @@ public async Task TimeoutSufficientPeersAsync()
await aliceClient1.SignTransactionAsync(signedCoinJoin, keyChain, token);
await aliceClient2.SignTransactionAsync(signedCoinJoin, keyChain, token);
await arena.TriggerAndWaitRoundAsync(token);
- Assert.DoesNotContain(round, arena.Rounds.Where(x => x.Phase != Phase.Ended));
+ Assert.DoesNotContain(round, arena.Rounds.Where(x => x.Phase < Phase.Ended));
Assert.Single(arena.Rounds.Where(x => x is BlameRound));
var badOutpoint = alice3.Coin.Outpoint;
Assert.True(prison.IsBanned(badOutpoint, cfg.GetDoSConfiguration(), DateTimeOffset.UtcNow));
@@ -289,7 +289,7 @@ public async Task AliceWasNotReadyAsync()
var task1 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin1, keyChain, roundStateUpdater, token, token, token, silentLeaveToken);
var task2 = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, coin2, keyChain, roundStateUpdater, token, token, token, silentLeaveToken);
- while (Phase.OutputRegistration != round.Phase)
+ while (round.Phase < Phase.OutputRegistration)
{
await arena.TriggerAndWaitRoundAsync(token);
}
diff --git a/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/Rounds/Utils/ArenaExtensions.cs b/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/Rounds/Utils/ArenaExtensions.cs
index e4bf515806..1c34e74a11 100644
--- a/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/Rounds/Utils/ArenaExtensions.cs
+++ b/WalletWasabi.Tests/UnitTests/WabiSabi/Backend/Rounds/Utils/ArenaExtensions.cs
@@ -7,5 +7,5 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.Rounds.Utils;
public static class ArenaExtensions
{
public static IEnumerable GetActiveRounds(this Arena arena)
- => arena.Rounds.Where(x => x.Phase != Phase.Ended);
+ => arena.Rounds.Where(x => x.Phase < Phase.Ended);
}
diff --git a/WalletWasabi.Tests/UnitTests/WabiSabi/Client/BobClientTests.cs b/WalletWasabi.Tests/UnitTests/WabiSabi/Client/BobClientTests.cs
index 0dd4d0ee2e..d57c23d69f 100644
--- a/WalletWasabi.Tests/UnitTests/WabiSabi/Client/BobClientTests.cs
+++ b/WalletWasabi.Tests/UnitTests/WabiSabi/Client/BobClientTests.cs
@@ -77,7 +77,7 @@ public async Task RegisterOutputTestAsync()
{
await arena.TriggerAndWaitRoundAsync(token);
}
- while (round.Phase != Phase.ConnectionConfirmation);
+ while (round.Phase < Phase.ConnectionConfirmation);
var aliceClient = await task;
diff --git a/WalletWasabi.Tests/UnitTests/WabiSabi/SerializationTests.cs b/WalletWasabi.Tests/UnitTests/WabiSabi/SerializationTests.cs
index 2229c0b1a5..a01a76d1a2 100644
--- a/WalletWasabi.Tests/UnitTests/WabiSabi/SerializationTests.cs
+++ b/WalletWasabi.Tests/UnitTests/WabiSabi/SerializationTests.cs
@@ -151,7 +151,7 @@ public void ScalarSerialization()
Assert.Equal(Scalar.Zero, deserializedZero);
// Serialization round test.
- var scalar = new Scalar(ByteHelpers.FromHex("D9C17A80D299A51E1ED9CF94FCE5FD883ADACE4ECC167E1D1FB8E5C4A0ADC4D2"));
+ var scalar = new Scalar(Convert.FromHexString("D9C17A80D299A51E1ED9CF94FCE5FD883ADACE4ECC167E1D1FB8E5C4A0ADC4D2"));
var serializedScalar = JsonConvert.SerializeObject(scalar, converters);
Assert.Equal("\"D9C17A80D299A51E1ED9CF94FCE5FD883ADACE4ECC167E1D1FB8E5C4A0ADC4D2\"", serializedScalar);
diff --git a/WalletWasabi.Tests/UnitTests/Wallet/WalletJsonTest.cs b/WalletWasabi.Tests/UnitTests/Wallet/WalletJsonTest.cs
index e946b1d5e1..fe61e09a15 100644
--- a/WalletWasabi.Tests/UnitTests/Wallet/WalletJsonTest.cs
+++ b/WalletWasabi.Tests/UnitTests/Wallet/WalletJsonTest.cs
@@ -311,6 +311,7 @@ public void WalletJsonSaveTest()
"CoinJoinCoinSelectionSettings": {
"UseExperimentalCoinSelector": false,
"ForceUsingLowPrivacyCoins": false,
+ "CanSelectPrivateCoins": false,
"WeightedAnonymityLossNormal": 3,
"ValueLossRateNormal": 0.005,
"TargetCoinCountPerBucket": 10,
diff --git a/WalletWasabi.Tests/WalletWasabi.Tests.csproj b/WalletWasabi.Tests/WalletWasabi.Tests.csproj
index 4d89df03d0..1e590c295e 100644
--- a/WalletWasabi.Tests/WalletWasabi.Tests.csproj
+++ b/WalletWasabi.Tests/WalletWasabi.Tests.csproj
@@ -18,7 +18,6 @@
all
-
diff --git a/WalletWasabi/BitcoinCore/Rpc/IRPCClient.cs b/WalletWasabi/BitcoinCore/Rpc/IRPCClient.cs
index 8c1b7c798e..b269e7c423 100644
--- a/WalletWasabi/BitcoinCore/Rpc/IRPCClient.cs
+++ b/WalletWasabi/BitcoinCore/Rpc/IRPCClient.cs
@@ -40,8 +40,6 @@ public interface IRPCClient
Task GetMempoolInfoAsync(CancellationToken cancel = default);
- Task TestMempoolAcceptAsync(Transaction transaction, CancellationToken cancellationToken = default);
-
Task EstimateSmartFeeAsync(int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, CancellationToken cancellationToken = default);
Task GetTxOutAsync(uint256 txid, int index, bool includeMempool = true, CancellationToken cancellationToken = default);
@@ -60,8 +58,12 @@ public interface IRPCClient
Task GetRawTransactionAsync(uint256 txid, bool throwIfNotFound = true, CancellationToken cancellationToken = default);
+ Task GetRawTransactionInfoAsync(uint256 txid, bool throwIfNotFound = true, CancellationToken cancellationToken = default);
+
Task> GetRawTransactionsAsync(IEnumerable txids, CancellationToken cancel);
+ Task> GetRawTransactionInfosAsync(IEnumerable txids, CancellationToken cancel);
+
Task GetBlockCountAsync(CancellationToken cancellationToken = default);
Task GetNewAddressAsync(CancellationToken cancellationToken = default);
diff --git a/WalletWasabi/BitcoinCore/Rpc/RpcClientBase.cs b/WalletWasabi/BitcoinCore/Rpc/RpcClientBase.cs
index 8fb5b40f25..0430108368 100644
--- a/WalletWasabi/BitcoinCore/Rpc/RpcClientBase.cs
+++ b/WalletWasabi/BitcoinCore/Rpc/RpcClientBase.cs
@@ -123,11 +123,6 @@ public virtual async Task GetRawMempoolAsync(CancellationToken cancel
return await Rpc.GetTxOutAsync(txid, index, includeMempool, cancellationToken).ConfigureAwait(false);
}
- public virtual async Task TestMempoolAcceptAsync(Transaction transaction, CancellationToken cancellationToken = default)
- {
- return await Rpc.TestMempoolAcceptAsync(transaction, cancellationToken).ConfigureAwait(false);
- }
-
public virtual async Task StopAsync(CancellationToken cancellationToken = default)
{
await Rpc.StopAsync(cancellationToken).ConfigureAwait(false);
@@ -202,6 +197,24 @@ public virtual async Task GetRawTransactionAsync(uint256 txid, bool
return await Rpc.GetRawTransactionAsync(txid, throwIfNotFound, cancellationToken).ConfigureAwait(false);
}
+ public virtual async Task GetRawTransactionInfoAsync(uint256 txid, bool throwIfNotFound = true, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ return await Rpc.GetRawTransactionInfoAsync(txid, cancellationToken).ConfigureAwait(false);
+ }
+ catch
+ {
+ {
+ if (throwIfNotFound)
+ {
+ throw;
+ }
+ return null;
+ }
+ }
+ }
+
public virtual async Task> GetRawTransactionsAsync(IEnumerable txids, CancellationToken cancel)
{
// 8 is half of the default rpcworkqueue
@@ -230,6 +243,34 @@ public virtual async Task> GetRawTransactionsAsync(IEnu
return acquiredTransactions;
}
+ public virtual async Task> GetRawTransactionInfosAsync(IEnumerable txids, CancellationToken cancel)
+ {
+ // 8 is half of the default rpcworkqueue
+ List acquiredTransactionInfos = new();
+ foreach (var txidsChunk in txids.ChunkBy(8))
+ {
+ IRPCClient batchingRpc = PrepareBatch();
+ List> tasks = new();
+ foreach (var txid in txidsChunk)
+ {
+ tasks.Add(batchingRpc.GetRawTransactionInfoAsync(txid, throwIfNotFound: false, cancel));
+ }
+
+ await batchingRpc.SendBatchAsync(cancel).ConfigureAwait(false);
+
+ foreach (var tx in await Task.WhenAll(tasks).ConfigureAwait(false))
+ {
+ if (tx is not null)
+ {
+ acquiredTransactionInfos.Add(tx);
+ }
+ cancel.ThrowIfCancellationRequested();
+ }
+ }
+
+ return acquiredTransactionInfos;
+ }
+
public virtual async Task GetBlockCountAsync(CancellationToken cancellationToken = default)
{
return await Rpc.GetBlockCountAsync(cancellationToken).ConfigureAwait(false);
diff --git a/WalletWasabi/Blockchain/Analysis/FeesEstimation/AllFeeEstimate.cs b/WalletWasabi/Blockchain/Analysis/FeesEstimation/AllFeeEstimate.cs
index ba1f218468..6f2f35e2ea 100644
--- a/WalletWasabi/Blockchain/Analysis/FeesEstimation/AllFeeEstimate.cs
+++ b/WalletWasabi/Blockchain/Analysis/FeesEstimation/AllFeeEstimate.cs
@@ -21,12 +21,16 @@ public class AllFeeEstimate : IEquatable
.Skip(1)
.Zip(AllConfirmationTargets.Skip(1).Prepend(0), (x, y) => (Start: y, End: x));
+ [JsonConstructor]
+ public AllFeeEstimate(Dictionary estimations) : this(estimations.Select(x => (x.Key, new FeeRate((decimal)x.Value))).ToDictionary())
+ {
+ }
+
///
/// Constructor takes the input confirmation estimations and filters out all confirmation targets that are not whitelisted.
///
/// Map of confirmation targets to fee rates in satoshis (e.g. confirmation target 1 -> 50 sats/vByte).
- [JsonConstructor]
- public AllFeeEstimate(IDictionary estimations)
+ public AllFeeEstimate(IDictionary estimations)
{
Guard.NotNullOrEmpty(nameof(estimations), estimations);
@@ -39,7 +43,7 @@ public AllFeeEstimate(IDictionary estimations)
// Make sure values are unique and in the correct order and fee rates are consistently decreasing.
Estimations = [];
- var lastFeeRate = int.MaxValue;
+ var lastFeeRate = new FeeRate(Constants.MaximumNumberOfBitcoinsMoney);
foreach (var estimation in filteredEstimations)
{
// Otherwise it's inconsistent data.
@@ -51,11 +55,16 @@ public AllFeeEstimate(IDictionary estimations)
}
}
+ [JsonProperty("Estimations")]
+ public Dictionary JsonEstimations
+ {
+ get => Estimations.Select(x => (x.Key, (int)Math.Floor(x.Value.SatoshiPerByte))).ToDictionary();
+ }
+
///
/// Gets the fee estimations: int: fee target, int: satoshi/vByte
///
- [JsonProperty]
- public Dictionary Estimations { get; }
+ public Dictionary Estimations { get; }
///
/// Estimations where we try to fill out gaps for all valid time spans.
@@ -70,7 +79,7 @@ public AllFeeEstimate(IDictionary estimations)
}
var timeSpan = TimeSpan.FromMinutes(20);
- IEnumerable<(TimeSpan timeSpan, FeeRate feeRate)> convertedEstimations = Estimations.Select(x => (TimeSpan.FromMinutes(x.Key * 10), new FeeRate((decimal)x.Value)));
+ IEnumerable<(TimeSpan timeSpan, FeeRate feeRate)> convertedEstimations = Estimations.Select(x => (TimeSpan.FromMinutes(x.Key * 10), x.Value));
var wildEstimations = new List<(TimeSpan timeSpan, FeeRate feeRate)>();
var prevFeeRate = FeeRate.Zero;
@@ -135,11 +144,9 @@ public AllFeeEstimate(IDictionary estimations)
public FeeRate GetFeeRate(int confirmationTarget)
{
// Where the target is still under or equal to the requested target.
- decimal satoshiPerByte = Estimations
+ return Estimations
.Last(x => x.Key <= confirmationTarget) // The last should be the largest confirmation target.
.Value;
-
- return new FeeRate(satoshiPerByte);
}
public bool TryEstimateConfirmationTime(SmartTransaction tx, [NotNullWhen(true)] out TimeSpan? confirmationTime)
@@ -198,7 +205,7 @@ public TimeSpan EstimateConfirmationTime(FeeRate feeRate)
public override int GetHashCode()
{
int hash = 13;
- foreach (KeyValuePair est in Estimations)
+ foreach (var est in Estimations)
{
hash ^= est.Key.GetHashCode() ^ est.Value.GetHashCode();
}
@@ -224,7 +231,7 @@ public override int GetHashCode()
equal = true;
foreach (var pair in x.Estimations)
{
- if (y.Estimations.TryGetValue(pair.Key, out int value))
+ if (y.Estimations.TryGetValue(pair.Key, out FeeRate? value))
{
// Require value be equal.
if (value != pair.Value)
diff --git a/WalletWasabi/Blockchain/BlockFilters/IndexBuilderService.cs b/WalletWasabi/Blockchain/BlockFilters/IndexBuilderService.cs
index b8217e66e2..fd11fef2e6 100644
--- a/WalletWasabi/Blockchain/BlockFilters/IndexBuilderService.cs
+++ b/WalletWasabi/Blockchain/BlockFilters/IndexBuilderService.cs
@@ -72,7 +72,7 @@ public IndexBuilderService(IndexType indexType, IRPCClient rpc, BlockNotifier bl
BlockNotifier.OnBlock += BlockNotifier_OnBlock;
}
- public static byte[][] DummyScript { get; } = new byte[][] { ByteHelpers.FromHex("0009BBE4C2D17185643765C265819BF5261755247D") };
+ public static byte[][] DummyScript { get; } = [Convert.FromHexString("0009BBE4C2D17185643765C265819BF5261755247D")];
private IRPCClient RpcClient { get; }
private BlockNotifier BlockNotifier { get; }
@@ -81,6 +81,7 @@ public IndexBuilderService(IndexType indexType, IRPCClient rpc, BlockNotifier bl
/// Guards .
private object IndexLock { get; } = new();
+
private uint StartingHeight { get; }
public bool IsRunning => Interlocked.Read(ref _serviceStatus) == Running;
private bool IsStopping => Interlocked.Read(ref _serviceStatus) >= Stopping;
diff --git a/WalletWasabi/Blockchain/TransactionBuilding/FeeStrategy.cs b/WalletWasabi/Blockchain/TransactionBuilding/FeeStrategy.cs
index 8033a59165..75d7d0c643 100644
--- a/WalletWasabi/Blockchain/TransactionBuilding/FeeStrategy.cs
+++ b/WalletWasabi/Blockchain/TransactionBuilding/FeeStrategy.cs
@@ -6,7 +6,7 @@ namespace WalletWasabi.Blockchain.TransactionBuilding;
public class FeeStrategy
{
- public static readonly FeeRate MinimumFeeRate = new(1m);
+ public static readonly FeeRate MinimumFeeRate = Constants.MinRelayFeeRate;
private int? _target;
private FeeRate? _feeRate;
@@ -22,7 +22,7 @@ private FeeStrategy(FeeRate feeRate)
{
if (feeRate < MinimumFeeRate)
{
- throw new ArgumentOutOfRangeException(nameof(feeRate), feeRate, "Cannot be less than 1 sat/vByte.");
+ throw new ArgumentOutOfRangeException(nameof(feeRate), feeRate, $"Cannot be less than {MinimumFeeRate.SatoshiPerByte} sat/vByte.");
}
Type = FeeStrategyType.Rate;
diff --git a/WalletWasabi/Blockchain/Transactions/SmartTransaction.cs b/WalletWasabi/Blockchain/Transactions/SmartTransaction.cs
index 7613b9f328..254822fbbd 100644
--- a/WalletWasabi/Blockchain/Transactions/SmartTransaction.cs
+++ b/WalletWasabi/Blockchain/Transactions/SmartTransaction.cs
@@ -201,13 +201,6 @@ public IReadOnlyCollection ForeignVirtualOutputs
public uint256 GetHash() => Transaction.GetHash();
- ///
- /// A transaction can signal that is replaceable by fee in two ways:
- /// * Explicitly by using a nSequence < (0xffffffff - 1) or,
- /// * Implicitly in case one of its unconfirmed ancestors are replaceable
- ///
- public bool IsRBF => !Confirmed && (Transaction.RBF || IsReplacement || WalletInputs.Any(x => x.Transaction.IsRBF));
-
public bool IsImmature(int bestHeight)
{
return Transaction.IsCoinBase && Height >= bestHeight - 100;
@@ -273,7 +266,6 @@ public bool IsCpfpable(KeyManager keyManager) =>
public bool IsRbfable(KeyManager keyManager) =>
!keyManager.IsWatchOnly && !keyManager.IsHardwareWallet // [Difficultly] Watch-only and hardware wallets are problematic. It remains a ToDo for the future.
&& !Confirmed // [Impossibility] We can only speed up unconfirmed transactions.
- && IsRBF // [Impossibility] Otherwise it must signal RBF.
&& !GetForeignInputs(keyManager).Any() // [Impossibility] Must not have foreign inputs, otherwise we couldn't do RBF.
&& WalletOutputs.All(x => !x.IsSpent()); // [Dangerous] All the outputs we know of should not be spent, otherwise we shouldn't do RBF.
diff --git a/WalletWasabi/Blockchain/Transactions/TransactionFactory.cs b/WalletWasabi/Blockchain/Transactions/TransactionFactory.cs
index 54475a0450..41f02cf9f9 100644
--- a/WalletWasabi/Blockchain/Transactions/TransactionFactory.cs
+++ b/WalletWasabi/Blockchain/Transactions/TransactionFactory.cs
@@ -144,8 +144,6 @@ public BuildTransactionResult BuildTransaction(
builder.SetChange(changeHdPubKey.GetAssumedScriptPubKey());
}
- builder.OptInRBF = true;
-
builder.SendEstimatedFees(parameters.FeeRate);
var psbt = builder.BuildPSBT(false);
@@ -164,7 +162,10 @@ public BuildTransactionResult BuildTransaction(
throw new InvalidOperationException("Impossible to get the fees of the PSBT, this should never happen.");
}
- var vSize = builder.EstimateSize(psbt.GetOriginalTransaction(), true);
+ if (!psbt.TryGetVirtualSize(out var vSize))
+ {
+ throw new InvalidOperationException("It was not possible to get the virtual size of the transaction");
+ }
// Do some checks
Money totalSendAmountNoFee = realToSend.Sum(x => x.amount);
diff --git a/WalletWasabi/Crypto/HashHelpers.cs b/WalletWasabi/Crypto/HashHelpers.cs
deleted file mode 100644
index 2d5b959cf6..0000000000
--- a/WalletWasabi/Crypto/HashHelpers.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Security.Cryptography;
-using System.Text;
-using WalletWasabi.Helpers;
-
-namespace WalletWasabi.Crypto;
-
-public static class HashHelpers
-{
- /// SHA-256 hash. Letters are always in upper-case.
- public static string GenerateSha256Hash(string input) => ByteHelpers.ToHex(GenerateSha256Hash(Encoding.UTF8.GetBytes(input)));
-
- public static byte[] GenerateSha256Hash(byte[] input)
- {
- var hash = SHA256.HashData(input);
-
- return hash;
- }
-
- public static int ComputeHashCode(params byte[] data)
- {
- var hash = new HashCode();
- foreach (var element in data)
- {
- hash.Add(element);
- }
- return hash.ToHashCode();
- }
-}
diff --git a/WalletWasabi/Extensions/NBitcoinExtensions.cs b/WalletWasabi/Extensions/NBitcoinExtensions.cs
index 651fb76173..e079f9d8d8 100644
--- a/WalletWasabi/Extensions/NBitcoinExtensions.cs
+++ b/WalletWasabi/Extensions/NBitcoinExtensions.cs
@@ -57,13 +57,13 @@ public static async Task DownloadBlockAsync(this Node node, uint256 hash,
public static string ToHex(this IBitcoinSerializable me)
{
- return ByteHelpers.ToHex(me.ToBytes());
+ return Convert.ToHexString(me.ToBytes());
}
public static void FromHex(this IBitcoinSerializable me, string hex)
{
Guard.NotNullOrEmptyOrWhitespace(nameof(hex), hex);
- me.FromBytes(ByteHelpers.FromHex(hex));
+ me.FromBytes(Convert.FromHexString(hex));
}
///
@@ -525,7 +525,7 @@ public static bool TryParseBitcoinAddressForNetwork(string address, Network netw
}
}
- public static double GetAnonScore(this Transaction transaction)
+ public static double GetAnonSet(this Transaction transaction)
{
int totalCount = transaction.Outputs.Count;
int diffCount = transaction.Outputs.Select(x => x.Value.Satoshi).ToHashSet().Count;
diff --git a/WalletWasabi/Extensions/RPCClientExtensions.cs b/WalletWasabi/Extensions/RPCClientExtensions.cs
index 7b71f8834f..4b09bb885a 100644
--- a/WalletWasabi/Extensions/RPCClientExtensions.cs
+++ b/WalletWasabi/Extensions/RPCClientExtensions.cs
@@ -9,7 +9,7 @@
using WalletWasabi.Blockchain.Analysis.FeesEstimation;
using WalletWasabi.Helpers;
using WalletWasabi.Logging;
-using FeeRateByConfirmationTarget = System.Collections.Generic.Dictionary;
+using FeeRateByConfirmationTarget = System.Collections.Generic.Dictionary;
namespace WalletWasabi.Extensions;
@@ -38,8 +38,8 @@ private static EstimateSmartFeeResponse SimulateRegTestFeeEstimation(int confirm
private static FeeRateByConfirmationTarget SimulateRegTestFeeEstimation() =>
Constants.ConfirmationTargets
- .Select(target => SimulateRegTestFeeEstimation(target))
- .ToDictionary(x => x.Blocks, x => (int)Math.Ceiling(x.FeeRate.SatoshiPerByte));
+ .Select(SimulateRegTestFeeEstimation)
+ .ToDictionary(x => x.Blocks, x => x.FeeRate);
///
/// If null is returned, no exception is thrown, so the test was successful.
@@ -80,10 +80,10 @@ public static async Task EstimateAllFeeAsync(this IRPCClient rpc
private static FeeRateByConfirmationTarget SmartEstimationsWithMempoolInfo(FeeRateByConfirmationTarget smartEstimations, MemPoolInfo mempoolInfo)
{
var minEstimations = GetFeeEstimationsFromMempoolInfo(mempoolInfo);
- var minEstimationFor260Mb = new FeeRate((decimal)minEstimations.GetValueOrDefault(260 / 4));
+ var minEstimationFor260Mb = minEstimations.GetValueOrDefault(260 / 4) ?? FeeRate.Zero;
var minSanityFeeRate = FeeRate.Max(minEstimationFor260Mb, mempoolInfo.GetSanityFeeRate());
- var estimationForTarget2 = minEstimations.GetValueOrDefault(2);
- var maxEstimationFor3Mb = new FeeRate(estimationForTarget2 > 0 ? estimationForTarget2 : 5_000m);
+ var estimationForTarget2 = minEstimations.GetValueOrDefault(2) ?? FeeRate.Zero;
+ var maxEstimationFor3Mb = estimationForTarget2 > FeeRate.Zero ? estimationForTarget2 : new FeeRate(5_000m);
var maxSanityFeeRate = maxEstimationFor3Mb;
var fixedEstimations = smartEstimations
@@ -93,12 +93,12 @@ private static FeeRateByConfirmationTarget SmartEstimationsWithMempoolInfo(FeeRa
inner => inner.Key,
(outer, inner) => new { Estimation = outer, MinimumFromMemPool = inner })
.SelectMany(
- x => x.MinimumFromMemPool.DefaultIfEmpty(),
+ x => x.MinimumFromMemPool.Any() ? x.MinimumFromMemPool : [KeyValuePair.Create(0, FeeRate.Zero)],
(a, b) =>
{
- var maxLowerBound = Math.Max(a.Estimation.Value, b.Value);
- var maxMinFeeRate = Math.Max((int)minSanityFeeRate.SatoshiPerByte, maxLowerBound);
- var minMaxFeeRate = Math.Min((int)maxSanityFeeRate.SatoshiPerByte, maxMinFeeRate);
+ var maxLowerBound = FeeRate.Max(a.Estimation.Value, b.Value);
+ var maxMinFeeRate = FeeRate.Max(minSanityFeeRate, maxLowerBound);
+ var minMaxFeeRate = FeeRate.Min(maxSanityFeeRate, maxMinFeeRate);
return (
Target: a.Estimation.Key,
FeeRate: minMaxFeeRate);
@@ -137,7 +137,7 @@ private static async Task GetFeeEstimationsAsync(IR
.Where(x => x.IsCompletedSuccessfully)
.Select(x => (target: x.Result.Blocks, feeRate: x.Result.FeeRate))
.DistinctBy(x => x.target)
- .ToDictionary(x => x.target, x => (int)Math.Ceiling(x.feeRate.SatoshiPerByte));
+ .ToDictionary(x => x.target, x => x.feeRate);
}
private static FeeRateByConfirmationTarget GetFeeEstimationsFromMempoolInfo(MemPoolInfo mempoolInfo)
@@ -202,10 +202,10 @@ private static FeeRateByConfirmationTarget GetFeeEstimationsFromMempoolInfo(MemP
var consolidatedFeeGroupByTarget = feeGroupsByTarget
.GroupBy(
x => x.Target,
- (target, feeGroups) => (Target: target, FeeRate: feeGroups.Last().FeeRate.SatoshiPerByte));
+ (target, feeGroups) => (Target: target, FeeRate: feeGroups.Last().FeeRate));
var feeRateByConfirmationTarget = consolidatedFeeGroupByTarget
- .ToDictionary(x => x.Target, x => (int)Math.Ceiling(x.FeeRate));
+ .ToDictionary(x => x.Target, x => x.FeeRate);
return feeRateByConfirmationTarget;
}
@@ -226,41 +226,6 @@ public static async Task GetRpcStatusAsync(this IRPCClient rpc, Cance
}
}
- public static async Task<(bool accept, string rejectReason)> TestMempoolAcceptAsync(this IRPCClient rpc, IEnumerable coins, int fakeOutputCount, Money feePerInputs, Money feePerOutputs, CancellationToken cancellationToken)
- {
- // Check if mempool would accept a fake transaction created with the registered inputs.
- // This will catch ascendant/descendant count and size limits for example.
- var fakeTransaction = rpc.Network.CreateTransaction();
- fakeTransaction.Inputs.AddRange(coins.Select(coin => new TxIn(coin.Outpoint)));
- Money totalFakeOutputsValue;
- try
- {
- totalFakeOutputsValue = NBitcoinHelpers.TakeFee(coins, fakeOutputCount, feePerInputs, feePerOutputs);
- }
- catch (InvalidOperationException ex)
- {
- return (false, ex.Message);
- }
- for (int i = 0; i < fakeOutputCount; i++)
- {
- var fakeOutputValue = totalFakeOutputsValue / fakeOutputCount;
- fakeTransaction.Outputs.Add(fakeOutputValue, new Key());
- }
- MempoolAcceptResult testMempoolAcceptResult = await rpc.TestMempoolAcceptAsync(fakeTransaction, cancellationToken).ConfigureAwait(false);
-
- if (!testMempoolAcceptResult.IsAllowed)
- {
- string rejected = testMempoolAcceptResult.RejectReason;
-
- if (!(rejected.Contains("mandatory-script-verify-flag-failed", StringComparison.OrdinalIgnoreCase)
- || rejected.Contains("non-mandatory-script-verify-flag", StringComparison.OrdinalIgnoreCase)))
- {
- return (false, rejected);
- }
- }
- return (true, "");
- }
-
///
/// Gets the transactions that are unconfirmed using getrawmempool.
/// This is efficient when many transaction ids are provided.
diff --git a/WalletWasabi/Helpers/ByteArrayEqualityComparer.cs b/WalletWasabi/Helpers/ByteArrayEqualityComparer.cs
index 046636cc1f..abb3c7b80d 100644
--- a/WalletWasabi/Helpers/ByteArrayEqualityComparer.cs
+++ b/WalletWasabi/Helpers/ByteArrayEqualityComparer.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using WalletWasabi.Crypto;
namespace WalletWasabi.Helpers;
@@ -8,5 +7,10 @@ public class ByteArrayEqualityComparer : IEqualityComparer
{
public bool Equals([AllowNull] byte[] x, [AllowNull] byte[] y) => ByteHelpers.CompareFastUnsafe(x, y);
- public int GetHashCode([DisallowNull] byte[] obj) => HashHelpers.ComputeHashCode(obj);
+ public int GetHashCode([DisallowNull] byte[] obj)
+ {
+ var hash = new HashCode();
+ hash.AddBytes(obj);
+ return hash.ToHashCode();
+ }
}
diff --git a/WalletWasabi/Helpers/ByteHelpers.cs b/WalletWasabi/Helpers/ByteHelpers.cs
index 711a8d4202..0253331366 100644
--- a/WalletWasabi/Helpers/ByteHelpers.cs
+++ b/WalletWasabi/Helpers/ByteHelpers.cs
@@ -86,21 +86,4 @@ public static unsafe bool CompareFastUnsafe(byte[]? array1, byte[]? array2)
return true;
}
}
-
- ///
- public static string ToHex(params byte[] bytes)
- {
- return Convert.ToHexString(bytes);
- }
-
- ///
- public static byte[] FromHex(string hex)
- {
- if (string.IsNullOrWhiteSpace(hex))
- {
- return Array.Empty();
- }
-
- return Convert.FromHexString(hex);
- }
}
diff --git a/WalletWasabi/Helpers/ImportWalletHelper.cs b/WalletWasabi/Helpers/ImportWalletHelper.cs
index 4dfb8475ca..5f83f45017 100644
--- a/WalletWasabi/Helpers/ImportWalletHelper.cs
+++ b/WalletWasabi/Helpers/ImportWalletHelper.cs
@@ -81,7 +81,7 @@ private static KeyManager GetKeyManagerByColdcardJson(WalletManager manager, JOb
}
}
- var bytes = ByteHelpers.FromHex(Guard.NotNullOrEmptyOrWhitespace(nameof(mfpString), mfpString, trim: true));
+ var bytes = Convert.FromHexString(Guard.NotNullOrEmptyOrWhitespace(nameof(mfpString), mfpString, trim: true));
HDFingerprint mfp = reverseByteOrder ? new HDFingerprint(bytes.Reverse().ToArray()) : new HDFingerprint(bytes);
if (manager.WalletExists(mfp))
diff --git a/WalletWasabi/Helpers/NBitcoinHelpers.cs b/WalletWasabi/Helpers/NBitcoinHelpers.cs
index c63247fa0a..193f91847d 100644
--- a/WalletWasabi/Helpers/NBitcoinHelpers.cs
+++ b/WalletWasabi/Helpers/NBitcoinHelpers.cs
@@ -49,7 +49,7 @@ public static ExtPubKey BetterParseExtPubKey(string extPubKeyString)
catch
{
// Try hex, Old wallet format was like this.
- epk = new ExtPubKey(ByteHelpers.FromHex(extPubKeyString)); // Starts with "ExtPubKey": "hexbytes...
+ epk = new ExtPubKey(Convert.FromHexString(extPubKeyString)); // Starts with "ExtPubKey": "hexbytes...
}
}
}
diff --git a/WalletWasabi/JsonConverters/HDFingerprintJsonConverter.cs b/WalletWasabi/JsonConverters/HDFingerprintJsonConverter.cs
index 5ac754572f..b4bf459056 100644
--- a/WalletWasabi/JsonConverters/HDFingerprintJsonConverter.cs
+++ b/WalletWasabi/JsonConverters/HDFingerprintJsonConverter.cs
@@ -1,6 +1,5 @@
using NBitcoin;
using Newtonsoft.Json;
-using WalletWasabi.Helpers;
namespace WalletWasabi.JsonConverters;
@@ -9,13 +8,8 @@ public class HDFingerprintJsonConverter : JsonConverter
///
public override HDFingerprint? ReadJson(JsonReader reader, Type objectType, HDFingerprint? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
- var s = (string?)reader.Value;
- if (string.IsNullOrWhiteSpace(s))
- {
- return null;
- }
-
- return new HDFingerprint(ByteHelpers.FromHex(s));
+ var s = reader.Value as string;
+ return !string.IsNullOrWhiteSpace(s) ? new HDFingerprint(Convert.FromHexString(s)) : null;
}
///
diff --git a/WalletWasabi/Lang/Resources.Designer.cs b/WalletWasabi/Lang/Resources.Designer.cs
index 68a7b0b24c..c2eca62e8b 100644
--- a/WalletWasabi/Lang/Resources.Designer.cs
+++ b/WalletWasabi/Lang/Resources.Designer.cs
@@ -1,4 +1,4 @@
-//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
@@ -924,6 +924,24 @@ public static string CannotModifyWithTwoFactorEnabled {
}
}
+ ///
+ /// Looks up a localized string similar to Can select already private coins.
+ ///
+ public static string CanSelectPrivateCoinsInCoinJoinCoinSelector {
+ get {
+ return ResourceManager.GetString("CanSelectPrivateCoinsInCoinJoinCoinSelector", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The selection is allowed to contain already private coins..
+ ///
+ public static string CanSelectPrivateCoinsInCoinJoinCoinSelectorToolTip {
+ get {
+ return ResourceManager.GetString("CanSelectPrivateCoinsInCoinJoinCoinSelectorToolTip", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Can't participate in coinjoin until: {0}.
///
diff --git a/WalletWasabi/Lang/Resources.de.resx b/WalletWasabi/Lang/Resources.de.resx
index c675bc80a5..0f0b06b043 100644
--- a/WalletWasabi/Lang/Resources.de.resx
+++ b/WalletWasabi/Lang/Resources.de.resx
@@ -2119,21 +2119,6 @@
Als Standard festlegen
-
- Bitcoin-Netzwerkdaten werden heruntergeladen und verarbeitet
-
-
- Dieser Prozess kann beim ersten Start, bei großen Wallets oder nach längeren Synchronisationspausen länger dauern.
-
-
- Ginger tut dies, ohne dass Dritte von Deinem Kontostand oder Deiner finanziellen Aktivität erfahren.
-
-
- Zwei-Faktor-Authentifizierung ist deaktiviert. Aktiviere sie in den Einstellungen für besseren Schutz.
-
-
- Einstellungen öffnen
-
Nachricht signieren
@@ -2200,4 +2185,10 @@
Rundenunterbrechung
+
+ Bereits private Coins können ausgewählt werden
+
+
+ Die Auswahl darf bereits private Coins enthalten.
+
diff --git a/WalletWasabi/Lang/Resources.es.resx b/WalletWasabi/Lang/Resources.es.resx
index f1cdf6f6eb..946ef9b7ac 100644
--- a/WalletWasabi/Lang/Resources.es.resx
+++ b/WalletWasabi/Lang/Resources.es.resx
@@ -2185,4 +2185,10 @@
Interrupción de la ronda
+
+ Se pueden seleccionar monedas ya privadas
+
+
+ La selección puede contener monedas ya privadas.
+
diff --git a/WalletWasabi/Lang/Resources.fr.resx b/WalletWasabi/Lang/Resources.fr.resx
index 76c6d62a19..810eee8b9e 100644
--- a/WalletWasabi/Lang/Resources.fr.resx
+++ b/WalletWasabi/Lang/Resources.fr.resx
@@ -2112,12 +2112,6 @@
Impossible de supprimer le portefeuille, consultez les journaux pour plus de détails.
-
-
- L'authentification à deux facteurs est désactivée. Activez-la dans les paramètres pour une meilleure protection.
-
-
- Ouvrir les paramètres
Synchronisation de votre portefeuille...
@@ -2191,4 +2185,10 @@
Interruption de la manche
+
+ Il est possible de sélectionner des pièces déjà privées
+
+
+ La sélection est autorisée à contenir des pièces déjà privées.
+
diff --git a/WalletWasabi/Lang/Resources.hu.resx b/WalletWasabi/Lang/Resources.hu.resx
index 9d7bdf2ea6..00f0708a85 100644
--- a/WalletWasabi/Lang/Resources.hu.resx
+++ b/WalletWasabi/Lang/Resources.hu.resx
@@ -1597,7 +1597,7 @@
Régi érmekiválasztó használata másodlagos opcióként
- Az új és a régi pénzválasztó is használatban lesz, és a jobb eredmény kerül kiválasztásra.
+ Az új és a régi érmeválasztó is használatban lesz, és a jobb eredmény kerül kiválasztásra.
Konfiguráció
@@ -2185,4 +2185,10 @@
Kör megszakítása
+
+ Már anonim érmék is választhatók
+
+
+ A kiválasztott érmék tartalmazhatnak már anonim érméket is.
+
diff --git a/WalletWasabi/Lang/Resources.it.resx b/WalletWasabi/Lang/Resources.it.resx
index 9cf63dfb56..7fba50b606 100644
--- a/WalletWasabi/Lang/Resources.it.resx
+++ b/WalletWasabi/Lang/Resources.it.resx
@@ -2089,6 +2089,27 @@
Avvia il coinjoin per ottenere privacy
+
+ Risincronizza
+
+
+ Elimina Portafoglio
+
+
+ Elimina
+
+
+ Eliminare un portafoglio è permanente e non può essere annullato. Il portafoglio può essere ripristinato solo utilizzando le tue parole di recupero, quindi assicurati di averle. Per confermare l’eliminazione, inserisci
+
+
+ nel campo sottostante.
+
+
+ Non è richiesto il caricamento di documenti per acquisti inferiori a 1000 USD con questo fornitore.
+
+
+ Dati sensibili
+
Impossibile eliminare il portafoglio, controlla i log per maggiori dettagli.
@@ -2164,4 +2185,10 @@
Interruzione del turno
+
+ È possibile selezionare monete già private
+
+
+ La selezione può contenere monete già private.
+
diff --git a/WalletWasabi/Lang/Resources.pt.resx b/WalletWasabi/Lang/Resources.pt.resx
index aeec8de4c2..19f822b319 100644
--- a/WalletWasabi/Lang/Resources.pt.resx
+++ b/WalletWasabi/Lang/Resources.pt.resx
@@ -2185,4 +2185,10 @@
Interrupção da rodada
+
+ É possível selecionar moedas já privadas
+
+
+ A seleção pode conter moedas já privadas.
+
diff --git a/WalletWasabi/Lang/Resources.resx b/WalletWasabi/Lang/Resources.resx
index f7a7c2cb5c..2c8adf80ff 100644
--- a/WalletWasabi/Lang/Resources.resx
+++ b/WalletWasabi/Lang/Resources.resx
@@ -2091,7 +2091,7 @@
Start coinjoining to gain privacy
-
+
Resync
@@ -2187,4 +2187,10 @@
Round Interruption
+
+ Can select already private coins
+
+
+ The selection is allowed to contain already private coins.
+
diff --git a/WalletWasabi/Lang/Resources.tr.resx b/WalletWasabi/Lang/Resources.tr.resx
index 7ebc26026e..f1415ecca1 100644
--- a/WalletWasabi/Lang/Resources.tr.resx
+++ b/WalletWasabi/Lang/Resources.tr.resx
@@ -2185,4 +2185,10 @@
Turun kesilmesi
+
+ Zaten özel olan coinler seçilebilir
+
+
+ Seçim, zaten özel olan coinleri içerebilir.
+
diff --git a/WalletWasabi/Lang/Resources.zh.resx b/WalletWasabi/Lang/Resources.zh.resx
index df8e2184c8..13465e7e1b 100644
--- a/WalletWasabi/Lang/Resources.zh.resx
+++ b/WalletWasabi/Lang/Resources.zh.resx
@@ -2118,21 +2118,6 @@
隐藏
-
-
- 比特币网络数据下载与处理
-
-
- 首次启动、大型钱包或距上次同步间隔较久时,此过程可能需要更长时间。
-
-
- Ginger 通过这种方式确保第三方无法获知你的账户余额和财务活动。
-
-
- 双重验证已关闭。请至设置开启增强防护。
-
-
- 打开设置
签署消息
@@ -2200,4 +2185,10 @@
回合中断
+
+ 可以选择已经私有的币
+
+
+ 选择中允许包含已经私有的币。
+
diff --git a/WalletWasabi/Stores/IndexStore.cs b/WalletWasabi/Stores/IndexStore.cs
index f3e89645a9..d2a4e758b7 100644
--- a/WalletWasabi/Stores/IndexStore.cs
+++ b/WalletWasabi/Stores/IndexStore.cs
@@ -2,7 +2,6 @@
using NBitcoin;
using Nito.AsyncEx;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
@@ -28,15 +27,11 @@ public IndexStore(string workFolderPath, Network network, SmartHeaderChain smart
workFolderPath = Guard.NotNullOrEmptyOrWhitespace(nameof(workFolderPath), workFolderPath, trim: true);
IoHelpers.EnsureDirectoryExists(workFolderPath);
- // Migration data.
- OldIndexFilePath = Path.Combine(workFolderPath, "MatureIndex.dat");
- OldImmatureIndexFilePath = Path.Combine(workFolderPath, "ImmatureIndex.dat");
- NewIndexFilePath = Path.Combine(workFolderPath, "IndexStore.sqlite");
- RunMigration = File.Exists(OldIndexFilePath);
+ IndexFilePath = Path.Combine(workFolderPath, "IndexStore.sqlite");
if (network == Network.RegTest)
{
- File.Delete(NewIndexFilePath);
+ File.Delete(IndexFilePath);
}
IndexStorage = CreateBlockFilterSqliteStorage();
@@ -46,13 +41,13 @@ private BlockFilterSqliteStorage CreateBlockFilterSqliteStorage()
{
try
{
- return BlockFilterSqliteStorage.FromFile(dataSource: NewIndexFilePath, startingFilter: StartingFilters.GetStartingFilter(Network));
+ return BlockFilterSqliteStorage.FromFile(dataSource: IndexFilePath, startingFilter: StartingFilters.GetStartingFilter(Network));
}
catch (SqliteException ex) when (ex.SqliteExtendedErrorCode == 11) // 11 ~ SQLITE_CORRUPT error code
{
- Logger.LogError($"Failed to open SQLite storage file because it's corrupted. Deleting the storage file '{NewIndexFilePath}'.");
+ Logger.LogError($"Failed to open SQLite storage file because it's corrupted. Deleting the storage file '{IndexFilePath}'.");
- File.Delete(NewIndexFilePath);
+ File.Delete(IndexFilePath);
throw;
}
}
@@ -61,17 +56,7 @@ private BlockFilterSqliteStorage CreateBlockFilterSqliteStorage()
public event EventHandler>? NewFilters;
- /// Mature index path for migration purposes.
- private string OldIndexFilePath { get; }
-
- /// Immature index path for migration purposes.
- private string OldImmatureIndexFilePath { get; }
-
- /// SQLite file path for migration purposes.
- private string NewIndexFilePath { get; }
-
- /// Run migration if SQLite file does not exist.
- private bool RunMigration { get; }
+ private string IndexFilePath { get; }
/// NBitcoin network.
private Network Network { get; }
@@ -97,16 +82,6 @@ public async Task InitializeAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
- // Migration code.
- if (RunMigration)
- {
- MigrateToSqliteNoLock(cancellationToken);
- }
-
- // If the automatic migration to SQLite is stopped, we would not delete the old index data.
- // So check it every time.
- RemoveOldIndexFilesIfExist();
-
await InitializeFiltersNoLockAsync(cancellationToken).ConfigureAwait(false);
// Initialization succeeded.
@@ -120,93 +95,6 @@ public async Task InitializeAsync(CancellationToken cancellationToken)
}
}
- private void RemoveOldIndexFilesIfExist()
- {
- if (File.Exists(OldIndexFilePath))
- {
- try
- {
- File.Delete($"{OldImmatureIndexFilePath}.dig"); // No exception is thrown if file does not exist.
- File.Delete(OldImmatureIndexFilePath);
- File.Delete($"{OldIndexFilePath}.dig");
- File.Delete(OldIndexFilePath);
-
- Logger.LogInfo("Removed old index file data.");
- }
- catch (Exception ex)
- {
- Logger.LogDebug(ex);
- }
- }
- }
-
- private void MigrateToSqliteNoLock(CancellationToken cancel)
- {
- int i = 0;
-
- try
- {
- Logger.LogWarning("Migration of block filters to SQLite format is about to begin. Please wait a moment.");
-
- Stopwatch stopwatch = Stopwatch.StartNew();
-
- IndexStorage.Clear();
-
- List filters = new(capacity: 10_000);
- using (FileStream fs = File.Open(OldIndexFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
- using (BufferedStream bs = new(fs))
- using (StreamReader sr = new(bs))
- {
- while (true)
- {
- cancel.ThrowIfCancellationRequested();
-
- i++;
- string? line = sr.ReadLine();
-
- if (line is null)
- {
- break;
- }
-
- // Starting filter is already added at this point.
- if (i == 1)
- {
- continue;
- }
-
- filters.Add(line);
-
- if (i % 10_000 == 0)
- {
- IndexStorage.BulkAppend(filters);
- filters.Clear();
- }
- }
- }
-
- IndexStorage.BulkAppend(filters);
-
- Logger.LogInfo($"Migration of {i} filters to SQLite was finished in {stopwatch.Elapsed} seconds.");
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (Exception ex)
- {
- Logger.LogError(ex);
-
- IndexStorage.Dispose();
-
- // Do not run migration code again if it fails.
- File.Delete(NewIndexFilePath);
- File.Delete(OldIndexFilePath);
-
- IndexStorage = CreateBlockFilterSqliteStorage();
- }
- }
-
/// Guarded by .
private Task InitializeFiltersNoLockAsync(CancellationToken cancellationToken)
{
diff --git a/WalletWasabi/Tor/Control/TorControlClientFactory.cs b/WalletWasabi/Tor/Control/TorControlClientFactory.cs
index c12e2f8dbd..77fdc903ba 100644
--- a/WalletWasabi/Tor/Control/TorControlClientFactory.cs
+++ b/WalletWasabi/Tor/Control/TorControlClientFactory.cs
@@ -78,7 +78,7 @@ internal async Task AuthSafeCookieOrThrowAsync(TorControlClien
{
byte[] nonceBytes = new byte[32];
Random.GetBytes(nonceBytes);
- string clientNonce = ByteHelpers.ToHex(nonceBytes);
+ string clientNonce = Convert.ToHexString(nonceBytes);
TorControlReply authChallengeReply = await controlClient.SendCommandAsync($"AUTHCHALLENGE SAFECOOKIE {clientNonce}\r\n", cancellationToken).ConfigureAwait(false);
@@ -107,8 +107,8 @@ internal async Task AuthSafeCookieOrThrowAsync(TorControlClien
string toHash = $"{cookieString}{clientNonce}{serverNonce}";
using HMACSHA256 hmacSha256 = new(ClientHmacKey);
- byte[] serverHash = hmacSha256.ComputeHash(ByteHelpers.FromHex(toHash));
- string serverHashStr = ByteHelpers.ToHex(serverHash);
+ byte[] serverHash = hmacSha256.ComputeHash(Convert.FromHexString(toHash));
+ string serverHashStr = Convert.ToHexString(serverHash);
Logger.LogTrace($"Authenticate using server hash: '{serverHashStr}'.");
TorControlReply authenticationReply = await controlClient.SendCommandAsync($"AUTHENTICATE {serverHashStr}\r\n", cancellationToken).ConfigureAwait(false);
diff --git a/WalletWasabi/Tor/Http/Helpers/HttpMessageHelper.cs b/WalletWasabi/Tor/Http/Helpers/HttpMessageHelper.cs
index bf313b129d..87ad52653c 100644
--- a/WalletWasabi/Tor/Http/Helpers/HttpMessageHelper.cs
+++ b/WalletWasabi/Tor/Http/Helpers/HttpMessageHelper.cs
@@ -40,7 +40,7 @@ public static async Task ReadStartLineAsync(Stream stream, CancellationT
// End of stream has been reached.
if (read == -1)
{
- Logger.LogTrace($"End of stream has been reached during reading HTTP start-line. Read bytes: '{ByteHelpers.ToHex(bab.ToArray())}'.");
+ Logger.LogTrace($"End of stream has been reached during reading HTTP start-line. Read bytes: '{Convert.ToHexString(bab.ToArray())}'.");
throw new TorConnectionReadException("HTTP start-line is incomplete. Tor circuit probably died.");
}
diff --git a/WalletWasabi/Tor/Socks5/Models/Bases/ByteArraySerializableBase.cs b/WalletWasabi/Tor/Socks5/Models/Bases/ByteArraySerializableBase.cs
index aa20116d65..d86e0c4b32 100644
--- a/WalletWasabi/Tor/Socks5/Models/Bases/ByteArraySerializableBase.cs
+++ b/WalletWasabi/Tor/Socks5/Models/Bases/ByteArraySerializableBase.cs
@@ -11,9 +11,9 @@ public string ToHex(bool xhhSyntax = false)
{
if (xhhSyntax)
{
- return $"X'{ByteHelpers.ToHex(ToBytes())}'";
+ return $"X'{Convert.ToHexString(ToBytes())}'";
}
- return ByteHelpers.ToHex(ToBytes());
+ return Convert.ToHexString(ToBytes());
}
public override string ToString()
diff --git a/WalletWasabi/Tor/Socks5/Models/Bases/OctetSerializableBase.cs b/WalletWasabi/Tor/Socks5/Models/Bases/OctetSerializableBase.cs
index 71face623b..d5671d76ec 100644
--- a/WalletWasabi/Tor/Socks5/Models/Bases/OctetSerializableBase.cs
+++ b/WalletWasabi/Tor/Socks5/Models/Bases/OctetSerializableBase.cs
@@ -1,4 +1,3 @@
-using WalletWasabi.Helpers;
using WalletWasabi.Tor.Socks5.Models.Interfaces;
namespace WalletWasabi.Tor.Socks5.Models.Bases;
@@ -15,9 +14,9 @@ public string ToHex(bool xhhSyntax = false)
{
if (xhhSyntax)
{
- return $"X'{ByteHelpers.ToHex(ToByte())}'";
+ return $"X'{ByteValue:X2}'";
}
- return ByteHelpers.ToHex(ToByte());
+ return $"{ByteValue:X2}";
}
public override string ToString()
diff --git a/WalletWasabi/Tor/Socks5/Models/Fields/ByteArrayFields/MethodsField.cs b/WalletWasabi/Tor/Socks5/Models/Fields/ByteArrayFields/MethodsField.cs
index 4ec0a2dc56..d07b877872 100644
--- a/WalletWasabi/Tor/Socks5/Models/Fields/ByteArrayFields/MethodsField.cs
+++ b/WalletWasabi/Tor/Socks5/Models/Fields/ByteArrayFields/MethodsField.cs
@@ -14,7 +14,7 @@ public MethodsField(byte[] bytes)
{
if (b != MethodField.NoAuthenticationRequired && b != MethodField.UsernamePassword)
{
- throw new FormatException($"Unrecognized authentication method: {ByteHelpers.ToHex(b)}.");
+ throw new FormatException($"Unrecognized authentication method: {b:X2}.");
}
}
diff --git a/WalletWasabi/Tor/TorProcessManager.cs b/WalletWasabi/Tor/TorProcessManager.cs
index c4b9897ed8..e3f6820024 100644
--- a/WalletWasabi/Tor/TorProcessManager.cs
+++ b/WalletWasabi/Tor/TorProcessManager.cs
@@ -4,7 +4,6 @@
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
-using WalletWasabi.Helpers;
using WalletWasabi.Logging;
using WalletWasabi.Microservices;
using WalletWasabi.Models;
@@ -455,7 +454,7 @@ internal virtual async Task InitTorControlAsync(CancellationTo
}
// Get cookie.
- string cookieString = ByteHelpers.ToHex(File.ReadAllBytes(Settings.CookieAuthFilePath));
+ string cookieString = Convert.ToHexString(File.ReadAllBytes(Settings.CookieAuthFilePath));
// Authenticate.
TorControlClientFactory factory = new();
diff --git a/WalletWasabi/Tor/TorSettings.cs b/WalletWasabi/Tor/TorSettings.cs
index eb458730a6..75d2205494 100644
--- a/WalletWasabi/Tor/TorSettings.cs
+++ b/WalletWasabi/Tor/TorSettings.cs
@@ -173,7 +173,11 @@ public string GetCmdArguments()
$"--CookieAuthFile \"{CookieAuthFilePath}\"",
$"--DataDirectory \"{TorDataDir}\"",
$"--GeoIPFile \"{GeoIpPath}\"",
- $"--GeoIPv6File \"{GeoIp6Path}\""
+ $"--GeoIPv6File \"{GeoIp6Path}\"",
+ $"--NumEntryGuards 3",
+ $"--NumPrimaryGuards 3",
+ $"--ConfluxEnabled 1",
+ $"--ConfluxClientUX throughput"
];
if (useBridges)
diff --git a/WalletWasabi/WabiSabi/Backend/MiningFeeRateEstimator.cs b/WalletWasabi/WabiSabi/Backend/MiningFeeRateEstimator.cs
index 03405ee5ee..766c689300 100644
--- a/WalletWasabi/WabiSabi/Backend/MiningFeeRateEstimator.cs
+++ b/WalletWasabi/WabiSabi/Backend/MiningFeeRateEstimator.cs
@@ -18,6 +18,8 @@ public MiningFeeRateEstimator(WabiSabiConfig config, IRPCClient rpc)
protected WabiSabiConfig Config { get; }
protected IRPCClient Rpc { get; }
+ public virtual FeeRate GetRoundMinimumFeeRate => FeeRate.Zero;
+
public virtual async Task GetRoundFeeRateAsync(CancellationToken cancellationToken)
{
var feeRate = (await Rpc.EstimateConservativeSmartFeeAsync((int)Config.ConfirmationTarget, cancellationToken).ConfigureAwait(false)).FeeRate;
diff --git a/WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs b/WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
index 689392f66d..492b188e67 100644
--- a/WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
+++ b/WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
@@ -6,6 +6,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -168,7 +169,7 @@ private async Task StepInputRegistrationPhaseAsync(CancellationToken cancel)
{
// This should never happen.
CoinVerifier.VerifierAuditArchiver.LogException(round.Id, "AliceException", exc);
- Logger.LogDiscord(LogLevel.Error, $"AliceException at round {round.Id}: {exc.Message}", normalLogLevel: LogLevel.Error);
+ Logger.LogDiscord("main", LogLevel.Error, $"AliceException at round {round.Id}: {exc.Message}", normalLogLevel: LogLevel.Error);
throw;
}
}
@@ -405,7 +406,14 @@ private async Task StepTransactionSigningPhaseAsync(CancellationToken cancellati
await Rpc.SendRawTransactionAsync(coinjoin, cancellationToken).ConfigureAwait(false);
EndRound(round, EndRoundState.TransactionBroadcasted);
round.LogInfo($"Successfully broadcast the coinjoin: {coinjoin.GetHash()}.");
- round.LogInfo($"Coinjoin summary {coinjoin.GetHash()}, {coinjoin.Inputs.Count}, {coinjoin.Outputs.Count}, {coinjoin.GetAnonScore():F2}, {state.Inputs.Select(x => x.Amount).Sum().Satoshi}, {coinjoin.Outputs.Select(x => x.Value).Sum().Satoshi}, {round.ExpectedCoordinationFee.Satoshi}, {round.CoordinationFee.Satoshi}, {feeRate.SatoshiPerByte}");
+
+ round.LogInfo($"Coinjoin summary {coinjoin.GetHash()}, {coinjoin.Inputs.Count}, {coinjoin.Outputs.Count}, {coinjoin.GetAnonSet():F2}, {state.Inputs.Select(x => x.Amount).Sum().Satoshi}, {coinjoin.Outputs.Select(x => x.Value).Sum().Satoshi}, {round.ExpectedCoordinationFee.Satoshi}, {round.CoordinationFee.Satoshi}, {feeRate.SatoshiPerByte}");
+ Logger.LogDiscord(
+ "coinjoin",
+ LogLevel.Information,
+ $"New [coinjoin](https://mempool.space/tx/{coinjoin.GetHash()})! 🥳 I/O: **{coinjoin.Inputs.Count}/{coinjoin.Outputs.Count}** Income: **{round.CoordinationFee.ToUnit(MoneyUnit.BTC).ToString("0.0000 0000", CultureInfo.InvariantCulture)} BTC**",
+ rawMessage: true
+ );
var coordinatorScriptPubKey = Config.GetNextCleanCoordinatorScript();
if (round.CoordinatorScript == coordinatorScriptPubKey)
@@ -566,60 +574,6 @@ private async Task CreateRoundsAsync(CancellationToken cancellationToken)
{
FeeRate? feeRate = null;
- // Have rounds to split the volume around minimum input counts if load balance is required.
- // Only do things if the load balancer compatibility is configured.
- if (Config.WW200CompatibleLoadBalancing)
- {
- foreach (var round in Rounds.Where(x =>
- x.Phase == Phase.InputRegistration
- && x is not BlameRound
- && !x.IsInputRegistrationEnded(x.Parameters.MaxInputCountByRound)
- && x.InputCount >= Config.RoundDestroyerThreshold).ToArray())
- {
- feeRate = await MiningFeeRateEstimator.GetRoundFeeRateAsync(cancellationToken).ConfigureAwait(false);
-
- var allInputs = round.Alices.Select(y => y.Coin.Amount).OrderBy(x => x).ToArray();
-
- // 0.75 to bias towards larger numbers as larger input owners often have many smaller inputs too.
- var smallSuggestion = allInputs.Skip((int)(allInputs.Length * Config.WW200CompatibleLoadBalancingInputSplit)).First();
- var largeSuggestion = MaxSuggestedAmountProvider.AbsoluteMaximumInput;
-
- var roundWithoutThis = Rounds.Except(new[] { round });
- RoundParameters parameters = RoundParameterFactory.CreateRoundParameter(feeRate, largeSuggestion);
- Round? foundLargeRound = roundWithoutThis
- .FirstOrDefault(x =>
- x.Phase == Phase.InputRegistration
- && x is not BlameRound
- && !x.IsInputRegistrationEnded(round.Parameters.MaxInputCountByRound)
- && x.Parameters.MaxSuggestedAmount >= allInputs.Max()
- && x.InputRegistrationTimeFrame.Remaining > TimeSpan.FromSeconds(60));
- var largeRound = foundLargeRound ?? TryMineRound(parameters, roundWithoutThis.ToArray());
-
- if (largeRound is not null)
- {
- parameters = RoundParameterFactory.CreateRoundParameter(feeRate, smallSuggestion);
- var smallRound = TryMineRound(parameters, roundWithoutThis.Concat(new[] { largeRound }).ToArray());
-
- // If creation is successful, only then destroy the round.
- if (smallRound is not null)
- {
- AddRound(largeRound);
- AddRound(smallRound);
-
- if (foundLargeRound is null)
- {
- largeRound.LogInfo($"Mined round with parameters: {nameof(largeRound.Parameters.MaxSuggestedAmount)}:'{largeRound.Parameters.MaxSuggestedAmount}' BTC.");
- }
- smallRound.LogInfo($"Mined round with parameters: {nameof(smallRound.Parameters.MaxSuggestedAmount)}:'{smallRound.Parameters.MaxSuggestedAmount}' BTC.");
-
- // If it can't create the large round, then don't abort.
- EndRound(round, EndRoundState.AbortedLoadBalancing);
- Logger.LogInfo($"Destroyed round with {allInputs.Length} inputs. Threshold: {Config.RoundDestroyerThreshold}");
- }
- }
- }
- }
-
bool IsRoundRegistrable(TimeSpan inputRegRemainingTime, TimeSpan createNewRoundBeforeInputRegEnd)
{
var remainingTime = inputRegRemainingTime < TimeSpan.Zero ? TimeSpan.Zero : inputRegRemainingTime;
@@ -650,43 +604,6 @@ protected virtual Round CreateRoundObject(FeeRate feeRate)
return round;
}
- private Round? TryMineRound(RoundParameters parameters, Round[] rounds)
- {
- // Huge HACK to keep it compatible with WW2.0.0 client version, which's
- // round preference is based on the ordering of ToImmutableDictionary.
- // Add round until ToImmutableDictionary orders it to be the first round
- // so old clients will prefer that one.
- IOrderedEnumerable? orderedRounds;
- Round r;
- var before = DateTimeOffset.UtcNow;
- var times = 0;
- var maxCycleTimes = 300;
- do
- {
- var roundsCopy = rounds.ToList();
- r = new Round(parameters, SecureRandom.Instance);
- roundsCopy.Add(r);
- orderedRounds = roundsCopy
- .Where(x => x.Phase == Phase.InputRegistration && x is not BlameRound && !x.IsInputRegistrationEnded(x.Parameters.MaxInputCountByRound))
- .OrderBy(x => x.Parameters.MaxSuggestedAmount)
- .ThenBy(x => x.InputCount);
- times++;
- }
- while (times <= maxCycleTimes && orderedRounds.ToImmutableDictionary(x => x.Id, x => x).First().Key != r.Id);
-
- Logger.LogDebug($"First ordered round creator did {times} cycles.");
-
- if (times > maxCycleTimes)
- {
- r.LogInfo("First ordered round creation too expensive. Skipping...");
- return null;
- }
- else
- {
- return r;
- }
- }
-
private void TimeoutRounds()
{
foreach (var expiredRound in Rounds.Where(
diff --git a/WalletWasabi/WabiSabi/Backend/Statistics/CoinJoinFeeRateStatStore.cs b/WalletWasabi/WabiSabi/Backend/Statistics/CoinJoinFeeRateStatStore.cs
index c96851a333..a713d673ce 100644
--- a/WalletWasabi/WabiSabi/Backend/Statistics/CoinJoinFeeRateStatStore.cs
+++ b/WalletWasabi/WabiSabi/Backend/Statistics/CoinJoinFeeRateStatStore.cs
@@ -14,16 +14,19 @@ namespace WalletWasabi.WabiSabi.Backend.Statistics;
public class CoinJoinFeeRateStatStore : PeriodicRunner
{
- public CoinJoinFeeRateStatStore(WabiSabiConfig config, IRPCClient rpc, IEnumerable feeRateStats)
+ private readonly FeeRate _minimumMiningFeeRate;
+
+ public CoinJoinFeeRateStatStore(WabiSabiConfig config, IRPCClient rpc, IEnumerable feeRateStats, FeeRate minimumMiningFeeRate)
: base(TimeSpan.FromMinutes(10))
{
Config = config;
Rpc = rpc;
+ _minimumMiningFeeRate = minimumMiningFeeRate;
CoinJoinFeeRateStats = new(feeRateStats.OrderBy(x => x.DateTimeOffset));
}
public CoinJoinFeeRateStatStore(WabiSabiConfig config, IRPCClient rpc)
- : this(config, rpc, Enumerable.Empty())
+ : this(config, rpc, Enumerable.Empty(), FeeRate.Zero)
{
}
@@ -76,6 +79,11 @@ private FeeRate GetMedian(TimeSpan timeFrame)
? new FeeRate((feeRates[feeRates.Length / 2].FeeRate.SatoshiPerByte + feeRates[(feeRates.Length / 2) - 1].FeeRate.SatoshiPerByte) / 2)
: feeRates[feeRates.Length / 2].FeeRate;
+ if (med < _minimumMiningFeeRate)
+ {
+ med = _minimumMiningFeeRate;
+ }
+
return med;
}
@@ -87,7 +95,7 @@ public CoinJoinFeeRateMedian[] GetDefaultMedians()
return DefaultMedians;
}
- public static CoinJoinFeeRateStatStore LoadFromFile(string filePath, WabiSabiConfig config, IRPCClient rpc)
+ public static CoinJoinFeeRateStatStore LoadFromFile(string filePath, WabiSabiConfig config, IRPCClient rpc, FeeRate minimumMiningFeeRate)
{
var from = DateTimeOffset.UtcNow - MaximumTimeToStore;
@@ -97,7 +105,7 @@ public static CoinJoinFeeRateStatStore LoadFromFile(string filePath, WabiSabiCon
.Select(x => CoinJoinFeeRateStat.FromLine(x))
.Where(x => x.DateTimeOffset >= from);
- var store = new CoinJoinFeeRateStatStore(config, rpc, stats);
+ var store = new CoinJoinFeeRateStatStore(config, rpc, stats, minimumMiningFeeRate);
return store;
}
diff --git a/WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs b/WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
index aaa110fd73..235136bd2f 100644
--- a/WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
+++ b/WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
@@ -184,14 +184,6 @@ public WabiSabiConfig() : base()
[JsonProperty(PropertyName = "RoundParallelization", DefaultValueHandling = DefaultValueHandling.Populate)]
public int RoundParallelization { get; set; } = 1;
- [DefaultValue(false)]
- [JsonProperty(PropertyName = "WW200CompatibleLoadBalancing", DefaultValueHandling = DefaultValueHandling.Populate)]
- public bool WW200CompatibleLoadBalancing { get; set; } = false;
-
- [DefaultValue(0.75)]
- [JsonProperty(PropertyName = "WW200CompatibleLoadBalancingInputSplit", DefaultValueHandling = DefaultValueHandling.Populate)]
- public double WW200CompatibleLoadBalancingInputSplit { get; set; } = 0.75;
-
[DefaultValue("CoinJoinCoordinatorIdentifier")]
[JsonProperty(PropertyName = "CoordinatorIdentifier", DefaultValueHandling = DefaultValueHandling.Populate)]
public string CoordinatorIdentifier { get; set; } = "CoinJoinCoordinatorIdentifier";
diff --git a/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelectionParameters.cs b/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelectionParameters.cs
index fbbc8e876c..a0865906fd 100644
--- a/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelectionParameters.cs
+++ b/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelectionParameters.cs
@@ -17,6 +17,7 @@ namespace WalletWasabi.WabiSabi.Client.CoinJoin.Client;
/// Useful statistics from the wallet
/// The random geneator to be used
public record CoinJoinCoinSelectionParameters(
+ int AnonScoreTarget,
FeeRate MiningFeeRate,
long MinInputAmount,
long CoinJoinLoss,
@@ -28,7 +29,7 @@ public record CoinJoinCoinSelectionParameters(
WasabiRandom Random)
{
// This paramter leads to drop every coin
- public static readonly CoinJoinCoinSelectionParameters Empty = new(FeeRate.Zero, 10000, 0, 0, 0, 0, new([], 0), new(10, 3.0, 0.01), SecureRandom.Instance);
+ public static readonly CoinJoinCoinSelectionParameters Empty = new(2, FeeRate.Zero, 10000, 0, 0, 0, 0, new([], 0), new(10, 3.0, 0.01), SecureRandom.Instance);
public bool IsCoinAboveAllowedLoss(ISmartCoin coin) => MiningFeeRate.GetFee(coin.ScriptType.EstimateInputVsize()).Satoshi / (double)coin.Amount.Satoshi > MaxCoinLossRate;
diff --git a/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelectionSettings.cs b/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelectionSettings.cs
index 0edf89064b..c40b1ba630 100644
--- a/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelectionSettings.cs
+++ b/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelectionSettings.cs
@@ -13,6 +13,9 @@ public CoinJoinCoinSelectionSettings()
// The coin selector will check and propose only candidates that has at least one low privacy coin
public bool ForceUsingLowPrivacyCoins { get; set; } = false;
+ // Allowed to use already private coins
+ public bool CanSelectPrivateCoins { get; set; } = false;
+
// Lowering this value will result to favor coin selections with less weighted anonymity loss (weighted privacy difference between coins)
public double WeightedAnonymityLossNormal { get; set; } = 3.0;
diff --git a/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelector.cs b/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelector.cs
index f9095bb639..d234b3e848 100644
--- a/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelector.cs
+++ b/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinJoinCoinSelector.cs
@@ -69,6 +69,7 @@ internal static int GetBucketIndex(SmartCoin coin)
private CoinJoinCoinSelectionParameters CreateParameters(UtxoSelectionParameters parameters, double maxWeightedAnonymityLoss, double maxValueLossRate)
{
CoinJoinCoinSelectionParameters res = new(
+ AnonScoreTarget: AnonScoreTarget,
MiningFeeRate: parameters.MiningFeeRate,
MinInputAmount: parameters.AllowedInputAmounts.Min.Satoshi,
CoinJoinLoss: (long)(.4 * parameters.MinAllowedOutputAmount.Satoshi + parameters.MiningFeeRate.GetFee(8 * Constants.P2wpkhOutputVirtualSize).Satoshi),
@@ -84,7 +85,7 @@ private CoinJoinCoinSelectionParameters CreateParameters(UtxoSelectionParameters
private CoinJoinCoinSelectionParameters _coinSelectionParameters = CoinJoinCoinSelectionParameters.Empty;
- private const int SufficeCandidateCountForCoinSelection = 150;
+ private const int SufficeCandidateCountForCoinSelection = 200;
public List SelectCoinsForRoundNew(UtxoSelectionParameters parameters, Money liquidityClue)
{
@@ -138,35 +139,29 @@ public List SelectCoinsForRoundNew(UtxoSelectionParameters parameters
_wallet.LogInfo($"Target InputCount is {inputCount} (Amount {walletAmount}, CoinRate {coinCountRate:F2} = {walletCoinCount} / {expectedCoinCount:F2})");
- int sensitivityDecrement = 2;
- int absLowestSensitivity = (int)-Math.Min(Math.Ceiling(walletMaxBallance), inputCount) - sensitivityDecrement;
+ // Always try to get candidates without private coins first
+ CollectCandidates(candidatesDict, selectableCoins, inputCount, walletMaxBallance, parameters);
- int maxDistance = forceUsingLowPrivacyCoins ? 30 : 20;
- double valueRateLossMul = 0.025 / maxDistance;
- double anonymityLossMul = (forceUsingLowPrivacyCoins ? 0.5 : 1.0) * Math.Max(AnonScoreTarget - 1.5, 4.0) / maxDistance;
- int totalCandidates = 0;
- for (int lowestSensitivity = 1; lowestSensitivity >= absLowestSensitivity && totalCandidates < SufficeCandidateCountForCoinSelection; lowestSensitivity -= sensitivityDecrement)
+ if (_settings.CanSelectPrivateCoins)
{
- int distanceIncrement = 1;
- for (int idx = 0; idx < maxDistance && totalCandidates < SufficeCandidateCountForCoinSelection; idx += distanceIncrement)
+ int candidateCountNonPrivate = candidatesDict.Sum(x => x.Value.Count);
+ if (candidateCountNonPrivate >= SufficeCandidateCountForCoinSelection)
{
- for (int jdx = 0; jdx < idx; jdx++)
- {
- double maxValueRateLoss = 0.001 + jdx * valueRateLossMul;
- double maxWeightedAnonymityLoss = 1.5 + (idx - jdx) * anonymityLossMul;
- _coinSelectionParameters = CreateParameters(parameters, maxWeightedAnonymityLoss, maxValueRateLoss);
- CollectCandidates(candidatesDict, selectableCoins, inputCount, lowestSensitivity);
- }
- int recountedCandidates = candidatesDict.Sum(x => x.Value.Count);
- if (recountedCandidates > 0 && recountedCandidates - totalCandidates < 2 && idx + 1 < maxDistance)
- {
- distanceIncrement = Math.Min(distanceIncrement + 1, maxDistance - idx - 1);
- }
- else
+ _wallet.LogInfo($"Using private coins is allowed, but already have enough candidates {candidateCountNonPrivate}, not using private coins.");
+ }
+ else
+ {
+ List selectablePrivateCoins = _privateCoins.Where(x => !_coinSelectionParameters.IsCoinAboveAllowedLoss(x)).ToList();
+ _wallet.LogInfo($"Using private coins is allowed, {selectablePrivateCoins.Count} coins found.");
+ if (selectablePrivateCoins.Count > 0)
{
- distanceIncrement = 1;
+ selectablePrivateCoins = selectablePrivateCoins.OrderBy(x => Math.Round(x.AnonymitySet, 3) * 1000 + x.Amount.Satoshi * amountScale).ToList();
+ // Simply adding to the end and retry
+ selectableCoins.AddRange(selectablePrivateCoins);
+ CollectCandidates(candidatesDict, selectableCoins, inputCount, walletMaxBallance, parameters);
+ int candidateCountPrivate = candidatesDict.Sum(x => x.Value.Count);
+ _wallet.LogInfo($"Changed the possible candidates from {candidateCountNonPrivate} to {candidateCountPrivate}.");
}
- totalCandidates = recountedCandidates;
}
}
@@ -185,6 +180,7 @@ public List SelectCoinsForRoundNew(UtxoSelectionParameters parameters
candidates.RemoveAt(idx + 1);
}
}
+ int unqiueCandidatesCount = candidates.Count;
// Now we need to choose
var bestScore = candidates[0].Score;
var bestLossScore = _comparer.GetLossScore(candidates[0]);
@@ -197,6 +193,8 @@ public List SelectCoinsForRoundNew(UtxoSelectionParameters parameters
break;
}
}
+ _wallet.LogInfo($"Created {unqiueCandidatesCount} candidates, kept the first {candidates.Count} with scores {bestScore} - {scoreLimit} to choose from.");
+
var finalCandidate = candidates.RandomElement(_random) ?? candidates[0];
return finalCandidate.Coins.ToShuffled(_random).ToList();
}
@@ -204,12 +202,54 @@ public List SelectCoinsForRoundNew(UtxoSelectionParameters parameters
return [];
}
- private void CollectCandidates(Dictionary> candidates, List selectableCoins, int inputCount, double lowestSensitivity)
+ private void CollectCandidates(Dictionary> candidates, List selectableCoins, int inputCount, double walletMaxBallance, UtxoSelectionParameters parameters)
+ {
+ int sensitivityDecrement = 2;
+ int absLowestSensitivity = (int)-Math.Min(Math.Ceiling(walletMaxBallance), inputCount) - sensitivityDecrement;
+
+ bool forceUsingLowPrivacyCoins = _settings.ForceUsingLowPrivacyCoins;
+ int maxDistance = forceUsingLowPrivacyCoins ? 30 : 20;
+ double valueRateLossMul = 0.025 / maxDistance;
+ double anonymityLossMul = (forceUsingLowPrivacyCoins ? 0.5 : 1.0) * Math.Max(AnonScoreTarget - 1.5, 4.0) / maxDistance;
+ int totalCandidates = candidates.Sum(x => x.Value.Count);
+ for (int lowestSensitivity = 1; lowestSensitivity >= absLowestSensitivity && totalCandidates < SufficeCandidateCountForCoinSelection; lowestSensitivity -= sensitivityDecrement)
+ {
+ int distanceIncrement = 1;
+ for (int idx = 0; idx < maxDistance && totalCandidates < SufficeCandidateCountForCoinSelection; idx += distanceIncrement)
+ {
+ for (int jdx = 0; jdx < idx; jdx++)
+ {
+ double maxValueRateLoss = 0.001 + jdx * valueRateLossMul;
+ double maxWeightedAnonymityLoss = 1.5 + (idx - jdx) * anonymityLossMul;
+ _coinSelectionParameters = CreateParameters(parameters, maxWeightedAnonymityLoss, maxValueRateLoss);
+ CollectCandidatesWithSensitivity(candidates, selectableCoins, inputCount, lowestSensitivity);
+ }
+ int recountedCandidates = candidates.Sum(x => x.Value.Count);
+ if (recountedCandidates > 0 && recountedCandidates - totalCandidates < 2 && idx + 1 < maxDistance)
+ {
+ distanceIncrement = Math.Min(distanceIncrement + 1, maxDistance - idx - 1);
+ }
+ else
+ {
+ distanceIncrement = 1;
+ }
+ totalCandidates = recountedCandidates;
+ }
+ }
+ }
+
+ private void CollectCandidatesWithSensitivity(Dictionary> candidates, List selectableCoins, int inputCount, double lowestSensitivity)
{
bool forceUsingLowPrivacyCoins = _settings.ForceUsingLowPrivacyCoins;
double coinCheck = SufficeCandidateCountForCoinSelection / (double)candidates.Count;
int triesPerStartingCoin = Math.Max(2, Math.Min((int)Math.Round(coinCheck), 6));
int maxCandidatesPerStartingCoin = Math.Max(3, Math.Min((int)Math.Round(coinCheck * 2), 20));
+ // If we have very few starting coins then we try to increase the allowed candidates per coin further
+ if (candidates.Count < 4)
+ {
+ maxCandidatesPerStartingCoin = Math.Max(maxCandidatesPerStartingCoin, (int)Math.Round(coinCheck));
+ }
+
// These are the starting candidates
foreach (var (coin, list) in candidates)
{
@@ -255,7 +295,7 @@ private List GetAnonContinuityList(List list, SmartCoin st
SmartCoin coin = list[idx];
sumAmount += coin.Amount.Satoshi;
sumVSize += coin.ScriptPubKey.EstimateInputVsize();
- sumAmountMulAnonScore += (coin.AnonymitySet - minimumAnonScore) * coin.Amount.Satoshi;
+ sumAmountMulAnonScore += CoinSelectionCandidate.GetCoinAnonymityWeight(coin, AnonScoreTarget, minimumAnonScore);
if (sumAmountMulAnonScore <= maxWeightedAnonymityLoss * sumAmount)
{
result.Add(coin);
diff --git a/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinSelectionCandidate.cs b/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinSelectionCandidate.cs
index bf1421c588..bdcf72acbc 100644
--- a/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinSelectionCandidate.cs
+++ b/WalletWasabi/WabiSabi/Client/CoinJoin/Client/CoinSelectionCandidate.cs
@@ -6,6 +6,7 @@
using System.Linq;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Extensions;
+using WalletWasabi.Helpers;
namespace WalletWasabi.WabiSabi.Client.CoinJoin.Client;
@@ -37,7 +38,7 @@ public CoinRemovalStatistics(SmartCoin coin, int coinCount, int transactionCount
public CoinSelectionCandidate(List coins, CoinJoinCoinSelectionParameters coinSelectionParameters)
{
- Coins = new(coins);
+ Coins = [.. coins];
RemovedCoins = [];
_coinSelectionParameters = coinSelectionParameters;
Refresh();
@@ -45,8 +46,8 @@ public CoinSelectionCandidate(List coins, CoinJoinCoinSelectionParame
public CoinSelectionCandidate(CoinSelectionCandidate src)
{
- Coins = new(src.Coins);
- RemovedCoins = new(src.RemovedCoins);
+ Coins = [.. src.Coins];
+ RemovedCoins = [.. src.RemovedCoins];
_coinSelectionParameters = src._coinSelectionParameters;
_amount = src._amount;
_vsize = src._vsize;
@@ -91,6 +92,14 @@ public bool Equals(CoinSelectionCandidate other)
return true;
}
+ public static double GetCoinAnonymityWeight(SmartCoin coin, int anonScoreTarget, double minAnonymityScore)
+ {
+ // Extra penalty for private coins, we allow to use private coins, but use when really needed
+ double modifier = (coin.IsPrivate(anonScoreTarget) ? PrivateCoinAnonymityPenalty : 0) - minAnonymityScore;
+ double res = (coin.AnonymitySet + modifier) * coin.Amount.Satoshi;
+ return res;
+ }
+
// Calculate some of the decision factors
[MemberNotNull(nameof(_amount))]
public void Refresh()
@@ -117,7 +126,7 @@ public void Refresh()
MinimumAnonymityCount++;
}
- _weightedAnonymitySet += coin.AnonymitySet * coin.Amount.Satoshi;
+ _weightedAnonymitySet += GetCoinAnonymityWeight(coin, _coinSelectionParameters.AnonScoreTarget, 0);
_vsize += coin.ScriptPubKey.EstimateInputVsize();
_transactions.AddValue(coin.TransactionId, 1);
@@ -287,7 +296,7 @@ private void RemoveCoin(SmartCoin coin)
}
_amount -= coin.Amount;
- _weightedAnonymitySet -= coin.AnonymitySet * coin.Amount.Satoshi;
+ _weightedAnonymitySet -= GetCoinAnonymityWeight(coin, _coinSelectionParameters.AnonScoreTarget, 0);
_vsize -= coin.ScriptPubKey.EstimateInputVsize();
_transactions.AddValue(coin.TransactionId, -1);
@@ -349,6 +358,8 @@ private void CalculateBucketScoreForRemovalStatistics(CoinRemovalStatistics stat
public bool GoodCandidate => AnonymityLoss <= _coinSelectionParameters.MaxWeightedAnonymityLoss && ValueLossRate <= _coinSelectionParameters.MaxValueLossRate;
+ private const double PrivateCoinAnonymityPenalty = 2;
+
private Money _amount;
public override Money Amount => _amount;
public override int CoinCount => Coins.Count;
diff --git a/WalletWasabi/WabiSabi/Client/CoinJoin/Manager/CoinJoinTrackerFactory.cs b/WalletWasabi/WabiSabi/Client/CoinJoin/Manager/CoinJoinTrackerFactory.cs
index 770c93bc7b..f4e4a0c1ba 100644
--- a/WalletWasabi/WabiSabi/Client/CoinJoin/Manager/CoinJoinTrackerFactory.cs
+++ b/WalletWasabi/WabiSabi/Client/CoinJoin/Manager/CoinJoinTrackerFactory.cs
@@ -52,6 +52,7 @@ public async Task CreateAndStartAsync(IWallet wallet, IWallet?
CoinJoinConfiguration,
LiquidityClueProvider,
feeRateMedianTimeFrame: wallet.FeeRateMedianTimeFrame,
+ safeMiningFeeRate: wallet.SafeMiningFeeRate,
skipFactors: wallet.CoinjoinSkipFactors,
doNotRegisterInLastMinuteTimeLimit: TimeSpan.FromMinutes(1));
diff --git a/WalletWasabi/WabiSabi/Client/RoundStateAwaiters/RoundStateHolder.cs b/WalletWasabi/WabiSabi/Client/RoundStateAwaiters/RoundStateHolder.cs
index 843a388b31..d81cb1a3fc 100644
--- a/WalletWasabi/WabiSabi/Client/RoundStateAwaiters/RoundStateHolder.cs
+++ b/WalletWasabi/WabiSabi/Client/RoundStateAwaiters/RoundStateHolder.cs
@@ -12,7 +12,7 @@ namespace WalletWasabi.WabiSabi.Client.RoundStateAwaiters;
public class RoundStateHolder
{
- public RoundStateHolder(RoundState roundState, string[] allowedCoordinatorIdentifiers, bool verify)
+ public RoundStateHolder(RoundState roundState, string[] allowedCoordinatorIdentifiers, bool verify, DateTimeOffset minInputRegistrationStart)
{
RoundState = roundState;
Confidence = 0;
@@ -21,6 +21,11 @@ public RoundStateHolder(RoundState roundState, string[] allowedCoordinatorIdenti
_inputCount = -1;
_exception = null;
_allowedCoordinatorIdentifiers = allowedCoordinatorIdentifiers;
+
+ if (verify && roundState.InputRegistrationStart <= minInputRegistrationStart)
+ {
+ Exception = new CoinJoinClientException(CoinjoinError.TamperedRoundState, $"Registration time is earlier than should be {roundState.Id}.");
+ }
VerifyAndSet(roundState, false, verify);
}
diff --git a/WalletWasabi/WabiSabi/Client/RoundStateAwaiters/RoundStateUpdater.cs b/WalletWasabi/WabiSabi/Client/RoundStateAwaiters/RoundStateUpdater.cs
index 2dabc0332f..28260e50d5 100644
--- a/WalletWasabi/WabiSabi/Client/RoundStateAwaiters/RoundStateUpdater.cs
+++ b/WalletWasabi/WabiSabi/Client/RoundStateAwaiters/RoundStateUpdater.cs
@@ -9,6 +9,8 @@
using WalletWasabi.Bases;
using WalletWasabi.WabiSabi.Backend.PostRequests;
using WalletWasabi.WabiSabi.Backend.Rounds;
+using WalletWasabi.WabiSabi.Client.CoinJoin.Client;
+using WalletWasabi.WabiSabi.Client.StatusChangedEvents;
using WalletWasabi.WabiSabi.Models;
namespace WalletWasabi.WabiSabi.Client.RoundStateAwaiters;
@@ -85,9 +87,26 @@ protected override async Task ActionAsync(CancellationToken cancellationToken)
CoinJoinFeeRateMedians = response.CoinJoinFeeRateMedians.ToDictionary(a => a.TimeFrame, a => a.MedianFeeRate);
+ var timeLimitFromLastSuccessfulRequestTime = LastSuccessfulRequestTime > DateTimeOffset.UnixEpoch ? LastSuccessfulRequestTime - TimeSpan.FromMinutes(1) : LastSuccessfulRequestTime;
+ DateTimeOffset minInputRegistrationStart = RoundStates.Values.Select(x => x.RoundState.InputRegistrationStart).Append(timeLimitFromLastSuccessfulRequestTime).Max();
// Don't use ToImmutable dictionary, because that ruins the original order and makes the server unable to suggest a round preference.
// ToDo: ToDictionary doesn't guarantee the order by design so .NET team might change this out of our feet, so there's room for improvement here.
- RoundStates = response.RoundStates.Select(rs => CheckAndMergeRoundState(rs, requestFromCheckpointList)).ToDictionary(x => x.RoundState.Id, x => x);
+ var newRoundStates = response.RoundStates.Select(rs => CheckAndMergeRoundState(rs, requestFromCheckpointList, minInputRegistrationStart)).ToDictionary(x => x.RoundState.Id, x => x);
+
+ if (_verifyRoundState)
+ {
+ var actives = newRoundStates.Values.Where(x => x.RoundState.Phase != Phase.Ended && !x.RoundState.IsBlame).ToList();
+ if (actives.Count > 4)
+ {
+ // Suspiciously lot active rounds
+ foreach (var roundHolder in actives)
+ {
+ roundHolder.Exception = new CoinJoinClientException(CoinjoinError.TamperedRoundState, $"Too many active rounds found {roundHolder.RoundState.Id}.");
+ }
+ }
+ }
+
+ RoundStates = newRoundStates;
lock (AwaitersLock)
{
@@ -103,11 +122,11 @@ protected override async Task ActionAsync(CancellationToken cancellationToken)
_waitSlowRequestMode = TimeSpan.FromMilliseconds(_random.GetInt(2 * 60000, 5 * 60000));
}
- private RoundStateHolder CheckAndMergeRoundState(RoundState rs, Dictionary requestFromCheckpointList)
+ private RoundStateHolder CheckAndMergeRoundState(RoundState rs, Dictionary requestFromCheckpointList, DateTimeOffset minInputRegistrationStart)
{
if (!RoundStates.TryGetValue(rs.Id, out RoundStateHolder? rsh))
{
- return new(rs, _allowedCoordinatorIdentifiers, _verifyRoundState);
+ return new(rs, _allowedCoordinatorIdentifiers, _verifyRoundState, minInputRegistrationStart);
}
rsh.VerifyAndSet(rs, requestFromCheckpointList.ContainsKey(rs.Id), _verifyRoundState);
diff --git a/WalletWasabi/WabiSabi/Crypto/Serialization/GroupElementJsonConverter.cs b/WalletWasabi/WabiSabi/Crypto/Serialization/GroupElementJsonConverter.cs
index 570d3a9423..8c1211520b 100644
--- a/WalletWasabi/WabiSabi/Crypto/Serialization/GroupElementJsonConverter.cs
+++ b/WalletWasabi/WabiSabi/Crypto/Serialization/GroupElementJsonConverter.cs
@@ -1,6 +1,5 @@
using Newtonsoft.Json;
using WabiSabi.Crypto.Groups;
-using WalletWasabi.Helpers;
namespace WalletWasabi.WabiSabi.Crypto.Serialization;
@@ -11,7 +10,7 @@ public class GroupElementJsonConverter : JsonConverter
{
if (reader.Value is string serialized)
{
- return GroupElement.FromBytes(ByteHelpers.FromHex(serialized));
+ return GroupElement.FromBytes(Convert.FromHexString(serialized));
}
throw new ArgumentException($"No valid serialized {nameof(GroupElement)} passed.");
}
@@ -21,7 +20,7 @@ public override void WriteJson(JsonWriter writer, GroupElement? value, JsonSeria
{
if (value is { } ge)
{
- writer.WriteValue(ByteHelpers.ToHex(ge.ToBytes()));
+ writer.WriteValue(Convert.ToHexString(ge.ToBytes()));
return;
}
throw new ArgumentException($"No valid {nameof(GroupElement)}.", nameof(value));
diff --git a/WalletWasabi/WabiSabi/Crypto/Serialization/ScalarJsonConverter.cs b/WalletWasabi/WabiSabi/Crypto/Serialization/ScalarJsonConverter.cs
index 22cce10ccb..2aed6a3af4 100644
--- a/WalletWasabi/WabiSabi/Crypto/Serialization/ScalarJsonConverter.cs
+++ b/WalletWasabi/WabiSabi/Crypto/Serialization/ScalarJsonConverter.cs
@@ -11,7 +11,7 @@ public override Scalar ReadJson(JsonReader reader, Type objectType, Scalar exist
{
if (reader.Value is string serialized)
{
- return new Scalar(ByteHelpers.FromHex(serialized));
+ return new Scalar(Convert.FromHexString(serialized));
}
throw new ArgumentException($"No valid serialized {nameof(Scalar)} passed.");
}
@@ -19,6 +19,6 @@ public override Scalar ReadJson(JsonReader reader, Type objectType, Scalar exist
///
public override void WriteJson(JsonWriter writer, Scalar scalar, JsonSerializer serializer)
{
- writer.WriteValue(ByteHelpers.ToHex(scalar.ToBytes()));
+ writer.WriteValue(Convert.ToHexString(scalar.ToBytes()));
}
}
diff --git a/WalletWasabi/WabiSabi/Models/Serialization/OwnershipProofJsonConverter.cs b/WalletWasabi/WabiSabi/Models/Serialization/OwnershipProofJsonConverter.cs
index 1f00e767f1..a394069f11 100644
--- a/WalletWasabi/WabiSabi/Models/Serialization/OwnershipProofJsonConverter.cs
+++ b/WalletWasabi/WabiSabi/Models/Serialization/OwnershipProofJsonConverter.cs
@@ -12,7 +12,7 @@ public class OwnershipProofJsonConverter : JsonConverter
{
if (reader.Value is string serialized)
{
- return OwnershipProof.FromBytes(ByteHelpers.FromHex(serialized));
+ return OwnershipProof.FromBytes(Convert.FromHexString(serialized));
}
throw new ArgumentException($"No valid serialized {nameof(OwnershipProof)} passed.");
}
@@ -21,6 +21,6 @@ public class OwnershipProofJsonConverter : JsonConverter
public override void WriteJson(JsonWriter writer, OwnershipProof? value, JsonSerializer serializer)
{
var bytes = value.ToBytes();
- writer.WriteValue(ByteHelpers.ToHex(bytes));
+ writer.WriteValue(Convert.ToHexString(bytes));
}
}
diff --git a/WalletWasabi/WabiSabi/Models/Serialization/WitScriptJsonConverter.cs b/WalletWasabi/WabiSabi/Models/Serialization/WitScriptJsonConverter.cs
index 344949357a..4ca3afc556 100644
--- a/WalletWasabi/WabiSabi/Models/Serialization/WitScriptJsonConverter.cs
+++ b/WalletWasabi/WabiSabi/Models/Serialization/WitScriptJsonConverter.cs
@@ -1,6 +1,5 @@
using NBitcoin;
using Newtonsoft.Json;
-using WalletWasabi.Helpers;
namespace WalletWasabi.WabiSabi.Models.Serialization;
@@ -11,7 +10,7 @@ public class WitScriptJsonConverter : JsonConverter
{
if (reader.Value is string serialized)
{
- return new WitScript(ByteHelpers.FromHex(serialized));
+ return new WitScript(Convert.FromHexString(serialized));
}
throw new ArgumentException($"No valid serialized {nameof(WitScript)} passed.");
}
@@ -20,6 +19,6 @@ public class WitScriptJsonConverter : JsonConverter
public override void WriteJson(JsonWriter writer, WitScript? value, JsonSerializer serializer)
{
var bytes = value?.ToBytes() ?? throw new ArgumentNullException(nameof(value));
- writer.WriteValue(ByteHelpers.ToHex(bytes));
+ writer.WriteValue(Convert.ToHexString(bytes));
}
}
diff --git a/WalletWasabi/WabiSabi/Recommendation/DenominationFactory.cs b/WalletWasabi/WabiSabi/Recommendation/DenominationFactory.cs
index f8822453fd..f7772806d8 100644
--- a/WalletWasabi/WabiSabi/Recommendation/DenominationFactory.cs
+++ b/WalletWasabi/WabiSabi/Recommendation/DenominationFactory.cs
@@ -86,8 +86,9 @@ public bool IsValidDenomination(IList denoms, IList inputEffective
}
var maxInput = inputEffectiveValues.Max();
+ // Now we allow denom above the biggest input to fight against the coin fragmentation
// There is no garantee that denoms[^1] <= inputEffectiveValues.Min(), that's completely valid!
- if (denoms[0] > maxInput || denoms[^1] < MinAllowedOutputAmount)
+ if (denoms[0] > 3 * maxInput || denoms[^1] < MinAllowedOutputAmount)
{
return false;
}
diff --git a/WalletWasabi/WabiSabi/WabiSabiCoordinator.cs b/WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
index 7393044906..3f4cd4149a 100644
--- a/WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
+++ b/WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
@@ -34,7 +34,7 @@ public WabiSabiCoordinator(CoordinatorParameters parameters, IRPCClient rpc, ICo
CoinVerifier = coinVerifier;
CoinJoinTransactionArchiver transactionArchiver = new(Path.Combine(parameters.CoordinatorDataDir, "CoinJoinTransactions"));
- CoinJoinFeeRateStatStore = CoinJoinFeeRateStatStore.LoadFromFile(parameters.CoinJoinFeeRateStatStoreFilePath, Config, rpc);
+ CoinJoinFeeRateStatStore = CoinJoinFeeRateStatStore.LoadFromFile(parameters.CoinJoinFeeRateStatStoreFilePath, Config, rpc, miningFeeRateEstimator?.GetRoundMinimumFeeRate ?? FeeRate.Zero);
IoHelpers.EnsureContainingDirectoryExists(Parameters.CoinJoinFeeRateStatStoreFilePath);
CoinJoinFeeRateStatStore.NewStat += FeeRateStatStore_NewStat;
diff --git a/WalletWasabi/WalletWasabi.csproj b/WalletWasabi/WalletWasabi.csproj
index 4bbba5afa4..41faa33aef 100644
--- a/WalletWasabi/WalletWasabi.csproj
+++ b/WalletWasabi/WalletWasabi.csproj
@@ -33,11 +33,11 @@
+
-
diff --git a/WalletWasabi/Wallets/P2PBlockProvider.cs b/WalletWasabi/Wallets/P2PBlockProvider.cs
index 26a5db319e..38da4dc3ba 100644
--- a/WalletWasabi/Wallets/P2PBlockProvider.cs
+++ b/WalletWasabi/Wallets/P2PBlockProvider.cs
@@ -43,15 +43,7 @@ public async Task TryGetBlockWithSourceDataAsync(uint256 block
{
Node? node = sourceRequest.Node;
- if (node is null)
- {
- node = await P2PNodesManager.GetNodeAsync(cancellationToken).ConfigureAwait(false);
-
- if (node is null || !node.IsConnected)
- {
- return new P2pBlockResponse(Block: null, new P2pSourceData(P2pSourceDataStatusCode.NoPeerAvailable, Node: null, P2PNodesManager.ConnectedNodesCount));
- }
- }
+ node ??= await P2PNodesManager.GetNodeAsync(cancellationToken).ConfigureAwait(false);
double timeout = sourceRequest.Timeout ?? P2PNodesManager.GetCurrentTimeout();
@@ -99,5 +91,9 @@ public async Task TryGetBlockWithSourceDataAsync(uint256 block
return new P2pBlockResponse(Block: null, new P2pSourceData(P2pSourceDataStatusCode.Failure, node, connectedNodes));
}
}
+ finally
+ {
+ P2PNodesManager.TryReleaseNode(node);
+ }
}
}
diff --git a/WalletWasabi/Wallets/P2PNodesManager.cs b/WalletWasabi/Wallets/P2PNodesManager.cs
index 497b390cb9..f4e4165a9d 100644
--- a/WalletWasabi/Wallets/P2PNodesManager.cs
+++ b/WalletWasabi/Wallets/P2PNodesManager.cs
@@ -1,11 +1,15 @@
using NBitcoin;
using NBitcoin.Protocol;
+using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using System.Xml.Linq;
using WabiSabi.Crypto.Randomness;
using WalletWasabi.Extensions;
using WalletWasabi.Helpers;
using WalletWasabi.Logging;
+using WalletWasabi.Tor.Socks5.Pool.Circuits;
namespace WalletWasabi.Wallets;
@@ -24,20 +28,21 @@ public P2PNodesManager(Network network, NodesGroup nodes, bool isTorEnabled)
private int NodeTimeouts { get; set; }
public uint ConnectedNodesCount => (uint)Nodes.ConnectedNodes.Count;
- public async Task GetNodeAsync(CancellationToken cancellationToken)
+ private readonly HashSet _nodesInUse = new();
+
+ public async Task GetNodeAsync(CancellationToken cancellationToken)
{
do
{
if (Nodes.ConnectedNodes.Count > 0)
{
- var node = Nodes.ConnectedNodes.RandomElement(SecureRandom.Instance);
+ var node = Nodes.ConnectedNodes.Where(n => !_nodesInUse.Contains(n)).RandomElement(SecureRandom.Instance);
if (node is not null && node.IsConnected)
{
+ _nodesInUse.Add(node);
return node;
}
-
- Logger.LogTrace($"Selected node is null or disconnected.");
}
await Task.Delay(TimeSpan.FromMilliseconds(50), cancellationToken).ConfigureAwait(false);
@@ -61,6 +66,16 @@ public void DisconnectNode(Node node, string reason)
node.DisconnectAsync(reason);
}
+ public bool TryReleaseNode(Node? node)
+ {
+ if (node is null)
+ {
+ return false;
+ }
+
+ return _nodesInUse.Remove(node);
+ }
+
public double GetCurrentTimeout()
{
// More permissive timeout if few nodes are connected to avoid exhaustion.
diff --git a/WalletWasabi/packages.lock.json b/WalletWasabi/packages.lock.json
index b4d9a05f14..0eaaf2942a 100644
--- a/WalletWasabi/packages.lock.json
+++ b/WalletWasabi/packages.lock.json
@@ -4,11 +4,11 @@
"net8.0": {
"Microsoft.AspNetCore.WebUtilities": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "z1SXKg5Bk02VmrrOab1TO2yxkZIfL4RyrS+yCpwxcLTqJwImYhEttz3LYbl1gQebkAAvx2Fm4NVXmopxXeLZgw==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "fB3ikXAlz6yQuy029zDAS3J4qW3o6HQYL+kqsTjhiog1JwgpfkRTELCTGxMv7fL6VljFtfNJIQ/2684soCuI9A==",
"dependencies": {
- "Microsoft.Net.Http.Headers": "8.0.0",
+ "Microsoft.Net.Http.Headers": "8.0.19",
"System.IO.Pipelines": "8.0.0"
}
},
@@ -20,11 +20,11 @@
},
"Microsoft.Data.Sqlite": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "H+iC5IvkCCKSNHXzL3JARvDn7VpkvuJM91KVB89sKjeTF/KX/BocNNh93ZJtX5MCQKb/z4yVKgkU2sVIq+xKfg==",
+ "requested": "[8.0.19, )",
+ "resolved": "8.0.19",
+ "contentHash": "GcYP5qUdpnF3FPoVZ6EewQ7EESRWuX79pTBYxRo/KCCiz9HTDtTka0FH+h3fUGJqk21nc0Q9BApThywO1enFaw==",
"dependencies": {
- "Microsoft.Data.Sqlite.Core": "8.0.0",
+ "Microsoft.Data.Sqlite.Core": "8.0.19",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.6"
}
},
@@ -39,29 +39,29 @@
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "AG7HWwVRdCHlaA++1oKDxLsXIBxmDpMPb3VoyOoAghEWnkUvEAdYQUwnV4jJbAaa/nMYNiEh5ByoLauZBEiovg==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "nHwq9aPBdBPYXPti6wYEEfgXddfBrYC+CQLn+qISiwQq5tpfaqDZSKOJNxoe9rfQxGf1c+2wC/qWFe1QYJPYqw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0"
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2"
}
},
"Microsoft.Extensions.Http": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "kDYeKJUzh0qeg/AI+nSr3ffthmXYQTEb0nS9qRC7YhSbbuN4M4NPbaB77AJwtkTnCV9XZ7qYj3dkZaNcyl73EA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics": "8.0.0",
- "Microsoft.Extensions.Logging": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics": "8.0.1",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Win32.SystemEvents": {
@@ -72,9 +72,9 @@
},
"NBitcoin": {
"type": "Direct",
- "requested": "[7.0.42.2, )",
- "resolved": "7.0.42.2",
- "contentHash": "U9kvuVxKJ/xZs0ttF0ddVbkTLMZogWejYLYysuNz1n0MfjxR3diOnN2lE9pulgVclIieRRMOgZmIDB2MASIqxA==",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "29o3gYqYehyelNs54jbvcGfOvmyx9Gr1SEN/WDqky54qpxB2U+SCs0k4ppihr5h5Sbf+NwyrHrrjiYqmIoMycQ==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
"Newtonsoft.Json": "13.0.1"
@@ -101,9 +101,9 @@
},
"System.Text.Json": {
"type": "Direct",
- "requested": "[8.0.5, )",
- "resolved": "8.0.5",
- "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg=="
+ "requested": "[8.0.6, )",
+ "resolved": "8.0.6",
+ "contentHash": "BvSpVBsVN9b+Y+wONbvJOHd1HjXQf33+XiC28ZMOwRsYb42mz3Q8YHnpTSwpwJLqYCMqM+0UUVC3V+pi25XfkQ=="
},
"WabiSabi": {
"type": "Direct",
@@ -126,8 +126,8 @@
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "pujbzfszX7jAl7oTbHhqx7pxd9jibeyHHl8zy1gd55XMaKWjDtc5XhhNYwQnrwWYCInNdVoArbaaAvLgW7TwuA==",
+ "resolved": "8.0.19",
+ "contentHash": "ugQbXR+SwaFHXkfMW+Q6Dn9VSQn6uUoaFp49Zqe+EQGDNMb8dviFCratqnRiBXZKAqt2aFRsV+Cj5gqcTWU/dA==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.6"
}
@@ -172,22 +172,21 @@
},
"Microsoft.Extensions.Diagnostics": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==",
+ "resolved": "8.0.1",
+ "contentHash": "doVPCUUCY7c6LhBsEfiy3W1bvS7Mi6LkfQMS8nlC22jZWNxBv8VO8bdfeyvpYFst6Kxqk7HBC6lytmEoBssvSQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
}
},
"Microsoft.Extensions.Diagnostics.Abstractions": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==",
+ "resolved": "8.0.1",
+ "contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "System.Diagnostics.DiagnosticSource": "8.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
}
},
"Microsoft.Extensions.FileProviders.Abstractions": {
@@ -259,8 +258,8 @@
},
"Microsoft.Net.Http.Headers": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "YlHqL8oWBX3H1LmdKUOxEMW8cVD8nUACEnE2Fu3Ze4k7mYf8yJ1o/uLqoequQV0GDupXyCBEzYhn7Zxdz7pqYQ==",
+ "resolved": "8.0.19",
+ "contentHash": "f2hSRVq5rR97YlfGcScVMXJvQpNpbbpnZjwsZ4kmN5/T3xk9DBVt1SPZDJIPrp/sSfdjz8aQtD8jKLXHyoHVng==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
@@ -270,11 +269,6 @@
"resolved": "3.1.4",
"contentHash": "23N1DCusSRCx1hoNiIMl3JnMZrdY78a/WcsiN1LIAg6sq8MiC7mszDiUgHKD6txm+m9PxJBigBLH7MPBQCRCDQ=="
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.6",
@@ -305,11 +299,6 @@
"SQLitePCLRaw.core": "2.1.6"
}
},
- "System.Diagnostics.DiagnosticSource": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ=="
- },
"System.Interactive.Async": {
"type": "Transitive",
"resolved": "6.0.1",
@@ -339,10 +328,11 @@
"gingercommon": {
"type": "Project",
"dependencies": {
- "Microsoft.Extensions.Http": "[8.0.0, )",
+ "Microsoft.Extensions.Http": "[8.0.1, )",
"Microsoft.Extensions.Logging.Console": "[8.0.1, )",
"Microsoft.Extensions.Logging.Debug": "[8.0.1, )",
- "NBitcoin": "[7.0.42.2, )"
+ "NBitcoin": "[9.0.0, )",
+ "Newtonsoft.Json": "[13.0.3, )"
}
},
"Microsoft.Extensions.Logging.Console": {
@@ -368,6 +358,12 @@
"Microsoft.Extensions.Logging": "8.0.1",
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
}
+ },
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
}
},
"net8.0/linux-arm64": {
diff --git a/deps-all.nix b/deps-all.nix
deleted file mode 100644
index 4cc8c4a8c5..0000000000
--- a/deps-all.nix
+++ /dev/null
@@ -1,387 +0,0 @@
-# This file was automatically generated by passthru.fetch-deps.
-# Please dont edit it manually, your changes might get overwritten!
-
-{ fetchNuGet }: [
- (fetchNuGet { pname = "Avalonia"; version = "11.0.999-cibuild0044755-beta"; sha256 = "06aszzj0qlv9zjqik1id30yk7hz249m0wjcjdckf0j5fg7265vvr"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia/11.0.999-cibuild0044755-beta/avalonia.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Angle.Windows.Natives"; version = "2.1.0.2023020321"; sha256 = "1az4s1g22ipak9a3xfh55z2h3rm6lpqh7svbpw6ag4ysrgsjjsjd"; })
- (fetchNuGet { pname = "Avalonia.BuildServices"; version = "0.0.29"; sha256 = "05mm7f0jssih3gbzqfgjnfq5cnqa85ihsg0z1897ciihv8qd3waq"; })
- (fetchNuGet { pname = "Avalonia.Controls.ColorPicker"; version = "11.0.999-cibuild0044755-beta"; sha256 = "1b6rcy42imvm9vd0xcw3jv4wmacdz5j7sc1iqkjhlwkkf5dirkkp"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.controls.colorpicker/11.0.999-cibuild0044755-beta/avalonia.controls.colorpicker.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Controls.DataGrid"; version = "11.0.999-cibuild0044755-beta"; sha256 = "0vx7x1bddkx4vqvdjnaffw13vnfqfvj2dj5w1wzlpf7z71jn4cwx"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.controls.datagrid/11.0.999-cibuild0044755-beta/avalonia.controls.datagrid.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Controls.TreeDataGrid"; version = "11.0.2"; sha256 = "1b8hymad7rhr6zrj493i1hwlib5cg24dsj8k4v5lxpkc94lnhz0g"; })
- (fetchNuGet { pname = "Avalonia.Desktop"; version = "11.0.999-cibuild0044755-beta"; sha256 = "14hmf7qdhpqd4s9rpsa3r0rm02gkh1dsdp4zyy1m8jsb4c8nb6hc"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.desktop/11.0.999-cibuild0044755-beta/avalonia.desktop.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Diagnostics"; version = "11.0.999-cibuild0044755-beta"; sha256 = "1qh1s7ysx491py4lpz9gn948vajmjwfsdj800jzhwx9rx6ns2lch"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.diagnostics/11.0.999-cibuild0044755-beta/avalonia.diagnostics.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Fonts.Inter"; version = "11.0.999-cibuild0044755-beta"; sha256 = "13lbz6ncimgaignibqam4y6n3g68ih6p49dh52xxzv1dxl6gmk1x"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.fonts.inter/11.0.999-cibuild0044755-beta/avalonia.fonts.inter.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.FreeDesktop"; version = "11.0.999-cibuild0044755-beta"; sha256 = "12nc0rpsxbqwhzilvqqbfjz0xpq1r95cvb849n9p72mk10vixw9z"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.freedesktop/11.0.999-cibuild0044755-beta/avalonia.freedesktop.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Headless"; version = "11.0.999-cibuild0044755-beta"; sha256 = "02hxmkg7ffpnyskbq9sqvjcnrzrmgk6p1m5a95y4ll19n62bfygb"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.headless/11.0.999-cibuild0044755-beta/avalonia.headless.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Headless.XUnit"; version = "11.0.999-cibuild0044755-beta"; sha256 = "12cyx29iqw7ay934f1mav12gkrwh3lw091isc7nn2r5ndcvswq31"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.headless.xunit/11.0.999-cibuild0044755-beta/avalonia.headless.xunit.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Native"; version = "11.0.999-cibuild0044755-beta"; sha256 = "0mjp822hx9m24l87nv0manifjqf1rsyn2h5vq7mg835ivqf5gv9f"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.native/11.0.999-cibuild0044755-beta/avalonia.native.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.ReactiveUI"; version = "11.0.999-cibuild0044755-beta"; sha256 = "0kwxw3symzibayw8fy1gpjjxkm73hz9lh1x4g54h002d7b04nzdp"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.reactiveui/11.0.999-cibuild0044755-beta/avalonia.reactiveui.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Remote.Protocol"; version = "11.0.999-cibuild0044755-beta"; sha256 = "064x1pjpj62pd2pkqxiwlml1vh6j72s6g4gr48xl906lr7azh38f"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.remote.protocol/11.0.999-cibuild0044755-beta/avalonia.remote.protocol.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Skia"; version = "11.0.999-cibuild0044755-beta"; sha256 = "092gn6bz7lkhd38bdjqpfrq0abbk72sngl7fvmw54vrqj559ca79"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.skia/11.0.999-cibuild0044755-beta/avalonia.skia.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Themes.Fluent"; version = "11.0.999-cibuild0044755-beta"; sha256 = "1szlsig2jjz3gcmysba24yrlbgrnjpas9mn3jzj2kfqb04l547n9"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.themes.fluent/11.0.999-cibuild0044755-beta/avalonia.themes.fluent.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Themes.Simple"; version = "11.0.999-cibuild0044755-beta"; sha256 = "1f8dhgj598wvsx3f0dr7wg043zv44qs48jkdpsw98w9h1pn6dv9i"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.themes.simple/11.0.999-cibuild0044755-beta/avalonia.themes.simple.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Win32"; version = "11.0.999-cibuild0044755-beta"; sha256 = "1ln72447arkk6c49wx7ynr17lia3dg0sj563cb8rkbyf3622dzm4"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.win32/11.0.999-cibuild0044755-beta/avalonia.win32.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.X11"; version = "11.0.999-cibuild0044755-beta"; sha256 = "1m3xxiz5gc8f32xrxx9c8xzpxfzpnrzc449yi0kd4vm70pq6a3y1"; url = "https://nuget-feed-all.avaloniaui.net/v3/package/avalonia.x11/11.0.999-cibuild0044755-beta/avalonia.x11.11.0.999-cibuild0044755-beta.nupkg"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Behaviors"; version = "11.0.5"; sha256 = "1min8904hfcnpqi5mcj7nwg765xdvd47bzcxrcp6w02affaiqbf1"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Interactions"; version = "11.0.5"; sha256 = "11x71sag6lzpncfy2cdc2lm0nv5akgi3w3b7amj7dzlabvik9ymk"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Interactions.Custom"; version = "11.0.5"; sha256 = "1hfinp529frw5199mbsby1wqqjgphyg308w6w0m3xy63650maxfh"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Interactions.DragAndDrop"; version = "11.0.5"; sha256 = "1y9vp21m9ykcgls2na5qvqpr3b9kkq9ijnnw9393d3aiwg4221wb"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Interactions.Draggable"; version = "11.0.5"; sha256 = "1a9962m4bdp7df254fhqzxl8day0pqd2qmcislghkw5j78i9rihb"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Interactions.Events"; version = "11.0.5"; sha256 = "11fwhk4gfx360i7swf01xmrd36m5gg82v3217bx8qxzrwk0bic9m"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Interactions.Reactive"; version = "11.0.5"; sha256 = "000c2fwqv5qaqwddfnpjvgbyn5v1gi8fa8l3hjrb7p5yqpnfpdnf"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Interactions.Responsive"; version = "11.0.5"; sha256 = "0kygik82r0hz5c4jikk8bd1ani2q18m76wy00pgqgifcs88iixsd"; })
- (fetchNuGet { pname = "Avalonia.Xaml.Interactivity"; version = "11.0.5"; sha256 = "1vpgndhv28sgfnb333q6d8js1s2xxgnxqq2rnfc5n129pkd0inlw"; })
- (fetchNuGet { pname = "Castle.Core"; version = "5.1.1"; sha256 = "1caf4878nvjid3cw3rw18p9cn53brfs5x8dkvf82xvcdwc3i0nd1"; })
- (fetchNuGet { pname = "coverlet.collector"; version = "6.0.0"; sha256 = "12j34vrkmph8lspbafnqmfnj2qvysz1jcrks2khw798s6dwv0j90"; })
- (fetchNuGet { pname = "dotnet-xunit"; version = "2.3.1"; sha256 = "0w1zslkig6qk6rhw6ckfy331rnbfbnxr0gdy2pxgnc8rz2fj2s54"; })
- (fetchNuGet { pname = "DynamicData"; version = "7.9.5"; sha256 = "1m9qx8g6na5ka6kd9vhg8gjmxrnkzb6v5cl5yqp1kdjsw4rcwy6x"; })
- (fetchNuGet { pname = "DynamicData"; version = "8.1.1"; sha256 = "0pm0x7988ia47q9fb3wlgp2y00dlp1kk0w66v8i7i40mg308qh64"; })
- (fetchNuGet { pname = "HarfBuzzSharp"; version = "7.3.0"; sha256 = "1rqcmdyzxz9kc0k8594hbpksjc23mkakmjybi4b8702qycxx0lrf"; })
- (fetchNuGet { pname = "HarfBuzzSharp.NativeAssets.Linux"; version = "7.3.0"; sha256 = "0i9gaiyjgmcpnfn1fixbxq8shqlh4ahng7j4dxlf38zlln1f6h80"; })
- (fetchNuGet { pname = "HarfBuzzSharp.NativeAssets.macOS"; version = "7.3.0"; sha256 = "1b5ng37bwk75cifw7p1hzn8z6sswi8h7h510qgwlbvgmlrs5r0ga"; })
- (fetchNuGet { pname = "HarfBuzzSharp.NativeAssets.WebAssembly"; version = "7.3.0"; sha256 = "0dcmclnyryb82wzsky1dn0gbjsvx84mfx46v984f5fmg4v238lpm"; })
- (fetchNuGet { pname = "HarfBuzzSharp.NativeAssets.Win32"; version = "7.3.0"; sha256 = "1hyvmz7rfbrxbcpnwyvb64gdk1hifcpz3rln58yyb7g1pnbpnw2s"; })
- (fetchNuGet { pname = "Libuv"; version = "1.9.0"; sha256 = "0ag6l9h1h4knf3hy1fjfrqm6mavr9zw35i0qrnnm8la4mdbcnd0f"; })
- (fetchNuGet { pname = "MicroCom.Runtime"; version = "0.11.0"; sha256 = "0p9c3m0zk59x9dcqw077hzd2yk60myisbacvm36mnwpcjwzjkp2m"; })
- (fetchNuGet { pname = "Microsoft.AspNetCore.JsonPatch"; version = "8.0.0"; sha256 = "1z052fqfwi28bd2p6045k7px2kad0nn3w6bglwf367lmf095pjaz"; })
- (fetchNuGet { pname = "Microsoft.AspNetCore.Mvc.NewtonsoftJson"; version = "8.0.0"; sha256 = "11rcqgl620mca0hz909vg9994iy3vizn77nr8q6jybn7v7pksyp0"; })
- (fetchNuGet { pname = "Microsoft.AspNetCore.Mvc.Testing"; version = "8.0.0"; sha256 = "0fh6bdpxxxm2b3rnlxs08zd0c3h5dj69acx924w4bbl9x7a1ikp4"; })
- (fetchNuGet { pname = "Microsoft.AspNetCore.TestHost"; version = "8.0.0"; sha256 = "140nr2lxhqf6jfnmb99fliw1pvlnlgcwaqw1kznarj2kfp6c7vpg"; })
- (fetchNuGet { pname = "Microsoft.AspNetCore.WebUtilities"; version = "8.0.0"; sha256 = "126xyqxsfhr6qn5r8fm13yybsqnzy1sbjw7l16xglg90jm62m33v"; })
- (fetchNuGet { pname = "Microsoft.Build"; version = "15.3.409"; sha256 = "0vzq6csp2yys9s96c7i37bjml439rdi47g8f5rzqdr7xf5a1jk81"; })
- (fetchNuGet { pname = "Microsoft.Build.Framework"; version = "15.3.409"; sha256 = "1dhanwb9ihbfay85xj7cwn0byzmmdz94hqfi3q6r1ncwdjd8y1s2"; })
- (fetchNuGet { pname = "Microsoft.Build.Runtime"; version = "15.3.409"; sha256 = "135ycnqz5jfg61y5zaapgc7xdpjx2aq4icmxb9ph7h5inl445q7q"; })
- (fetchNuGet { pname = "Microsoft.Build.Tasks.Core"; version = "15.3.409"; sha256 = "135swyygp7cz2civwsz6a7dj7h8bzp7yrybmgxjanxwrw66hm933"; })
- (fetchNuGet { pname = "Microsoft.Build.Utilities.Core"; version = "15.3.409"; sha256 = "1p8a0l9sxmjj86qha748qjw2s2n07q8mn41mj5r6apjnwl27ywnf"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.Analyzers"; version = "1.1.0"; sha256 = "08r667hj2259wbim1p3al5qxkshydykmb7nd9ygbjlg4mmydkapc"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.Analyzers"; version = "3.0.0"; sha256 = "0bbl0jpqywqmzz2gagld1p2gvdfldjfjmm25hil9wj2nq1zc4di8"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.Analyzers"; version = "3.3.4"; sha256 = "0wd6v57p53ahz5z9zg4iyzmy3src7rlsncyqpcag02jjj1yx6g58"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.BannedApiAnalyzers"; version = "3.3.4"; sha256 = "1vzrni7n94f17bzc13lrvcxvgspx9s25ap1p005z6i1ikx6wgx30"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.Common"; version = "1.3.0"; sha256 = "097qi36jhyllpqj313nxzwc64a4f65p014gaj6fz4z5jcphkkk15"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.Common"; version = "3.8.0"; sha256 = "12n7rvr39bzkf2maw7zplw8rwpxpxss4ich3bb2pw770rx4nyvyw"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.Common"; version = "4.6.0"; sha256 = "0qvkwkbqz4dhkxsisanax1lwm3nzyyb4kgb40qczxbl8g251cjp2"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.CSharp"; version = "1.3.0"; sha256 = "0vpslncd5lk88ijb42qbp88dfrd0fg4kri44w6jpmxb3fcqazais"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.CSharp"; version = "3.8.0"; sha256 = "1kmry65csvfn72zzc16vj1nfbfwam28wcmlrk3m5rzb8ydbzgylb"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.CSharp"; version = "4.6.0"; sha256 = "1yfvwygx795c9lswpiv8q19zydifarzljdmvv67vjmi559cm8b1q"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.CSharp.Scripting"; version = "3.8.0"; sha256 = "0w0yx0lpg54iw5jazqk46h48gx43ij32gwac8iywdj6kxfxm03vw"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.Scripting.Common"; version = "3.8.0"; sha256 = "0hjgxcsj5zy27lqk0986m59n5dbplx2vjjla2lsvg4bwg8qa7bpk"; })
- (fetchNuGet { pname = "Microsoft.CodeAnalysis.VisualBasic"; version = "1.3.0"; sha256 = "186chky80rryhzh5dh8j318ghyvn1a7r2876rlyadxdrs7aqv0ll"; })
- (fetchNuGet { pname = "Microsoft.CodeCoverage"; version = "17.8.0"; sha256 = "173wjadp3gan4x2jfjchngnc4ca4mb95h1sbb28jydfkfw0z1zvj"; })
- (fetchNuGet { pname = "Microsoft.CSharp"; version = "4.0.1"; sha256 = "0zxc0apx1gcx361jlq8smc9pfdgmyjh6hpka8dypc9w23nlsh6yj"; })
- (fetchNuGet { pname = "Microsoft.CSharp"; version = "4.3.0"; sha256 = "0gw297dgkh0al1zxvgvncqs0j15lsna9l1wpqas4rflmys440xvb"; })
- (fetchNuGet { pname = "Microsoft.CSharp"; version = "4.7.0"; sha256 = "0gd67zlw554j098kabg887b5a6pq9kzavpa3jjy5w53ccjzjfy8j"; })
- (fetchNuGet { pname = "Microsoft.Data.Sqlite"; version = "8.0.0"; sha256 = "02y3y3x4ggxcjcrnazwxdi08xmwabaalrm40rwjdij072x5va3yi"; })
- (fetchNuGet { pname = "Microsoft.Data.Sqlite.Core"; version = "8.0.0"; sha256 = "05qjnzk1fxybks92y93487l3mj5nghjcwiy360xjgk3jykz3rv39"; })
- (fetchNuGet { pname = "Microsoft.Extensions.ApiDescription.Server"; version = "6.0.5"; sha256 = "1pi2bm3cm0a7jzqzmfc2r7bpcdkmk3hhjfvb2c81j7wl7xdw3624"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Caching.Abstractions"; version = "8.0.0"; sha256 = "04m6ywsf9731z24nfd14z0ah8xl06619ba7mkdb4vg8h5jpllsn4"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Caching.Memory"; version = "8.0.0"; sha256 = "0bv8ihd5i2gwr97qljwf56h8mdwspmlw0zs64qyk608fb3ciwi25"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Configuration"; version = "8.0.0"; sha256 = "080kab87qgq2kh0ijry5kfdiq9afyzb8s0k3jqi5zbbi540yq4zl"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Configuration.Abstractions"; version = "8.0.0"; sha256 = "1jlpa4ggl1gr5fs7fdcw04li3y3iy05w3klr9lrrlc7v8w76kq71"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Configuration.Binder"; version = "8.0.0"; sha256 = "1m0gawiz8f5hc3li9vd5psddlygwgkiw13d7div87kmkf4idza8r"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Configuration.CommandLine"; version = "8.0.0"; sha256 = "026f7f2iv6ph2dc5rnslll0bly8qcx5clmh2nn9hgyqjizzc4qvy"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Configuration.EnvironmentVariables"; version = "8.0.0"; sha256 = "13qb8wz3k59ihq0mjcqz1kwrpyzxn5da4dhk2pvcgc42z9kcbf7r"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Configuration.FileExtensions"; version = "8.0.0"; sha256 = "1jrmlfzy4h32nzf1nm5q8bhkpx958b0ww9qx1k1zm4pyaf6mqb04"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Configuration.Json"; version = "8.0.0"; sha256 = "1n3ss26v1lq6b69fxk1vz3kqv9ppxq8ypgdqpd7415xrq66y4bqn"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Configuration.UserSecrets"; version = "8.0.0"; sha256 = "1br01zhzhnxjzqx63bxd25x48y9xs69hcs71pjni8y9kl50zja7z"; })
- (fetchNuGet { pname = "Microsoft.Extensions.DependencyInjection"; version = "8.0.0"; sha256 = "0i7qziz0iqmbk8zzln7kx9vd0lbx1x3va0yi3j1bgkjir13h78ps"; })
- (fetchNuGet { pname = "Microsoft.Extensions.DependencyInjection.Abstractions"; version = "8.0.0"; sha256 = "1zw0bpp5742jzx03wvqc8csnvsbgdqi0ls9jfc5i2vd3cl8b74pg"; })
- (fetchNuGet { pname = "Microsoft.Extensions.DependencyModel"; version = "8.0.0"; sha256 = "02jnx23hm1vid3yd9pw4gghzn6qkgdl5xfc5r0zrcxdax70rsh5a"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Diagnostics"; version = "8.0.0"; sha256 = "0ghwkld91k20hcbmzg2137w81mzzdh8hfaapdwckhza0vipya4kw"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Diagnostics.Abstractions"; version = "8.0.0"; sha256 = "15m4j6w9n8h0mj7hlfzb83hd3wn7aq1s7fxbicm16slsjfwzj82i"; })
- (fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Abstractions"; version = "2.0.0"; sha256 = "0d6y5isjy6jpf4w3f3w89cwh9p40glzhwvm7cwhx05wkqd8bk9w4"; })
- (fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Abstractions"; version = "8.0.0"; sha256 = "1idq65fxwcn882c06yci7nscy9i0rgw6mqjrl7362prvvsd9f15r"; })
- (fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Physical"; version = "2.0.0"; sha256 = "0l0l92g7sq4122n139av1pn1jl6wlw92hjmdnr47xdss0ndmwrs3"; })
- (fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Physical"; version = "8.0.0"; sha256 = "05wxjvjbx79ir7vfkri6b28k8zl8fa6bbr0i7gahqrim2ijvkp6v"; })
- (fetchNuGet { pname = "Microsoft.Extensions.FileSystemGlobbing"; version = "2.0.0"; sha256 = "02lzy6r14ghwfwm384xajq08vv3pl3ww0mi5isrr10vivhijhgg4"; })
- (fetchNuGet { pname = "Microsoft.Extensions.FileSystemGlobbing"; version = "8.0.0"; sha256 = "1igf2bqism22fxv7km5yv028r4rg12a4lki2jh4xg3brjkagiv7q"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Hosting"; version = "8.0.0"; sha256 = "1f2af5m1yny8b43251gsj75hjd9ixni1clcldy8cg91z1vxxm8dh"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Hosting.Abstractions"; version = "8.0.0"; sha256 = "00d5dwmzw76iy8z40ly01hy9gly49a7rpf7k7m99vrid1kxp346h"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Http"; version = "8.0.0"; sha256 = "09hmkhxipbpfmwz9q80746zp6cvbx1cqffxr5xjxv5cbjg5662aj"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging"; version = "8.0.0"; sha256 = "0nppj34nmq25gnrg0wh1q22y4wdqbih4ax493f226azv8mkp9s1i"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging.Abstractions"; version = "1.0.0"; sha256 = "1sh9bidmhy32gkz6fkli79mxv06546ybrzppfw5v2aq0bda1ghka"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging.Abstractions"; version = "8.0.0"; sha256 = "1klcqhg3hk55hb6vmjiq2wgqidsl81aldw0li2z98lrwx26msrr6"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging.Configuration"; version = "8.0.0"; sha256 = "1d9b734vnll935661wqkgl7ry60rlh5p876l2bsa930mvfsaqfcv"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging.Console"; version = "8.0.0"; sha256 = "1mvp3ipw7k33v2qw2yrvc4vl5yzgpk3yxa94gg0gz7wmcmhzvmkd"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging.Debug"; version = "8.0.0"; sha256 = "1h7mg97lj0ss47kq7zwnihh9c6xcrkwrr8ffhc16qcsrh36sg6q0"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging.EventLog"; version = "8.0.0"; sha256 = "05vfrxw7mlwlwhsl6r4yrhxk3sd8dv5sl0hdlcpgw62n53incw5x"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging.EventSource"; version = "8.0.0"; sha256 = "0gbjll6p03rmw0cf8fp0p8cxzn9awmzv8hvnyqbczrkax5h7p94i"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Options"; version = "8.0.0"; sha256 = "0p50qn6zhinzyhq9sy5svnmqqwhw2jajs2pbjh9sah504wjvhscz"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Options.ConfigurationExtensions"; version = "8.0.0"; sha256 = "04nm8v5a3zp0ill7hjnwnja3s2676b4wffdri8hdk2341p7mp403"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Primitives"; version = "2.0.0"; sha256 = "1xppr5jbny04slyjgngxjdm0maxdh47vq481ps944d7jrfs0p3mb"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Primitives"; version = "8.0.0"; sha256 = "0aldaz5aapngchgdr7dax9jw5wy7k7hmjgjpfgfv1wfif27jlkqm"; })
- (fetchNuGet { pname = "Microsoft.Net.Http.Headers"; version = "8.0.0"; sha256 = "0k5fcf00g8hpwxx4pkwa9iyy4sdspqx8zw9p3r3i6xyijsmk0ah7"; })
- (fetchNuGet { pname = "Microsoft.NET.Test.Sdk"; version = "17.8.0"; sha256 = "1syvl3g0hbrcgfi9rq6pld8s8hqqww4dflf1lxn59ccddyyx0gmv"; })
- (fetchNuGet { pname = "Microsoft.NETCore.App"; version = "1.0.0"; sha256 = "0i09cs7a7hxn9n1nx49382csvc7560j4hbxr2c8bwa69nhf2rrjp"; })
- (fetchNuGet { pname = "Microsoft.NETCore.App"; version = "2.0.5"; sha256 = "0qb7k624w7l0zhapdp519ymqg84a67r8zyd8cpj42hywsgb0dqv6"; })
- (fetchNuGet { pname = "Microsoft.NETCore.DotNetAppHost"; version = "2.0.5"; sha256 = "00bsxdg9c8msjxyffvfi8siqk8v2m7ca8fqy1npv7b2pzg3byjws"; })
- (fetchNuGet { pname = "Microsoft.NETCore.DotNetHost"; version = "1.0.1"; sha256 = "1qr4gnzlpwzv8jr7ijmdg13x2s9m35g4ma0bh18kci4ml7h9jb6a"; })
- (fetchNuGet { pname = "Microsoft.NETCore.DotNetHostPolicy"; version = "1.0.1"; sha256 = "0vbqww1bmlkz7xq05zxykv27xdrkl6nrjhs1iiszaa9ivf7nklz1"; })
- (fetchNuGet { pname = "Microsoft.NETCore.DotNetHostPolicy"; version = "2.0.5"; sha256 = "0v5csskiwpk8kz8wclqad8kcjmxr7ik4w99wl05740qvaag3qysk"; })
- (fetchNuGet { pname = "Microsoft.NETCore.DotNetHostResolver"; version = "1.0.1"; sha256 = "109zs3bqhzh6mhbf2rfpwxmpb8fq57jr7wriyylynirsqh1lnql4"; })
- (fetchNuGet { pname = "Microsoft.NETCore.DotNetHostResolver"; version = "2.0.5"; sha256 = "1sz2fdp8fdwz21x3lr2m1zhhrbix6iz699fjkwiryqdjl4ygd3hw"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Jit"; version = "1.0.2"; sha256 = "0jaan2wmg80lr0mhgfy70kb5cqjwv1a2ikmxgd0glpcxp7wr7pag"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Platforms"; version = "1.0.1"; sha256 = "01al6cfxp68dscl15z7rxfw9zvhm64dncsw09a1vmdkacsa2v6lr"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Platforms"; version = "1.1.0"; sha256 = "08vh1r12g6ykjygq5d3vq09zylgb84l63k49jc4v8faw9g93iqqm"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Platforms"; version = "1.1.1"; sha256 = "164wycgng4mi9zqi2pnsf1pq6gccbqvw6ib916mqizgjmd8f44pj"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Platforms"; version = "2.0.1"; sha256 = "1j2hmnivgb4plni2dd205kafzg6mkg7r4knrd3s7mg75wn2l25np"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Platforms"; version = "2.1.2"; sha256 = "1507hnpr9my3z4w1r6xk5n0s1j3y6a2c2cnynj76za7cphxi1141"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Runtime.CoreCLR"; version = "1.0.2"; sha256 = "1hxgsjyzh7hdgd34xwpn5s2myy1b1y9ms7xhvs6mkb75wap49bpc"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Targets"; version = "1.0.1"; sha256 = "0ppdkwy6s9p7x9jix3v4402wb171cdiibq7js7i13nxpdky7074p"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Targets"; version = "1.1.0"; sha256 = "193xwf33fbm0ni3idxzbr5fdq3i2dlfgihsac9jj7whj0gd902nh"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Targets"; version = "1.1.3"; sha256 = "05smkcyxir59rgrmp7d6327vvrlacdgldfxhmyr1azclvga1zfsq"; })
- (fetchNuGet { pname = "Microsoft.NETCore.Windows.ApiSets"; version = "1.0.1"; sha256 = "16k8chghkr25jf49banhzl839vs8n3vbfpg4wn4idi0hzjipix78"; })
- (fetchNuGet { pname = "Microsoft.OpenApi"; version = "1.2.3"; sha256 = "07b19k89whj69j87afkz86gp9b3iybw8jqwvlgcn43m7fb2y99rr"; })
- (fetchNuGet { pname = "Microsoft.TestPlatform.ObjectModel"; version = "17.8.0"; sha256 = "0b0i7lmkrcfvim8i3l93gwqvkhhhfzd53fqfnygdqvkg6np0cg7m"; })
- (fetchNuGet { pname = "Microsoft.TestPlatform.TestHost"; version = "17.8.0"; sha256 = "0f5jah93kjkvxwmhwb78lw11m9pkkq9fvf135hpymmmpxqbdh97q"; })
- (fetchNuGet { pname = "Microsoft.VisualBasic"; version = "10.0.1"; sha256 = "0q6vv9qfkbwn7gz8qf1gfcn33r87m260hsxdsk838mcbqmjz6wgc"; })
- (fetchNuGet { pname = "Microsoft.VisualStudio.Web.CodeGeneration.Contracts"; version = "2.0.2"; sha256 = "1fs6sbjn0chx6rv38d61zgk8mhyyxz44xp4wsfya0lvkckyszyn1"; })
- (fetchNuGet { pname = "Microsoft.VisualStudio.Web.CodeGeneration.Tools"; version = "2.0.2"; sha256 = "0fkjm06irs53d77z29i6dwj5pjhgj9ivhad8v39ghnrwasc0ivq6"; })
- (fetchNuGet { pname = "Microsoft.Win32.Primitives"; version = "4.0.1"; sha256 = "1n8ap0cmljbqskxpf8fjzn7kh1vvlndsa75k01qig26mbw97k2q7"; })
- (fetchNuGet { pname = "Microsoft.Win32.Registry"; version = "4.0.0"; sha256 = "1spf4m9pikkc19544p29a47qnhcd885klncahz133hbnyqbkmz9k"; })
- (fetchNuGet { pname = "Microsoft.Win32.SystemEvents"; version = "8.0.0"; sha256 = "05392f41ijgn17y8pbjcx535l1k09krnq3xdp60kyq568sn6xk2i"; })
- (fetchNuGet { pname = "Moq"; version = "4.18.4"; sha256 = "0x439pcaqg8kv0an4cjbspw8d98gq144yrqwhnnh6xf9qjaris94"; })
- (fetchNuGet { pname = "NBitcoin"; version = "7.0.42.2"; sha256 = "01hrzbjz0cwz7qnqqwi3rfavdccj095r0q1w7x60izs9wmwlgdni"; })
- (fetchNuGet { pname = "NBitcoin.Secp256k1"; version = "3.1.0"; sha256 = "1mbn757gds2019j7d3p59ykwibxvkz5dhxagy5f4zzvz7537a6my"; })
- (fetchNuGet { pname = "NETStandard.Library"; version = "1.6.0"; sha256 = "0nmmv4yw7gw04ik8ialj3ak0j6pxa9spih67hnn1h2c38ba8h58k"; })
- (fetchNuGet { pname = "NETStandard.Library"; version = "2.0.1"; sha256 = "0d44wjxphs1ck838v7dapm0ag0b91zpiy33cr5vflsrwrqgj51dk"; })
- (fetchNuGet { pname = "NETStandard.Library"; version = "2.0.3"; sha256 = "1fn9fxppfcg4jgypp2pmrpr6awl3qz1xmnri0cygpkwvyx27df1y"; })
- (fetchNuGet { pname = "Newtonsoft.Json"; version = "10.0.1"; sha256 = "15ncqic3p2rzs8q8ppi0irl2miq75kilw4lh8yfgjq96id0ds3hv"; })
- (fetchNuGet { pname = "Newtonsoft.Json"; version = "13.0.1"; sha256 = "0fijg0w6iwap8gvzyjnndds0q4b8anwxxvik7y8vgq97dram4srb"; })
- (fetchNuGet { pname = "Newtonsoft.Json"; version = "13.0.3"; sha256 = "0xrwysmrn4midrjal8g2hr1bbg38iyisl0svamb11arqws4w2bw7"; })
- (fetchNuGet { pname = "Newtonsoft.Json.Bson"; version = "1.0.2"; sha256 = "0c27bhy9x3c2n26inq32kmp6drpm71n6mqnmcr19wrlcaihglj35"; })
- (fetchNuGet { pname = "NuGet.Frameworks"; version = "4.0.0"; sha256 = "0nar684cm53cvzx28gzl6kmpg9mrfr1yv29323din7xqal4pscgq"; })
- (fetchNuGet { pname = "NuGet.Frameworks"; version = "6.5.0"; sha256 = "0s37d1p4md0k6d4cy6sq36f2dgkd9qfbzapxhkvi8awwh0vrynhj"; })
- (fetchNuGet { pname = "QRackers"; version = "1.1.0"; sha256 = "1w8p5iw4kfs1w54bh9snxg240q2dpy1wjkc0civcjk697b035imj"; })
- (fetchNuGet { pname = "ReactiveUI"; version = "18.3.1"; sha256 = "1lxkc8yk9glj0w9n5vry2dnwwvh8152ad2c5bivk8aciq64zidyn"; })
- (fetchNuGet { pname = "runtime.any.System.Collections"; version = "4.3.0"; sha256 = "0bv5qgm6vr47ynxqbnkc7i797fdi8gbjjxii173syrx14nmrkwg0"; })
- (fetchNuGet { pname = "runtime.any.System.Diagnostics.Tracing"; version = "4.3.0"; sha256 = "00j6nv2xgmd3bi347k00m7wr542wjlig53rmj28pmw7ddcn97jbn"; })
- (fetchNuGet { pname = "runtime.any.System.Globalization"; version = "4.3.0"; sha256 = "1daqf33hssad94lamzg01y49xwndy2q97i2lrb7mgn28656qia1x"; })
- (fetchNuGet { pname = "runtime.any.System.IO"; version = "4.3.0"; sha256 = "0l8xz8zn46w4d10bcn3l4yyn4vhb3lrj2zw8llvz7jk14k4zps5x"; })
- (fetchNuGet { pname = "runtime.any.System.Reflection"; version = "4.3.0"; sha256 = "02c9h3y35pylc0zfq3wcsvc5nqci95nrkq0mszifc0sjx7xrzkly"; })
- (fetchNuGet { pname = "runtime.any.System.Reflection.Extensions"; version = "4.3.0"; sha256 = "0zyri97dfc5vyaz9ba65hjj1zbcrzaffhsdlpxc9bh09wy22fq33"; })
- (fetchNuGet { pname = "runtime.any.System.Reflection.Primitives"; version = "4.3.0"; sha256 = "0x1mm8c6iy8rlxm8w9vqw7gb7s1ljadrn049fmf70cyh42vdfhrf"; })
- (fetchNuGet { pname = "runtime.any.System.Resources.ResourceManager"; version = "4.3.0"; sha256 = "03kickal0iiby82wa5flar18kyv82s9s6d4xhk5h4bi5kfcyfjzl"; })
- (fetchNuGet { pname = "runtime.any.System.Runtime"; version = "4.3.0"; sha256 = "1cqh1sv3h5j7ixyb7axxbdkqx6cxy00p4np4j91kpm492rf4s25b"; })
- (fetchNuGet { pname = "runtime.any.System.Runtime.Handles"; version = "4.3.0"; sha256 = "0bh5bi25nk9w9xi8z23ws45q5yia6k7dg3i4axhfqlnj145l011x"; })
- (fetchNuGet { pname = "runtime.any.System.Runtime.InteropServices"; version = "4.3.0"; sha256 = "0c3g3g3jmhlhw4klrc86ka9fjbl7i59ds1fadsb2l8nqf8z3kb19"; })
- (fetchNuGet { pname = "runtime.any.System.Text.Encoding"; version = "4.3.0"; sha256 = "0aqqi1v4wx51h51mk956y783wzags13wa7mgqyclacmsmpv02ps3"; })
- (fetchNuGet { pname = "runtime.any.System.Threading.Tasks"; version = "4.3.0"; sha256 = "03mnvkhskbzxddz4hm113zsch1jyzh2cs450dk3rgfjp8crlw1va"; })
- (fetchNuGet { pname = "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "16rnxzpk5dpbbl1x354yrlsbvwylrq456xzpsha1n9y3glnhyx9d"; })
- (fetchNuGet { pname = "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "0hkg03sgm2wyq8nqk6dbm9jh5vcq57ry42lkqdmfklrw89lsmr59"; })
- (fetchNuGet { pname = "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "0c2p354hjx58xhhz7wv6div8xpi90sc6ibdm40qin21bvi7ymcaa"; })
- (fetchNuGet { pname = "runtime.native.System"; version = "4.0.0"; sha256 = "1ppk69xk59ggacj9n7g6fyxvzmk1g5p4fkijm0d7xqfkig98qrkf"; })
- (fetchNuGet { pname = "runtime.native.System"; version = "4.3.0"; sha256 = "15hgf6zaq9b8br2wi1i3x0zvmk410nlmsmva9p0bbg73v6hml5k4"; })
- (fetchNuGet { pname = "runtime.native.System.IO.Compression"; version = "4.1.0"; sha256 = "0d720z4lzyfcabmmnvh0bnj76ll7djhji2hmfh3h44sdkjnlkknk"; })
- (fetchNuGet { pname = "runtime.native.System.Net.Http"; version = "4.0.1"; sha256 = "1hgv2bmbaskx77v8glh7waxws973jn4ah35zysnkxmf0196sfxg6"; })
- (fetchNuGet { pname = "runtime.native.System.Net.Security"; version = "4.0.1"; sha256 = "1nk4pf8vbrgf73p0skhwmzhgz1hax3j123ilhwdncr47l3x1dbhk"; })
- (fetchNuGet { pname = "runtime.native.System.Security.Cryptography"; version = "4.0.0"; sha256 = "0k57aa2c3b10wl3hfqbgrl7xq7g8hh3a3ir44b31dn5p61iiw3z9"; })
- (fetchNuGet { pname = "runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "18pzfdlwsg2nb1jjjjzyb5qlgy6xjxzmhnfaijq5s2jw3cm3ab97"; })
- (fetchNuGet { pname = "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "0qyynf9nz5i7pc26cwhgi8j62ps27sqmf78ijcfgzab50z9g8ay3"; })
- (fetchNuGet { pname = "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "1klrs545awhayryma6l7g2pvnp9xy4z0r1i40r80zb45q3i9nbyf"; })
- (fetchNuGet { pname = "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "0zcxjv5pckplvkg0r6mw3asggm7aqzbdjimhvsasb0cgm59x09l3"; })
- (fetchNuGet { pname = "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "0vhynn79ih7hw7cwjazn87rm9z9fj0rvxgzlab36jybgcpcgphsn"; })
- (fetchNuGet { pname = "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "160p68l2c7cqmyqjwxydcvgw7lvl1cr0znkw8fp24d1by9mqc8p3"; })
- (fetchNuGet { pname = "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "15zrc8fgd8zx28hdghcj5f5i34wf3l6bq5177075m2bc2j34jrqy"; })
- (fetchNuGet { pname = "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl"; version = "4.3.0"; sha256 = "1p4dgxax6p7rlgj4q73k73rslcnz4wdcv8q2flg1s8ygwcm58ld5"; })
- (fetchNuGet { pname = "runtime.unix.System.Diagnostics.Debug"; version = "4.3.0"; sha256 = "1lps7fbnw34bnh3lm31gs5c0g0dh7548wfmb8zz62v0zqz71msj5"; })
- (fetchNuGet { pname = "runtime.unix.System.Private.Uri"; version = "4.3.0"; sha256 = "1jx02q6kiwlvfksq1q9qr17fj78y5v6mwsszav4qcz9z25d5g6vk"; })
- (fetchNuGet { pname = "runtime.unix.System.Runtime.Extensions"; version = "4.3.0"; sha256 = "0pnxxmm8whx38dp6yvwgmh22smknxmqs5n513fc7m4wxvs1bvi4p"; })
- (fetchNuGet { pname = "SkiaSharp"; version = "2.88.3"; sha256 = "1yq694myq2rhfp2hwwpyzcg1pzpxcp7j72wib8p9pw9dfj7008sv"; })
- (fetchNuGet { pname = "SkiaSharp"; version = "2.88.7"; sha256 = "0f6wbk9dnjiffb9ycjachy1m9zw3pai2m503nym07qgb0izxm792"; })
- (fetchNuGet { pname = "SkiaSharp.NativeAssets.Linux"; version = "2.88.7"; sha256 = "0p0z6nxkkmabv46wmxhs3yr0xy24i6jzn54gk0hsm3h1a8vi3m21"; })
- (fetchNuGet { pname = "SkiaSharp.NativeAssets.macOS"; version = "2.88.3"; sha256 = "191ajgi6fnfqcvqvkayjsxasiz6l0bv3pps8vv9abbyc4b12qvph"; })
- (fetchNuGet { pname = "SkiaSharp.NativeAssets.macOS"; version = "2.88.7"; sha256 = "05xwa1izzvqz4gznvx2x31qnpvl1lc65hm5p9sscjg5afisya0ss"; })
- (fetchNuGet { pname = "SkiaSharp.NativeAssets.WebAssembly"; version = "2.88.7"; sha256 = "1k2hfasgbv01navc55zzwdwzfxcw4186jni35c00zykgwhbwb250"; })
- (fetchNuGet { pname = "SkiaSharp.NativeAssets.Win32"; version = "2.88.3"; sha256 = "03wwfbarsxjnk70qhqyd1dw65098dncqk2m0vksx92j70i7lry6q"; })
- (fetchNuGet { pname = "SkiaSharp.NativeAssets.Win32"; version = "2.88.7"; sha256 = "119mlbh5hmlis7vb111s95dwg5p1anm2hmv7cm6fz7gy18473d7v"; })
- (fetchNuGet { pname = "Splat"; version = "14.4.1"; sha256 = "03ycyjn2ii44npi015p4rk344xnjgdzz02cf63cmhx2ab8hv6p4b"; })
- (fetchNuGet { pname = "SQLitePCLRaw.bundle_e_sqlite3"; version = "2.1.6"; sha256 = "0pzgdfl707pd9fz108xaff22w7c2y27yaix6wfp36phqkdnzz43m"; })
- (fetchNuGet { pname = "SQLitePCLRaw.core"; version = "2.1.6"; sha256 = "1w8zsgz2w2q0a9cw9cl1rzrpv48a04nhyq67ywan6xlgknds65a7"; })
- (fetchNuGet { pname = "SQLitePCLRaw.lib.e_sqlite3"; version = "2.1.6"; sha256 = "0g959z7r3h43nwzm7z3jiib1xvyx146lxyv0x6fl8ll5wivpjyxq"; })
- (fetchNuGet { pname = "SQLitePCLRaw.provider.e_sqlite3"; version = "2.1.6"; sha256 = "1vs1c7yhi0mdqrd35ji289cxkhg7dxdnn6wgjjbngvqxkdhkyxyc"; })
- (fetchNuGet { pname = "Swashbuckle.AspNetCore"; version = "6.5.0"; sha256 = "0k61chpz5j59s1yax28vx0mppx20ff8vg8grwja112hfrzj1f45n"; })
- (fetchNuGet { pname = "Swashbuckle.AspNetCore.Swagger"; version = "6.5.0"; sha256 = "1s6axf6fin8sss3bvzp0s039rxrx71vx4rl559miw12bz3lld8kc"; })
- (fetchNuGet { pname = "Swashbuckle.AspNetCore.SwaggerGen"; version = "6.5.0"; sha256 = "0hq93gy5vyrigpdk9lhqwxglxwkbxa8ydllwcqs4bwfcsspzrs83"; })
- (fetchNuGet { pname = "Swashbuckle.AspNetCore.SwaggerUI"; version = "6.5.0"; sha256 = "17hx7kc187higm0gk67dndng3n7932sn3fwyj48l45cvyr3025h7"; })
- (fetchNuGet { pname = "System.AppContext"; version = "4.1.0"; sha256 = "0fv3cma1jp4vgj7a8hqc9n7hr1f1kjp541s6z0q1r6nazb4iz9mz"; })
- (fetchNuGet { pname = "System.Buffers"; version = "4.0.0"; sha256 = "13s659bcmg9nwb6z78971z1lr6bmh2wghxi1ayqyzl4jijd351gr"; })
- (fetchNuGet { pname = "System.Buffers"; version = "4.5.1"; sha256 = "04kb1mdrlcixj9zh1xdi5as0k0qi8byr5mi3p3jcxx72qz93s2y3"; })
- (fetchNuGet { pname = "System.Collections"; version = "4.0.11"; sha256 = "1ga40f5lrwldiyw6vy67d0sg7jd7ww6kgwbksm19wrvq9hr0bsm6"; })
- (fetchNuGet { pname = "System.Collections"; version = "4.3.0"; sha256 = "19r4y64dqyrq6k4706dnyhhw7fs24kpp3awak7whzss39dakpxk9"; })
- (fetchNuGet { pname = "System.Collections.Concurrent"; version = "4.0.12"; sha256 = "07y08kvrzpak873pmyxs129g1ch8l27zmg51pcyj2jvq03n0r0fc"; })
- (fetchNuGet { pname = "System.Collections.Immutable"; version = "1.2.0"; sha256 = "1jm4pc666yiy7af1mcf7766v710gp0h40p228ghj6bavx7xfa38m"; })
- (fetchNuGet { pname = "System.Collections.Immutable"; version = "5.0.0"; sha256 = "1kvcllagxz2q92g81zkz81djkn2lid25ayjfgjalncyc68i15p0r"; })
- (fetchNuGet { pname = "System.Collections.Immutable"; version = "7.0.0"; sha256 = "1n9122cy6v3qhsisc9lzwa1m1j62b8pi2678nsmnlyvfpk0zdagm"; })
- (fetchNuGet { pname = "System.Collections.NonGeneric"; version = "4.0.1"; sha256 = "19994r5y5bpdhj7di6w047apvil8lh06lh2c2yv9zc4fc5g9bl4d"; })
- (fetchNuGet { pname = "System.Collections.NonGeneric"; version = "4.3.0"; sha256 = "07q3k0hf3mrcjzwj8fwk6gv3n51cb513w4mgkfxzm3i37sc9kz7k"; })
- (fetchNuGet { pname = "System.Collections.Specialized"; version = "4.3.0"; sha256 = "1sdwkma4f6j85m3dpb53v9vcgd0zyc9jb33f8g63byvijcj39n20"; })
- (fetchNuGet { pname = "System.ComponentModel"; version = "4.0.1"; sha256 = "0v4qpmqlzyfad2kswxxj2frnaqqhz9201c3yn8fmmarx5vlzg52z"; })
- (fetchNuGet { pname = "System.ComponentModel"; version = "4.3.0"; sha256 = "0986b10ww3nshy30x9sjyzm0jx339dkjxjj3401r3q0f6fx2wkcb"; })
- (fetchNuGet { pname = "System.ComponentModel.Annotations"; version = "4.1.0"; sha256 = "0l6m3z6h2qjjam1rp1fzk7zz5czjjazmw78rbh72x25y6kmyn6wf"; })
- (fetchNuGet { pname = "System.ComponentModel.Annotations"; version = "4.5.0"; sha256 = "1jj6f6g87k0iwsgmg3xmnn67a14mq88np0l1ys5zkxhkvbc8976p"; })
- (fetchNuGet { pname = "System.ComponentModel.Primitives"; version = "4.3.0"; sha256 = "1svfmcmgs0w0z9xdw2f2ps05rdxmkxxhf0l17xk9l1l8xfahkqr0"; })
- (fetchNuGet { pname = "System.ComponentModel.TypeConverter"; version = "4.3.0"; sha256 = "17ng0p7v3nbrg3kycz10aqrrlw4lz9hzhws09pfh8gkwicyy481x"; })
- (fetchNuGet { pname = "System.Console"; version = "4.0.0"; sha256 = "0ynxqbc3z1nwbrc11hkkpw9skw116z4y9wjzn7id49p9yi7mzmlf"; })
- (fetchNuGet { pname = "System.Diagnostics.Contracts"; version = "4.0.1"; sha256 = "0y6dkd9n5k98vzhc3w14r2pbhf10qjn2axpghpmfr6rlxx9qrb9j"; })
- (fetchNuGet { pname = "System.Diagnostics.Debug"; version = "4.0.11"; sha256 = "0gmjghrqmlgzxivd2xl50ncbglb7ljzb66rlx8ws6dv8jm0d5siz"; })
- (fetchNuGet { pname = "System.Diagnostics.Debug"; version = "4.3.0"; sha256 = "00yjlf19wjydyr6cfviaph3vsjzg3d5nvnya26i2fvfg53sknh3y"; })
- (fetchNuGet { pname = "System.Diagnostics.DiagnosticSource"; version = "4.0.0"; sha256 = "1n6c3fbz7v8d3pn77h4v5wvsfrfg7v1c57lg3nff3cjyh597v23m"; })
- (fetchNuGet { pname = "System.Diagnostics.DiagnosticSource"; version = "8.0.0"; sha256 = "0nzra1i0mljvmnj1qqqg37xs7bl71fnpl68nwmdajchh65l878zr"; })
- (fetchNuGet { pname = "System.Diagnostics.EventLog"; version = "6.0.0"; sha256 = "08y1x2d5w2hnhkh9r1998pjc7r4qp0rmzax062abha85s11chifd"; })
- (fetchNuGet { pname = "System.Diagnostics.EventLog"; version = "8.0.0"; sha256 = "1xnvcidh2qf6k7w8ij1rvj0viqkq84cq47biw0c98xhxg5rk3pxf"; })
- (fetchNuGet { pname = "System.Diagnostics.FileVersionInfo"; version = "4.0.0"; sha256 = "1s5vxhy7i09bmw51kxqaiz9zaj9am8wsjyz13j85sp23z267hbv3"; })
- (fetchNuGet { pname = "System.Diagnostics.Process"; version = "4.1.0"; sha256 = "061lrcs7xribrmq7kab908lww6kn2xn1w3rdc41q189y0jibl19s"; })
- (fetchNuGet { pname = "System.Diagnostics.StackTrace"; version = "4.0.1"; sha256 = "0q29axqklpl36vvyni5h1cyb02lfvvkqprb9wfvcdca3181q5al2"; })
- (fetchNuGet { pname = "System.Diagnostics.Tools"; version = "4.0.1"; sha256 = "19cknvg07yhakcvpxg3cxa0bwadplin6kyxd8mpjjpwnp56nl85x"; })
- (fetchNuGet { pname = "System.Diagnostics.Tools"; version = "4.3.0"; sha256 = "0in3pic3s2ddyibi8cvgl102zmvp9r9mchh82ns9f0ms4basylw1"; })
- (fetchNuGet { pname = "System.Diagnostics.TraceSource"; version = "4.0.0"; sha256 = "1mc7r72xznczzf6mz62dm8xhdi14if1h8qgx353xvhz89qyxsa3h"; })
- (fetchNuGet { pname = "System.Diagnostics.Tracing"; version = "4.1.0"; sha256 = "1d2r76v1x610x61ahfpigda89gd13qydz6vbwzhpqlyvq8jj6394"; })
- (fetchNuGet { pname = "System.Dynamic.Runtime"; version = "4.0.11"; sha256 = "1pla2dx8gkidf7xkciig6nifdsb494axjvzvann8g2lp3dbqasm9"; })
- (fetchNuGet { pname = "System.Dynamic.Runtime"; version = "4.3.0"; sha256 = "1d951hrvrpndk7insiag80qxjbf2y0y39y8h5hnq9612ws661glk"; })
- (fetchNuGet { pname = "System.Globalization"; version = "4.0.11"; sha256 = "070c5jbas2v7smm660zaf1gh0489xanjqymkvafcs4f8cdrs1d5d"; })
- (fetchNuGet { pname = "System.Globalization"; version = "4.3.0"; sha256 = "1cp68vv683n6ic2zqh2s1fn4c2sd87g5hpp6l4d4nj4536jz98ki"; })
- (fetchNuGet { pname = "System.Globalization.Calendars"; version = "4.0.1"; sha256 = "0bv0alrm2ck2zk3rz25lfyk9h42f3ywq77mx1syl6vvyncnpg4qh"; })
- (fetchNuGet { pname = "System.Globalization.Extensions"; version = "4.0.1"; sha256 = "0hjhdb5ri8z9l93bw04s7ynwrjrhx2n0p34sf33a9hl9phz69fyc"; })
- (fetchNuGet { pname = "System.Globalization.Extensions"; version = "4.3.0"; sha256 = "02a5zfxavhv3jd437bsncbhd2fp1zv4gxzakp1an9l6kdq1mcqls"; })
- (fetchNuGet { pname = "System.IO"; version = "4.1.0"; sha256 = "1g0yb8p11vfd0kbkyzlfsbsp5z44lwsvyc0h3dpw6vqnbi035ajp"; })
- (fetchNuGet { pname = "System.IO"; version = "4.3.0"; sha256 = "05l9qdrzhm4s5dixmx68kxwif4l99ll5gqmh7rqgw554fx0agv5f"; })
- (fetchNuGet { pname = "System.IO.Compression"; version = "4.1.0"; sha256 = "0iym7s3jkl8n0vzm3jd6xqg9zjjjqni05x45dwxyjr2dy88hlgji"; })
- (fetchNuGet { pname = "System.IO.Compression.ZipFile"; version = "4.0.1"; sha256 = "0h72znbagmgvswzr46mihn7xm7chfk2fhrp5krzkjf29pz0i6z82"; })
- (fetchNuGet { pname = "System.IO.FileSystem"; version = "4.0.1"; sha256 = "0kgfpw6w4djqra3w5crrg8xivbanh1w9dh3qapb28q060wb9flp1"; })
- (fetchNuGet { pname = "System.IO.FileSystem"; version = "4.3.0"; sha256 = "0z2dfrbra9i6y16mm9v1v6k47f0fm617vlb7s5iybjjsz6g1ilmw"; })
- (fetchNuGet { pname = "System.IO.FileSystem.Primitives"; version = "4.0.1"; sha256 = "1s0mniajj3lvbyf7vfb5shp4ink5yibsx945k6lvxa96r8la1612"; })
- (fetchNuGet { pname = "System.IO.FileSystem.Primitives"; version = "4.3.0"; sha256 = "0j6ndgglcf4brg2lz4wzsh1av1gh8xrzdsn9f0yznskhqn1xzj9c"; })
- (fetchNuGet { pname = "System.IO.FileSystem.Watcher"; version = "4.0.0"; sha256 = "0rgfjiqz8dqy8hmbfsls4sa46ss6p9vh86cvn1vqx7zg45pf3hir"; })
- (fetchNuGet { pname = "System.IO.MemoryMappedFiles"; version = "4.0.0"; sha256 = "1ahp27llf76ngc0fngl8zy4y1sgflzrkmxddilnd0l0cbbq1lm6m"; })
- (fetchNuGet { pname = "System.IO.Pipelines"; version = "6.0.0"; sha256 = "08211lvckdsdbd67xz4f6cyk76cli565j0dby1grlc4k9bhwby65"; })
- (fetchNuGet { pname = "System.IO.Pipelines"; version = "8.0.0"; sha256 = "00f36lqz1wf3x51kwk23gznkjjrf5nmqic9n7073nhrgrvb43nid"; })
- (fetchNuGet { pname = "System.IO.Pipes"; version = "4.0.0"; sha256 = "0fxfvcf55s9q8zsykwh8dkq2xb5jcqnml2ycq8srfry2l07h18za"; })
- (fetchNuGet { pname = "System.IO.UnmanagedMemoryStream"; version = "4.0.1"; sha256 = "012g8nwbfv94rhblsb3pxn1bazfpgjiy3kmy00679gg3651b87jb"; })
- (fetchNuGet { pname = "System.Linq"; version = "4.1.0"; sha256 = "1ppg83svb39hj4hpp5k7kcryzrf3sfnm08vxd5sm2drrijsla2k5"; })
- (fetchNuGet { pname = "System.Linq"; version = "4.3.0"; sha256 = "1w0gmba695rbr80l1k2h4mrwzbzsyfl2z4klmpbsvsg5pm4a56s7"; })
- (fetchNuGet { pname = "System.Linq.Expressions"; version = "4.1.0"; sha256 = "1gpdxl6ip06cnab7n3zlcg6mqp7kknf73s8wjinzi4p0apw82fpg"; })
- (fetchNuGet { pname = "System.Linq.Expressions"; version = "4.3.0"; sha256 = "0ky2nrcvh70rqq88m9a5yqabsl4fyd17bpr63iy2mbivjs2nyypv"; })
- (fetchNuGet { pname = "System.Linq.Parallel"; version = "4.0.1"; sha256 = "0i33x9f4h3yq26yvv6xnq4b0v51rl5z8v1bm7vk972h5lvf4apad"; })
- (fetchNuGet { pname = "System.Linq.Queryable"; version = "4.0.1"; sha256 = "11jn9k34g245yyf260gr3ldzvaqa9477w2c5nhb1p8vjx4xm3qaw"; })
- (fetchNuGet { pname = "System.Memory"; version = "4.5.3"; sha256 = "0naqahm3wljxb5a911d37mwjqjdxv9l0b49p5dmfyijvni2ppy8a"; })
- (fetchNuGet { pname = "System.Memory"; version = "4.5.4"; sha256 = "14gbbs22mcxwggn0fcfs1b062521azb9fbb7c113x0mq6dzq9h6y"; })
- (fetchNuGet { pname = "System.Memory"; version = "4.5.5"; sha256 = "08jsfwimcarfzrhlyvjjid61j02irx6xsklf32rv57x2aaikvx0h"; })
- (fetchNuGet { pname = "System.Net.Http"; version = "4.1.0"; sha256 = "1i5rqij1icg05j8rrkw4gd4pgia1978mqhjzhsjg69lvwcdfg8yb"; })
- (fetchNuGet { pname = "System.Net.NameResolution"; version = "4.0.0"; sha256 = "0dj3pvpv069nyia28gkl4a0fb7q33hbxz2dg25qvpah3l7pbl0qh"; })
- (fetchNuGet { pname = "System.Net.Primitives"; version = "4.0.11"; sha256 = "10xzzaynkzkakp7jai1ik3r805zrqjxiz7vcagchyxs2v26a516r"; })
- (fetchNuGet { pname = "System.Net.Requests"; version = "4.0.11"; sha256 = "13mka55sa6dg6nw4zdrih44gnp8hnj5azynz47ljsh2791lz3d9h"; })
- (fetchNuGet { pname = "System.Net.Security"; version = "4.0.0"; sha256 = "0ybyfssnm0cri37byhxnkfrzprz77nizbfj553x7s1vry2pnm5gb"; })
- (fetchNuGet { pname = "System.Net.Sockets"; version = "4.1.0"; sha256 = "1385fvh8h29da5hh58jm1v78fzi9fi5vj93vhlm2kvqpfahvpqls"; })
- (fetchNuGet { pname = "System.Net.WebHeaderCollection"; version = "4.0.1"; sha256 = "10bxpxj80c4z00z3ksrfswspq9qqsw8jwxcbzvymzycb97m9b55q"; })
- (fetchNuGet { pname = "System.Numerics.Vectors"; version = "4.1.1"; sha256 = "1xkzrpl700pp0l6dc9fx7cj318i596w0i0qixsbrz5v65fnhbzia"; })
- (fetchNuGet { pname = "System.Numerics.Vectors"; version = "4.4.0"; sha256 = "0rdvma399070b0i46c4qq1h2yvjj3k013sqzkilz4bz5cwmx1rba"; })
- (fetchNuGet { pname = "System.Numerics.Vectors"; version = "4.5.0"; sha256 = "1kzrj37yzawf1b19jq0253rcs8hsq1l2q8g69d7ipnhzb0h97m59"; })
- (fetchNuGet { pname = "System.ObjectModel"; version = "4.0.12"; sha256 = "1sybkfi60a4588xn34nd9a58png36i0xr4y4v4kqpg8wlvy5krrj"; })
- (fetchNuGet { pname = "System.ObjectModel"; version = "4.3.0"; sha256 = "191p63zy5rpqx7dnrb3h7prvgixmk168fhvvkkvhlazncf8r3nc2"; })
- (fetchNuGet { pname = "System.Private.DataContractSerialization"; version = "4.1.1"; sha256 = "1xk9wvgzipssp1393nsg4n16zbr5481k03nkdlj954hzq5jkx89r"; })
- (fetchNuGet { pname = "System.Private.Uri"; version = "4.3.0"; sha256 = "04r1lkdnsznin0fj4ya1zikxiqr0h6r6a1ww2dsm60gqhdrf0mvx"; })
- (fetchNuGet { pname = "System.Private.Uri"; version = "4.3.2"; sha256 = "019s7jz73d236p23mnpfaxxwib019i0v1fbwbkys0hskgddvw7cc"; })
- (fetchNuGet { pname = "System.Reactive"; version = "5.0.0"; sha256 = "1lafmpnadhiwxyd543kraxa3jfdpm6ipblxrjlibym9b1ykpr5ik"; })
- (fetchNuGet { pname = "System.Reactive"; version = "6.0.0"; sha256 = "1mkvx1fwychpczksy6svfmniqhbm3xqblxqik6178l12xgq7aw45"; })
- (fetchNuGet { pname = "System.Reflection"; version = "4.1.0"; sha256 = "1js89429pfw79mxvbzp8p3q93il6rdff332hddhzi5wqglc4gml9"; })
- (fetchNuGet { pname = "System.Reflection"; version = "4.3.0"; sha256 = "0xl55k0mw8cd8ra6dxzh974nxif58s3k1rjv1vbd7gjbjr39j11m"; })
- (fetchNuGet { pname = "System.Reflection.DispatchProxy"; version = "4.0.1"; sha256 = "1maglcnvm3h8bfmx3rvwg4wjda7527iqp38cg1r6vh9japrw1n0r"; })
- (fetchNuGet { pname = "System.Reflection.Emit"; version = "4.0.1"; sha256 = "0ydqcsvh6smi41gyaakglnv252625hf29f7kywy2c70nhii2ylqp"; })
- (fetchNuGet { pname = "System.Reflection.Emit"; version = "4.3.0"; sha256 = "11f8y3qfysfcrscjpjym9msk7lsfxkk4fmz9qq95kn3jd0769f74"; })
- (fetchNuGet { pname = "System.Reflection.Emit.ILGeneration"; version = "4.0.1"; sha256 = "1pcd2ig6bg144y10w7yxgc9d22r7c7ww7qn1frdfwgxr24j9wvv0"; })
- (fetchNuGet { pname = "System.Reflection.Emit.ILGeneration"; version = "4.3.0"; sha256 = "0w1n67glpv8241vnpz1kl14sy7zlnw414aqwj4hcx5nd86f6994q"; })
- (fetchNuGet { pname = "System.Reflection.Emit.Lightweight"; version = "4.0.1"; sha256 = "1s4b043zdbx9k39lfhvsk68msv1nxbidhkq6nbm27q7sf8xcsnxr"; })
- (fetchNuGet { pname = "System.Reflection.Emit.Lightweight"; version = "4.3.0"; sha256 = "0ql7lcakycrvzgi9kxz1b3lljd990az1x6c4jsiwcacrvimpib5c"; })
- (fetchNuGet { pname = "System.Reflection.Extensions"; version = "4.0.1"; sha256 = "0m7wqwq0zqq9gbpiqvgk3sr92cbrw7cp3xn53xvw7zj6rz6fdirn"; })
- (fetchNuGet { pname = "System.Reflection.Extensions"; version = "4.3.0"; sha256 = "02bly8bdc98gs22lqsfx9xicblszr2yan7v2mmw3g7hy6miq5hwq"; })
- (fetchNuGet { pname = "System.Reflection.Metadata"; version = "1.3.0"; sha256 = "1y5m6kryhjpqqm2g3h3b6bzig13wkiw954x3b7icqjm6xypm1x3b"; })
- (fetchNuGet { pname = "System.Reflection.Metadata"; version = "1.6.0"; sha256 = "1wdbavrrkajy7qbdblpbpbalbdl48q3h34cchz24gvdgyrlf15r4"; })
- (fetchNuGet { pname = "System.Reflection.Metadata"; version = "5.0.0"; sha256 = "17qsl5nanlqk9iz0l5wijdn6ka632fs1m1fvx18dfgswm258r3ss"; })
- (fetchNuGet { pname = "System.Reflection.Metadata"; version = "7.0.0"; sha256 = "1wilasn2qmj870h2bhw348lspamm7pbinpb4m89icg113510l00v"; })
- (fetchNuGet { pname = "System.Reflection.Primitives"; version = "4.0.1"; sha256 = "1bangaabhsl4k9fg8khn83wm6yial8ik1sza7401621jc6jrym28"; })
- (fetchNuGet { pname = "System.Reflection.Primitives"; version = "4.3.0"; sha256 = "04xqa33bld78yv5r93a8n76shvc8wwcdgr1qvvjh959g3rc31276"; })
- (fetchNuGet { pname = "System.Reflection.TypeExtensions"; version = "4.1.0"; sha256 = "1bjli8a7sc7jlxqgcagl9nh8axzfl11f4ld3rjqsyxc516iijij7"; })
- (fetchNuGet { pname = "System.Reflection.TypeExtensions"; version = "4.3.0"; sha256 = "0y2ssg08d817p0vdag98vn238gyrrynjdj4181hdg780sif3ykp1"; })
- (fetchNuGet { pname = "System.Resources.Reader"; version = "4.0.0"; sha256 = "1jafi73dcf1lalrir46manq3iy6xnxk2z7gpdpwg4wqql7dv3ril"; })
- (fetchNuGet { pname = "System.Resources.ResourceManager"; version = "4.0.1"; sha256 = "0b4i7mncaf8cnai85jv3wnw6hps140cxz8vylv2bik6wyzgvz7bi"; })
- (fetchNuGet { pname = "System.Resources.ResourceManager"; version = "4.3.0"; sha256 = "0sjqlzsryb0mg4y4xzf35xi523s4is4hz9q4qgdvlvgivl7qxn49"; })
- (fetchNuGet { pname = "System.Resources.Writer"; version = "4.0.0"; sha256 = "07hp218kjdcvpl27djspnixgnacbp9apma61zz3wsca9fx5g3lmv"; })
- (fetchNuGet { pname = "System.Runtime"; version = "4.1.0"; sha256 = "02hdkgk13rvsd6r9yafbwzss8kr55wnj8d5c7xjnp8gqrwc8sn0m"; })
- (fetchNuGet { pname = "System.Runtime"; version = "4.3.0"; sha256 = "066ixvgbf2c929kgknshcxqj6539ax7b9m570cp8n179cpfkapz7"; })
- (fetchNuGet { pname = "System.Runtime"; version = "4.3.1"; sha256 = "03ch4d2acf6q037a4njxpll2kkx3dwzlg07yxr4z5m6j1kqgmm27"; })
- (fetchNuGet { pname = "System.Runtime.CompilerServices.Unsafe"; version = "4.4.0"; sha256 = "0a6ahgi5b148sl5qyfpyw383p3cb4yrkm802k29fsi4mxkiwir29"; })
- (fetchNuGet { pname = "System.Runtime.CompilerServices.Unsafe"; version = "4.7.1"; sha256 = "119br3pd85lq8zcgh4f60jzmv1g976q1kdgi3hvqdlhfbw6siz2j"; })
- (fetchNuGet { pname = "System.Runtime.CompilerServices.Unsafe"; version = "6.0.0"; sha256 = "0qm741kh4rh57wky16sq4m0v05fxmkjjr87krycf5vp9f0zbahbc"; })
- (fetchNuGet { pname = "System.Runtime.Extensions"; version = "4.1.0"; sha256 = "0rw4rm4vsm3h3szxp9iijc3ksyviwsv6f63dng3vhqyg4vjdkc2z"; })
- (fetchNuGet { pname = "System.Runtime.Extensions"; version = "4.3.0"; sha256 = "1ykp3dnhwvm48nap8q23893hagf665k0kn3cbgsqpwzbijdcgc60"; })
- (fetchNuGet { pname = "System.Runtime.Handles"; version = "4.0.1"; sha256 = "1g0zrdi5508v49pfm3iii2hn6nm00bgvfpjq1zxknfjrxxa20r4g"; })
- (fetchNuGet { pname = "System.Runtime.Handles"; version = "4.3.0"; sha256 = "0sw2gfj2xr7sw9qjn0j3l9yw07x73lcs97p8xfc9w1x9h5g5m7i8"; })
- (fetchNuGet { pname = "System.Runtime.InteropServices"; version = "4.1.0"; sha256 = "01kxqppx3dr3b6b286xafqilv4s2n0gqvfgzfd4z943ga9i81is1"; })
- (fetchNuGet { pname = "System.Runtime.InteropServices"; version = "4.3.0"; sha256 = "00hywrn4g7hva1b2qri2s6rabzwgxnbpw9zfxmz28z09cpwwgh7j"; })
- (fetchNuGet { pname = "System.Runtime.InteropServices.RuntimeInformation"; version = "4.0.0"; sha256 = "0glmvarf3jz5xh22iy3w9v3wyragcm4hfdr17v90vs7vcrm7fgp6"; })
- (fetchNuGet { pname = "System.Runtime.Loader"; version = "4.0.0"; sha256 = "0lpfi3psqcp6zxsjk2qyahal7zaawviimc8lhrlswhip2mx7ykl0"; })
- (fetchNuGet { pname = "System.Runtime.Numerics"; version = "4.0.1"; sha256 = "1y308zfvy0l5nrn46mqqr4wb4z1xk758pkk8svbz8b5ij7jnv4nn"; })
- (fetchNuGet { pname = "System.Runtime.Numerics"; version = "4.3.0"; sha256 = "19rav39sr5dky7afygh309qamqqmi9kcwvz3i0c5700v0c5cg61z"; })
- (fetchNuGet { pname = "System.Runtime.Serialization.Formatters"; version = "4.3.0"; sha256 = "114j35n8gcvn3sqv9ar36r1jjq0y1yws9r0yk8i6wm4aq7n9rs0m"; })
- (fetchNuGet { pname = "System.Runtime.Serialization.Primitives"; version = "4.1.1"; sha256 = "042rfjixknlr6r10vx2pgf56yming8lkjikamg3g4v29ikk78h7k"; })
- (fetchNuGet { pname = "System.Runtime.Serialization.Primitives"; version = "4.3.0"; sha256 = "01vv2p8h4hsz217xxs0rixvb7f2xzbh6wv1gzbfykcbfrza6dvnf"; })
- (fetchNuGet { pname = "System.Runtime.Serialization.Xml"; version = "4.1.1"; sha256 = "11747an5gbz821pwahaim3v82gghshnj9b5c4cw539xg5a3gq7rk"; })
- (fetchNuGet { pname = "System.Security.Claims"; version = "4.0.1"; sha256 = "03dw0ls49bvsrffgwycyifjgz0qzr9r85skqhdyhfd51fqf398n6"; })
- (fetchNuGet { pname = "System.Security.Cryptography.Algorithms"; version = "4.2.0"; sha256 = "148s9g5dgm33ri7dnh19s4lgnlxbpwvrw2jnzllq2kijj4i4vs85"; })
- (fetchNuGet { pname = "System.Security.Cryptography.Cng"; version = "4.2.0"; sha256 = "118jijz446kix20blxip0f0q8mhsh9bz118mwc2ch1p6g7facpzc"; })
- (fetchNuGet { pname = "System.Security.Cryptography.Csp"; version = "4.0.0"; sha256 = "1cwv8lqj8r15q81d2pz2jwzzbaji0l28xfrpw29kdpsaypm92z2q"; })
- (fetchNuGet { pname = "System.Security.Cryptography.Encoding"; version = "4.0.0"; sha256 = "0a8y1a5wkmpawc787gfmnrnbzdgxmx1a14ax43jf3rj9gxmy3vk4"; })
- (fetchNuGet { pname = "System.Security.Cryptography.OpenSsl"; version = "4.0.0"; sha256 = "16sx3cig3d0ilvzl8xxgffmxbiqx87zdi8fc73i3i7zjih1a7f4q"; })
- (fetchNuGet { pname = "System.Security.Cryptography.Primitives"; version = "4.0.0"; sha256 = "0i7cfnwph9a10bm26m538h5xcr8b36jscp9sy1zhgifksxz4yixh"; })
- (fetchNuGet { pname = "System.Security.Cryptography.X509Certificates"; version = "4.1.0"; sha256 = "0clg1bv55mfv5dq00m19cp634zx6inm31kf8ppbq1jgyjf2185dh"; })
- (fetchNuGet { pname = "System.Security.Principal"; version = "4.0.1"; sha256 = "1nbzdfqvzzbgsfdd5qsh94d7dbg2v4sw0yx6himyn52zf8z6007p"; })
- (fetchNuGet { pname = "System.Security.Principal.Windows"; version = "4.0.0"; sha256 = "1d3vc8i0zss9z8p4qprls4gbh7q4218l9845kclx7wvw41809k6z"; })
- (fetchNuGet { pname = "System.Text.Encoding"; version = "4.0.11"; sha256 = "1dyqv0hijg265dwxg6l7aiv74102d6xjiwplh2ar1ly6xfaa4iiw"; })
- (fetchNuGet { pname = "System.Text.Encoding"; version = "4.3.0"; sha256 = "1f04lkir4iladpp51sdgmis9dj4y8v08cka0mbmsy0frc9a4gjqr"; })
- (fetchNuGet { pname = "System.Text.Encoding.CodePages"; version = "4.0.1"; sha256 = "00wpm3b9y0k996rm9whxprngm8l500ajmzgy2ip9pgwk0icp06y3"; })
- (fetchNuGet { pname = "System.Text.Encoding.CodePages"; version = "4.5.1"; sha256 = "1z21qyfs6sg76rp68qdx0c9iy57naan89pg7p6i3qpj8kyzn921w"; })
- (fetchNuGet { pname = "System.Text.Encoding.CodePages"; version = "7.0.0"; sha256 = "0sn6hxdjm7bw3xgsmg041ccchsa4sp02aa27cislw3x61dbr68kq"; })
- (fetchNuGet { pname = "System.Text.Encoding.Extensions"; version = "4.0.11"; sha256 = "08nsfrpiwsg9x5ml4xyl3zyvjfdi4mvbqf93kjdh11j4fwkznizs"; })
- (fetchNuGet { pname = "System.Text.Encoding.Extensions"; version = "4.3.0"; sha256 = "11q1y8hh5hrp5a3kw25cb6l00v5l5dvirkz8jr3sq00h1xgcgrxy"; })
- (fetchNuGet { pname = "System.Text.Encodings.Web"; version = "8.0.0"; sha256 = "1wbypkx0m8dgpsaqgyywz4z760xblnwalb241d5qv9kx8m128i11"; })
- (fetchNuGet { pname = "System.Text.Json"; version = "8.0.0"; sha256 = "134savxw0sq7s448jnzw17bxcijsi1v38mirpbb6zfxmqlf04msw"; })
- (fetchNuGet { pname = "System.Text.RegularExpressions"; version = "4.1.0"; sha256 = "1mw7vfkkyd04yn2fbhm38msk7dz2xwvib14ygjsb8dq2lcvr18y7"; })
- (fetchNuGet { pname = "System.Text.RegularExpressions"; version = "4.3.0"; sha256 = "1bgq51k7fwld0njylfn7qc5fmwrk2137gdq7djqdsw347paa9c2l"; })
- (fetchNuGet { pname = "System.Threading"; version = "4.0.11"; sha256 = "19x946h926bzvbsgj28csn46gak2crv2skpwsx80hbgazmkgb1ls"; })
- (fetchNuGet { pname = "System.Threading"; version = "4.3.0"; sha256 = "0rw9wfamvhayp5zh3j7p1yfmx9b5khbf4q50d8k5rk993rskfd34"; })
- (fetchNuGet { pname = "System.Threading.Overlapped"; version = "4.0.1"; sha256 = "0fi79az3vmqdp9mv3wh2phblfjls89zlj6p9nc3i9f6wmfarj188"; })
- (fetchNuGet { pname = "System.Threading.Tasks"; version = "4.0.11"; sha256 = "0nr1r41rak82qfa5m0lhk9mp0k93bvfd7bbd9sdzwx9mb36g28p5"; })
- (fetchNuGet { pname = "System.Threading.Tasks"; version = "4.3.0"; sha256 = "134z3v9abw3a6jsw17xl3f6hqjpak5l682k2vz39spj4kmydg6k7"; })
- (fetchNuGet { pname = "System.Threading.Tasks.Dataflow"; version = "4.6.0"; sha256 = "0a1davr71wssyn4z1hr75lk82wqa0daz0vfwkmg1fm3kckfd72k1"; })
- (fetchNuGet { pname = "System.Threading.Tasks.Extensions"; version = "4.0.0"; sha256 = "1cb51z062mvc2i8blpzmpn9d9mm4y307xrwi65di8ri18cz5r1zr"; })
- (fetchNuGet { pname = "System.Threading.Tasks.Extensions"; version = "4.3.0"; sha256 = "1xxcx2xh8jin360yjwm4x4cf5y3a2bwpn2ygkfkwkicz7zk50s2z"; })
- (fetchNuGet { pname = "System.Threading.Tasks.Extensions"; version = "4.5.4"; sha256 = "0y6ncasgfcgnjrhynaf0lwpkpkmv4a07sswwkwbwb5h7riisj153"; })
- (fetchNuGet { pname = "System.Threading.Tasks.Parallel"; version = "4.0.1"; sha256 = "114wdg32hr46dfsnns3pgs67kcha5jn47p5gg0mhxfn5vrkr2p75"; })
- (fetchNuGet { pname = "System.Threading.Thread"; version = "4.0.0"; sha256 = "1gxxm5fl36pjjpnx1k688dcw8m9l7nmf802nxis6swdaw8k54jzc"; })
- (fetchNuGet { pname = "System.Threading.ThreadPool"; version = "4.0.10"; sha256 = "0fdr61yjcxh5imvyf93n2m3n5g9pp54bnw2l1d2rdl9z6dd31ypx"; })
- (fetchNuGet { pname = "System.Threading.Timer"; version = "4.0.1"; sha256 = "15n54f1f8nn3mjcjrlzdg6q3520571y012mx7v991x2fvp73lmg6"; })
- (fetchNuGet { pname = "System.Xml.ReaderWriter"; version = "4.0.11"; sha256 = "0c6ky1jk5ada9m94wcadih98l6k1fvf6vi7vhn1msjixaha419l5"; })
- (fetchNuGet { pname = "System.Xml.ReaderWriter"; version = "4.3.0"; sha256 = "0c47yllxifzmh8gq6rq6l36zzvw4kjvlszkqa9wq3fr59n0hl3s1"; })
- (fetchNuGet { pname = "System.Xml.XDocument"; version = "4.0.11"; sha256 = "0n4lvpqzy9kc7qy1a4acwwd7b7pnvygv895az5640idl2y9zbz18"; })
- (fetchNuGet { pname = "System.Xml.XDocument"; version = "4.3.0"; sha256 = "08h8fm4l77n0nd4i4fk2386y809bfbwqb7ih9d7564ifcxr5ssxd"; })
- (fetchNuGet { pname = "System.Xml.XmlDocument"; version = "4.0.1"; sha256 = "0ihsnkvyc76r4dcky7v3ansnbyqjzkbyyia0ir5zvqirzan0bnl1"; })
- (fetchNuGet { pname = "System.Xml.XmlDocument"; version = "4.3.0"; sha256 = "0bmz1l06dihx52jxjr22dyv5mxv6pj4852lx68grjm7bivhrbfwi"; })
- (fetchNuGet { pname = "System.Xml.XmlSerializer"; version = "4.0.11"; sha256 = "01nzc3gdslw90qfykq4qzr2mdnqxjl4sj0wp3fixiwdmlmvpib5z"; })
- (fetchNuGet { pname = "System.Xml.XPath"; version = "4.0.1"; sha256 = "0fjqgb6y66d72d5n8qq1h213d9nv2vi8mpv8p28j3m9rccmsh04m"; })
- (fetchNuGet { pname = "System.Xml.XPath.XDocument"; version = "4.0.1"; sha256 = "1fndc70lbjvh8kxs71c7cidfm8plznd61bg4fwpiyq3mq0qg5z0z"; })
- (fetchNuGet { pname = "System.Xml.XPath.XmlDocument"; version = "4.0.1"; sha256 = "0l7yljgif41iv5g56l3nxy97hzzgck2a7rhnfnljhx9b0ry41bvc"; })
- (fetchNuGet { pname = "Tmds.DBus.Protocol"; version = "0.15.0"; sha256 = "0d99kcs7r9cp6gpyc7z230czkkyx4164x86dhy0mca73f2ykc2g2"; })
- (fetchNuGet { pname = "WabiSabi"; version = "1.0.1.2"; sha256 = "1ra1wzl1sgny0bw1r7ykawnlsykd3zm4jd6bjdd00c6sgawss7qv"; })
- (fetchNuGet { pname = "xunit"; version = "2.6.6"; sha256 = "024290yclyq54jrm29bj6vipshq4dxpci9y06b9j8cpbsn7drr5s"; })
- (fetchNuGet { pname = "xunit.abstractions"; version = "2.0.2"; sha256 = "1cfpdhzrmqywsg8w899w9x5bxbhszipsm4791il1gf7cdq4hz463"; })
- (fetchNuGet { pname = "xunit.abstractions"; version = "2.0.3"; sha256 = "00wl8qksgkxld76fgir3ycc5rjqv1sqds6x8yx40927q5py74gfh"; })
- (fetchNuGet { pname = "xunit.analyzers"; version = "1.10.0"; sha256 = "0b4rbxpx4bmbjr18zn5afahx9imhqv0dg76flhjxsqzvx66zjqaf"; })
- (fetchNuGet { pname = "xunit.assert"; version = "2.6.6"; sha256 = "1rkp96b4zdbv38r2hffhcwfp82vcs86a24b09001h4x5ln51bdb5"; })
- (fetchNuGet { pname = "xunit.core"; version = "2.4.0"; sha256 = "1lcy8k62pnmsf15pppr7y940289rygxc0ipif1dsk9k3h5m7vpkn"; })
- (fetchNuGet { pname = "xunit.core"; version = "2.6.6"; sha256 = "0xi254srmvrrqkzq0n74d048hphijsk38gx47r68vm44q1vpzpln"; })
- (fetchNuGet { pname = "xunit.extensibility.core"; version = "2.4.0"; sha256 = "0qd834mv1017j13bjz7g0byiiqzpflnnqhm15zvnk309q48rgfrd"; })
- (fetchNuGet { pname = "xunit.extensibility.core"; version = "2.6.6"; sha256 = "0f8w71b58kbv23b7p6083jxy4pmpsa59r8xqpp2j71300cyp2rl0"; })
- (fetchNuGet { pname = "xunit.extensibility.execution"; version = "2.4.0"; sha256 = "0bpy9iw4dkx884ld10dlijlyfp13afxrb3akhprdvazhmh8lj53j"; })
- (fetchNuGet { pname = "xunit.extensibility.execution"; version = "2.6.6"; sha256 = "0n295fxvzwp4d27qa644m55klapvcmynb240rwcjr95yvgsfzjz4"; })
- (fetchNuGet { pname = "xunit.runner.visualstudio"; version = "2.5.6"; sha256 = "1knl6myb5zip2yii1mm5kxvkq81z3zj7dkn8zlqbb4ylaxslzf88"; })
-]
diff --git a/deps.nix b/deps.nix
index d2e0a99fbc..73640be8f7 100644
--- a/deps.nix
+++ b/deps.nix
@@ -3,9 +3,9 @@
{ fetchNuGet }: [
(fetchNuGet { pname = "LinqKit.Core"; version = "1.2.5"; sha256 = "15imfl77sfii5nz8i6pi3h5izhxyp2dihx13g2fzqnky1fj12gnk"; })
- (fetchNuGet { pname = "Microsoft.AspNetCore.JsonPatch"; version = "8.0.0"; sha256 = "1z052fqfwi28bd2p6045k7px2kad0nn3w6bglwf367lmf095pjaz"; })
- (fetchNuGet { pname = "Microsoft.AspNetCore.Mvc.NewtonsoftJson"; version = "8.0.0"; sha256 = "11rcqgl620mca0hz909vg9994iy3vizn77nr8q6jybn7v7pksyp0"; })
- (fetchNuGet { pname = "Microsoft.AspNetCore.WebUtilities"; version = "8.0.0"; sha256 = "126xyqxsfhr6qn5r8fm13yybsqnzy1sbjw7l16xglg90jm62m33v"; })
+ (fetchNuGet { pname = "Microsoft.AspNetCore.JsonPatch"; version = "8.0.19"; sha256 = "1866r07yjr6zrjyvd8a1pvczmifavvvm1hrh6i37fa8jafywjj0g"; })
+ (fetchNuGet { pname = "Microsoft.AspNetCore.Mvc.NewtonsoftJson"; version = "8.0.19"; sha256 = "0p0qf5qw6qib76ky3cpi3gcz15nynd17ys0alw3sxmlika7c9p73"; })
+ (fetchNuGet { pname = "Microsoft.AspNetCore.WebUtilities"; version = "8.0.19"; sha256 = "1dgbkd97chi7jgmbj24j9qf44b58q181nhidyxi3nwd5hlj6358d"; })
(fetchNuGet { pname = "Microsoft.Bcl.AsyncInterfaces"; version = "6.0.0"; sha256 = "15gqy2m14fdlvy1g59207h5kisznm355kbw010gy19vh47z8gpz3"; })
(fetchNuGet { pname = "Microsoft.Build"; version = "15.3.409"; sha256 = "0vzq6csp2yys9s96c7i37bjml439rdi47g8f5rzqdr7xf5a1jk81"; })
(fetchNuGet { pname = "Microsoft.Build.Framework"; version = "15.3.409"; sha256 = "1dhanwb9ihbfay85xj7cwn0byzmmdz94hqfi3q6r1ncwdjd8y1s2"; })
@@ -15,40 +15,35 @@
(fetchNuGet { pname = "Microsoft.CodeAnalysis.BannedApiAnalyzers"; version = "3.3.4"; sha256 = "1vzrni7n94f17bzc13lrvcxvgspx9s25ap1p005z6i1ikx6wgx30"; })
(fetchNuGet { pname = "Microsoft.CSharp"; version = "4.3.0"; sha256 = "0gw297dgkh0al1zxvgvncqs0j15lsna9l1wpqas4rflmys440xvb"; })
(fetchNuGet { pname = "Microsoft.CSharp"; version = "4.7.0"; sha256 = "0gd67zlw554j098kabg887b5a6pq9kzavpa3jjy5w53ccjzjfy8j"; })
- (fetchNuGet { pname = "Microsoft.Data.Sqlite"; version = "8.0.0"; sha256 = "02y3y3x4ggxcjcrnazwxdi08xmwabaalrm40rwjdij072x5va3yi"; })
- (fetchNuGet { pname = "Microsoft.Data.Sqlite.Core"; version = "8.0.0"; sha256 = "05qjnzk1fxybks92y93487l3mj5nghjcwiy360xjgk3jykz3rv39"; })
+ (fetchNuGet { pname = "Microsoft.Data.Sqlite"; version = "8.0.19"; sha256 = "1d18b01vhj1rxp88wwacp532vg6f88lyhbfvf4nrihq2xvbsg7l9"; })
+ (fetchNuGet { pname = "Microsoft.Data.Sqlite.Core"; version = "8.0.19"; sha256 = "1pxazx6c2167cm6kdcl9rhzwi29gpzxmzc9idll953kckykn053d"; })
(fetchNuGet { pname = "Microsoft.Extensions.ApiDescription.Server"; version = "6.0.5"; sha256 = "1pi2bm3cm0a7jzqzmfc2r7bpcdkmk3hhjfvb2c81j7wl7xdw3624"; })
(fetchNuGet { pname = "Microsoft.Extensions.Caching.Abstractions"; version = "8.0.0"; sha256 = "04m6ywsf9731z24nfd14z0ah8xl06619ba7mkdb4vg8h5jpllsn4"; })
(fetchNuGet { pname = "Microsoft.Extensions.Configuration"; version = "8.0.0"; sha256 = "080kab87qgq2kh0ijry5kfdiq9afyzb8s0k3jqi5zbbi540yq4zl"; })
(fetchNuGet { pname = "Microsoft.Extensions.Configuration.Abstractions"; version = "8.0.0"; sha256 = "1jlpa4ggl1gr5fs7fdcw04li3y3iy05w3klr9lrrlc7v8w76kq71"; })
(fetchNuGet { pname = "Microsoft.Extensions.Configuration.Binder"; version = "8.0.0"; sha256 = "1m0gawiz8f5hc3li9vd5psddlygwgkiw13d7div87kmkf4idza8r"; })
(fetchNuGet { pname = "Microsoft.Extensions.Configuration.Binder"; version = "8.0.2"; sha256 = "08gdj4ljvcax1lq9prmrasm3kdsw385ayah1fhd8dpq2x9b78q38"; })
- (fetchNuGet { pname = "Microsoft.Extensions.DependencyInjection"; version = "8.0.0"; sha256 = "0i7qziz0iqmbk8zzln7kx9vd0lbx1x3va0yi3j1bgkjir13h78ps"; })
(fetchNuGet { pname = "Microsoft.Extensions.DependencyInjection"; version = "8.0.1"; sha256 = "0dc5nwq2h9pskbq2cyc8cj6gwqi4b032pakw9ylg33dycj6k9n1v"; })
- (fetchNuGet { pname = "Microsoft.Extensions.DependencyInjection.Abstractions"; version = "8.0.0"; sha256 = "1zw0bpp5742jzx03wvqc8csnvsbgdqi0ls9jfc5i2vd3cl8b74pg"; })
(fetchNuGet { pname = "Microsoft.Extensions.DependencyInjection.Abstractions"; version = "8.0.2"; sha256 = "01i66wklw882p6xgpm3pfw8maw977y0pxfzhakd10pr4008xzwji"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Diagnostics"; version = "8.0.0"; sha256 = "0ghwkld91k20hcbmzg2137w81mzzdh8hfaapdwckhza0vipya4kw"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Diagnostics.Abstractions"; version = "8.0.0"; sha256 = "15m4j6w9n8h0mj7hlfzb83hd3wn7aq1s7fxbicm16slsjfwzj82i"; })
+ (fetchNuGet { pname = "Microsoft.Extensions.Diagnostics"; version = "8.0.1"; sha256 = "1dw8wjsjmxlrvv62af18yc5x2kp9sfkzbpx7qycci54m4qs8gdha"; })
+ (fetchNuGet { pname = "Microsoft.Extensions.Diagnostics.Abstractions"; version = "8.0.1"; sha256 = "1ga0fna5kzv0z1pmxi7f83k71kma2cxndqc6ymc93a1w21gdb43p"; })
(fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Abstractions"; version = "2.0.0"; sha256 = "0d6y5isjy6jpf4w3f3w89cwh9p40glzhwvm7cwhx05wkqd8bk9w4"; })
(fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Abstractions"; version = "8.0.0"; sha256 = "1idq65fxwcn882c06yci7nscy9i0rgw6mqjrl7362prvvsd9f15r"; })
(fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Physical"; version = "2.0.0"; sha256 = "0l0l92g7sq4122n139av1pn1jl6wlw92hjmdnr47xdss0ndmwrs3"; })
(fetchNuGet { pname = "Microsoft.Extensions.FileSystemGlobbing"; version = "2.0.0"; sha256 = "02lzy6r14ghwfwm384xajq08vv3pl3ww0mi5isrr10vivhijhgg4"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Hosting.Abstractions"; version = "8.0.0"; sha256 = "00d5dwmzw76iy8z40ly01hy9gly49a7rpf7k7m99vrid1kxp346h"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Http"; version = "8.0.0"; sha256 = "09hmkhxipbpfmwz9q80746zp6cvbx1cqffxr5xjxv5cbjg5662aj"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging"; version = "8.0.0"; sha256 = "0nppj34nmq25gnrg0wh1q22y4wdqbih4ax493f226azv8mkp9s1i"; })
+ (fetchNuGet { pname = "Microsoft.Extensions.Hosting.Abstractions"; version = "8.0.1"; sha256 = "0l0ihg0mw5cvsxdm00nsqyqgh7ldb46qq9m4ziahh1dgvcpibcpx"; })
+ (fetchNuGet { pname = "Microsoft.Extensions.Http"; version = "8.0.1"; sha256 = "0ykpqlb508aadr5x3gahzgf9hfpqgh6jafs19dw9gp633f2g1hs9"; })
(fetchNuGet { pname = "Microsoft.Extensions.Logging"; version = "8.0.1"; sha256 = "11g8lgdp0myxxmwkqdplriigh1ni1sjbyz0dbqx0y4jhig1xaixy"; })
(fetchNuGet { pname = "Microsoft.Extensions.Logging.Abstractions"; version = "1.0.0"; sha256 = "1sh9bidmhy32gkz6fkli79mxv06546ybrzppfw5v2aq0bda1ghka"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Logging.Abstractions"; version = "8.0.0"; sha256 = "1klcqhg3hk55hb6vmjiq2wgqidsl81aldw0li2z98lrwx26msrr6"; })
(fetchNuGet { pname = "Microsoft.Extensions.Logging.Abstractions"; version = "8.0.2"; sha256 = "15w02lha7q927av6lbmrc8xkrf72nvx6b99v1ywqd0c1gpqmwykh"; })
(fetchNuGet { pname = "Microsoft.Extensions.Logging.Configuration"; version = "8.0.1"; sha256 = "18driq681dy0sy22vb5x23lhnh12wig8p2s53pv5npl4dlj5nqhk"; })
(fetchNuGet { pname = "Microsoft.Extensions.Logging.Console"; version = "8.0.1"; sha256 = "11d4914yp38yd8cd6xwcswc8gayvrrz717qx0zvxh32va8bn3n6s"; })
(fetchNuGet { pname = "Microsoft.Extensions.Logging.Debug"; version = "8.0.1"; sha256 = "1a143snmfpgg79cd0qgb3c1ifazx23m0470iajwkqvk51q36m8c0"; })
- (fetchNuGet { pname = "Microsoft.Extensions.Options"; version = "8.0.0"; sha256 = "0p50qn6zhinzyhq9sy5svnmqqwhw2jajs2pbjh9sah504wjvhscz"; })
(fetchNuGet { pname = "Microsoft.Extensions.Options"; version = "8.0.2"; sha256 = "0as39ml1idgp42yvh725ddqp4illq87adzd1ymzx6xjxsxsjadq2"; })
(fetchNuGet { pname = "Microsoft.Extensions.Options.ConfigurationExtensions"; version = "8.0.0"; sha256 = "04nm8v5a3zp0ill7hjnwnja3s2676b4wffdri8hdk2341p7mp403"; })
(fetchNuGet { pname = "Microsoft.Extensions.Primitives"; version = "2.0.0"; sha256 = "1xppr5jbny04slyjgngxjdm0maxdh47vq481ps944d7jrfs0p3mb"; })
(fetchNuGet { pname = "Microsoft.Extensions.Primitives"; version = "8.0.0"; sha256 = "0aldaz5aapngchgdr7dax9jw5wy7k7hmjgjpfgfv1wfif27jlkqm"; })
- (fetchNuGet { pname = "Microsoft.Net.Http.Headers"; version = "8.0.0"; sha256 = "0k5fcf00g8hpwxx4pkwa9iyy4sdspqx8zw9p3r3i6xyijsmk0ah7"; })
+ (fetchNuGet { pname = "Microsoft.Net.Http.Headers"; version = "8.0.19"; sha256 = "0grz1xapl7z032qr8fc25i61fa7zqwffx0gwm5r4q8pac3q9nc25"; })
(fetchNuGet { pname = "Microsoft.NETCore.App"; version = "2.0.5"; sha256 = "0qb7k624w7l0zhapdp519ymqg84a67r8zyd8cpj42hywsgb0dqv6"; })
(fetchNuGet { pname = "Microsoft.NETCore.DotNetAppHost"; version = "2.0.5"; sha256 = "00bsxdg9c8msjxyffvfi8siqk8v2m7ca8fqy1npv7b2pzg3byjws"; })
(fetchNuGet { pname = "Microsoft.NETCore.DotNetHostPolicy"; version = "2.0.5"; sha256 = "0v5csskiwpk8kz8wclqad8kcjmxr7ik4w99wl05740qvaag3qysk"; })
@@ -64,7 +59,7 @@
(fetchNuGet { pname = "Microsoft.Win32.Primitives"; version = "4.0.1"; sha256 = "1n8ap0cmljbqskxpf8fjzn7kh1vvlndsa75k01qig26mbw97k2q7"; })
(fetchNuGet { pname = "Microsoft.Win32.Registry"; version = "4.0.0"; sha256 = "1spf4m9pikkc19544p29a47qnhcd885klncahz133hbnyqbkmz9k"; })
(fetchNuGet { pname = "Microsoft.Win32.SystemEvents"; version = "8.0.0"; sha256 = "05392f41ijgn17y8pbjcx535l1k09krnq3xdp60kyq568sn6xk2i"; })
- (fetchNuGet { pname = "NBitcoin"; version = "7.0.42.2"; sha256 = "01hrzbjz0cwz7qnqqwi3rfavdccj095r0q1w7x60izs9wmwlgdni"; })
+ (fetchNuGet { pname = "NBitcoin"; version = "9.0.0"; sha256 = "1i2vzz7bgm4s9ipafaifqz00g13cwxrq24dkrzr6asrif01qxfhl"; })
(fetchNuGet { pname = "NBitcoin.Secp256k1"; version = "3.1.0"; sha256 = "1mbn757gds2019j7d3p59ykwibxvkz5dhxagy5f4zzvz7537a6my"; })
(fetchNuGet { pname = "NBitcoin.Secp256k1"; version = "3.1.4"; sha256 = "0gqp6k7v3pfg6xx6w30yzj8yj0pi6q6kwpvyiq710rra82y7zx8g"; })
(fetchNuGet { pname = "NETStandard.Library"; version = "1.6.0"; sha256 = "0nmmv4yw7gw04ik8ialj3ak0j6pxa9spih67hnn1h2c38ba8h58k"; })
@@ -104,7 +99,6 @@
(fetchNuGet { pname = "System.Diagnostics.Debug"; version = "4.0.11"; sha256 = "0gmjghrqmlgzxivd2xl50ncbglb7ljzb66rlx8ws6dv8jm0d5siz"; })
(fetchNuGet { pname = "System.Diagnostics.Debug"; version = "4.3.0"; sha256 = "00yjlf19wjydyr6cfviaph3vsjzg3d5nvnya26i2fvfg53sknh3y"; })
(fetchNuGet { pname = "System.Diagnostics.DiagnosticSource"; version = "4.0.0"; sha256 = "1n6c3fbz7v8d3pn77h4v5wvsfrfg7v1c57lg3nff3cjyh597v23m"; })
- (fetchNuGet { pname = "System.Diagnostics.DiagnosticSource"; version = "8.0.0"; sha256 = "0nzra1i0mljvmnj1qqqg37xs7bl71fnpl68nwmdajchh65l878zr"; })
(fetchNuGet { pname = "System.Diagnostics.FileVersionInfo"; version = "4.0.0"; sha256 = "1s5vxhy7i09bmw51kxqaiz9zaj9am8wsjyz13j85sp23z267hbv3"; })
(fetchNuGet { pname = "System.Diagnostics.Process"; version = "4.1.0"; sha256 = "061lrcs7xribrmq7kab908lww6kn2xn1w3rdc41q189y0jibl19s"; })
(fetchNuGet { pname = "System.Diagnostics.Tools"; version = "4.0.1"; sha256 = "19cknvg07yhakcvpxg3cxa0bwadplin6kyxd8mpjjpwnp56nl85x"; })
@@ -191,7 +185,7 @@
(fetchNuGet { pname = "System.Text.Encoding.CodePages"; version = "4.0.1"; sha256 = "00wpm3b9y0k996rm9whxprngm8l500ajmzgy2ip9pgwk0icp06y3"; })
(fetchNuGet { pname = "System.Text.Encoding.Extensions"; version = "4.0.11"; sha256 = "08nsfrpiwsg9x5ml4xyl3zyvjfdi4mvbqf93kjdh11j4fwkznizs"; })
(fetchNuGet { pname = "System.Text.Encoding.Extensions"; version = "4.3.0"; sha256 = "11q1y8hh5hrp5a3kw25cb6l00v5l5dvirkz8jr3sq00h1xgcgrxy"; })
- (fetchNuGet { pname = "System.Text.Json"; version = "8.0.5"; sha256 = "1brzf0drzrzj3arh5yjyyjh7fzk9di2vksvkxa9xb89rikknib68"; })
+ (fetchNuGet { pname = "System.Text.Json"; version = "8.0.6"; sha256 = "1sxmdc40jss7xjr1hwban81868nyffcc0mp05s9xyfyhg0bxcgd8"; })
(fetchNuGet { pname = "System.Text.RegularExpressions"; version = "4.1.0"; sha256 = "1mw7vfkkyd04yn2fbhm38msk7dz2xwvib14ygjsb8dq2lcvr18y7"; })
(fetchNuGet { pname = "System.Text.RegularExpressions"; version = "4.3.0"; sha256 = "1bgq51k7fwld0njylfn7qc5fmwrk2137gdq7djqdsw347paa9c2l"; })
(fetchNuGet { pname = "System.Threading"; version = "4.0.11"; sha256 = "19x946h926bzvbsgj28csn46gak2crv2skpwsx80hbgazmkgb1ls"; })