Remove some mapping boilerplate
MODIFY
WalletWasabi.Gui/Config.cs
WalletWasabi.Gui/Config.cs
@@ -2,6 +2,7 @@ using NBitcoin;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
+using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
@@ -19,49 +20,62 @@ namespace WalletWasabi.Gui
[JsonObject(MemberSerialization.OptIn)]
public class Config : IConfig
{
+ public const int DefaultPrivacyLevelSome = 2;
+ public const int DefaultPrivacyLevelFine = 21;
+ public const int DefaultPrivacyLevelStrong = 50;
+ public const int DefaultMixUntilAnonymitySet = 50;
+ public const int DefaultTorSock5Port = 9050;
+ public static readonly Money DefaultDustThreshold = Money.Coins(0.0001m);
/// <inheritdoc />
public string FilePath { get; private set; }
[JsonProperty(PropertyName = "Network")]
[JsonConverter(typeof(NetworkJsonConverter))]
- public Network Network { get; internal set; }
+ public Network Network { get; internal set; } = Network.Main;
- [JsonProperty(PropertyName = "MainNetBackendUriV3")]
+ [DefaultValue("http://wasabiukrxmkdgve5kynjztuovbg43uxcbcxn6y2okcrsg7gb6jdmbad.onion/")]
+ [JsonProperty(PropertyName = "MainNetBackendUriV3", DefaultValueHandling = DefaultValueHandling.Populate)]
public string MainNetBackendUriV3 { get; private set; }
- [JsonProperty(PropertyName = "TestNetBackendUriV3")]
+ [DefaultValue("http://testwnp3fugjln6vh5vpj7mvq3lkqqwjj3c2aafyu7laxz42kgwh2rad.onion/")]
+ [JsonProperty(PropertyName = "TestNetBackendUriV3", DefaultValueHandling = DefaultValueHandling.Populate)]
public string TestNetBackendUriV3 { get; private set; }
- [JsonProperty(PropertyName = "MainNetFallbackBackendUri")]
+ [DefaultValue("https://wasabiwallet.io/")]
+ [JsonProperty(PropertyName = "MainNetFallbackBackendUri", DefaultValueHandling = DefaultValueHandling.Populate)]
public string MainNetFallbackBackendUri { get; private set; }
- [JsonProperty(PropertyName = "TestNetFallbackBackendUri")]
+ [DefaultValue("https://wasabiwallet.co/")]
+ [JsonProperty(PropertyName = "TestNetFallbackBackendUri", DefaultValueHandling = DefaultValueHandling.Populate)]
public string TestNetFallbackBackendUri { get; private set; }
- [JsonProperty(PropertyName = "RegTestBackendUriV3")]
+ [DefaultValue("http://localhost:37127/")]
+ [JsonProperty(PropertyName = "RegTestBackendUriV3", DefaultValueHandling = DefaultValueHandling.Populate)]
public string RegTestBackendUriV3 { get; private set; }
- [JsonProperty(PropertyName = "UseTor")]
- public bool? UseTor { get; internal set; }
+ [DefaultValue(true)]
+ [JsonProperty(PropertyName = "UseTor", DefaultValueHandling = DefaultValueHandling.Populate)]
+ public bool UseTor { get; internal set; }
[JsonProperty(PropertyName = "TorSocks5EndPoint")]
[JsonConverter(typeof(EndPointJsonConverter), Constants.DefaultTorSocksPort)]
- public EndPoint TorSocks5EndPoint { get; internal set; }
+ public EndPoint TorSocks5EndPoint { get; internal set; } = new IPEndPoint(IPAddress.Loopback, Constants.DefaultTorSocksPort);
[JsonProperty(PropertyName = "MainNetBitcoinP2pEndPoint")]
[JsonConverter(typeof(EndPointJsonConverter), Constants.DefaultMainNetBitcoinP2pPort)]
- public EndPoint MainNetBitcoinP2pEndPoint { get; internal set; }
+ public EndPoint MainNetBitcoinP2pEndPoint { get; internal set; } = new IPEndPoint(IPAddress.Loopback, Constants.DefaultMainNetBitcoinP2pPort);
[JsonProperty(PropertyName = "TestNetBitcoinP2pEndPoint")]
[JsonConverter(typeof(EndPointJsonConverter), Constants.DefaultTestNetBitcoinP2pPort)]
- public EndPoint TestNetBitcoinP2pEndPoint { get; internal set; }
+ public EndPoint TestNetBitcoinP2pEndPoint { get; internal set; } = new IPEndPoint(IPAddress.Loopback, Constants.DefaultTestNetBitcoinP2pPort);
[JsonProperty(PropertyName = "RegTestBitcoinP2pEndPoint")]
[JsonConverter(typeof(EndPointJsonConverter), Constants.DefaultRegTestBitcoinP2pPort)]
- public EndPoint RegTestBitcoinP2pEndPoint { get; internal set; }
+ public EndPoint RegTestBitcoinP2pEndPoint { get; internal set; } = new IPEndPoint(IPAddress.Loopback, Constants.DefaultRegTestBitcoinP2pPort);
- [JsonProperty(PropertyName = "MixUntilAnonymitySet")]
- public int? MixUntilAnonymitySet
+ [DefaultValue(DefaultMixUntilAnonymitySet)]
+ [JsonProperty(PropertyName = "MixUntilAnonymitySet", DefaultValueHandling = DefaultValueHandling.Populate)]
+ public int MixUntilAnonymitySet
{
get => _mixUntilAnonymitySet;
internal set
@@ -69,16 +83,17 @@ namespace WalletWasabi.Gui
if (_mixUntilAnonymitySet != value)
{
_mixUntilAnonymitySet = value;
- if (value.HasValue && ServiceConfiguration != default)
+ if (ServiceConfiguration != default)
{
- ServiceConfiguration.MixUntilAnonymitySet = value.Value;
+ ServiceConfiguration.MixUntilAnonymitySet = value;
}
}
}
}
- [JsonProperty(PropertyName = "PrivacyLevelSome")]
- public int? PrivacyLevelSome
+ [DefaultValue(DefaultPrivacyLevelSome)]
+ [JsonProperty(PropertyName = "PrivacyLevelSome", DefaultValueHandling = DefaultValueHandling.Populate)]
+ public int PrivacyLevelSome
{
get => _privacyLevelSome;
internal set
@@ -86,16 +101,17 @@ namespace WalletWasabi.Gui
if (_privacyLevelSome != value)
{
_privacyLevelSome = value;
- if (value.HasValue && ServiceConfiguration != default)
+ if (ServiceConfiguration != default)
{
- ServiceConfiguration.PrivacyLevelSome = value.Value;
+ ServiceConfiguration.PrivacyLevelSome = value;
}
}
}
}
- [JsonProperty(PropertyName = "PrivacyLevelFine")]
- public int? PrivacyLevelFine
+ [DefaultValue(DefaultPrivacyLevelFine)]
+ [JsonProperty(PropertyName = "PrivacyLevelFine", DefaultValueHandling = DefaultValueHandling.Populate)]
+ public int PrivacyLevelFine
{
get => _privacyLevelFine;
internal set
@@ -103,16 +119,17 @@ namespace WalletWasabi.Gui
if (_privacyLevelFine != value)
{
_privacyLevelFine = value;
- if (value.HasValue && ServiceConfiguration != default)
+ if (ServiceConfiguration != default)
{
- ServiceConfiguration.PrivacyLevelFine = value.Value;
+ ServiceConfiguration.PrivacyLevelFine = value;
}
}
}
}
- [JsonProperty(PropertyName = "PrivacyLevelStrong")]
- public int? PrivacyLevelStrong
+ [DefaultValue(DefaultPrivacyLevelStrong)]
+ [JsonProperty(PropertyName = "PrivacyLevelStrong", DefaultValueHandling = DefaultValueHandling.Populate)]
+ public int PrivacyLevelStrong
{
get => _privacyLevelStrong;
internal set
@@ -120,9 +137,9 @@ namespace WalletWasabi.Gui
if (_privacyLevelStrong != value)
{
_privacyLevelStrong = value;
- if (value.HasValue && ServiceConfiguration != default)
+ if (ServiceConfiguration != default)
{
- ServiceConfiguration.PrivacyLevelStrong = value.Value;
+ ServiceConfiguration.PrivacyLevelStrong = value;
}
}
}
@@ -130,7 +147,7 @@ namespace WalletWasabi.Gui
[JsonProperty(PropertyName = "DustThreshold")]
[JsonConverter(typeof(MoneyBtcJsonConverter))]
- public Money DustThreshold { get; internal set; }
+ public Money DustThreshold { get; internal set; } = DefaultDustThreshold;
private Uri _backendUri;
private Uri _fallbackBackendUri;
@@ -188,10 +205,10 @@ namespace WalletWasabi.Gui
return _fallbackBackendUri;
}
- private int? _mixUntilAnonymitySet;
- private int? _privacyLevelSome;
- private int? _privacyLevelFine;
- private int? _privacyLevelStrong;
+ private int _mixUntilAnonymitySet;
+ private int _privacyLevelSome;
+ private int _privacyLevelFine;
+ private int _privacyLevelStrong;
public EndPoint GetBitcoinP2pEndPoint()
{
@@ -239,27 +256,7 @@ namespace WalletWasabi.Gui
public async Task LoadOrCreateDefaultFileAsync()
{
AssertFilePathSet();
-
- Network = Network.Main;
-
- MainNetBackendUriV3 = "http://wasabiukrxmkdgve5kynjztuovbg43uxcbcxn6y2okcrsg7gb6jdmbad.onion/";
- TestNetBackendUriV3 = "http://testwnp3fugjln6vh5vpj7mvq3lkqqwjj3c2aafyu7laxz42kgwh2rad.onion/";
- MainNetFallbackBackendUri = "https://wasabiwallet.io/";
- TestNetFallbackBackendUri = "https://wasabiwallet.co/";
- RegTestBackendUriV3 = "http://localhost:37127/";
-
- UseTor = true;
- TorSocks5EndPoint = new IPEndPoint(IPAddress.Loopback, Constants.DefaultTorSocksPort);
-
- MainNetBitcoinP2pEndPoint = new IPEndPoint(IPAddress.Loopback, Constants.DefaultMainNetBitcoinP2pPort);
- TestNetBitcoinP2pEndPoint = new IPEndPoint(IPAddress.Loopback, Constants.DefaultTestNetBitcoinP2pPort);
- RegTestBitcoinP2pEndPoint = new IPEndPoint(IPAddress.Loopback, Constants.DefaultRegTestBitcoinP2pPort);
-
- MixUntilAnonymitySet = 50;
- PrivacyLevelSome = 2;
- PrivacyLevelFine = 21;
- PrivacyLevelStrong = 50;
- DustThreshold = Money.Coins(0.0001m);
+ JsonConvert.PopulateObject("{}", this);
if (!File.Exists(FilePath))
{
@@ -270,7 +267,7 @@ namespace WalletWasabi.Gui
await LoadFileAsync();
}
- ServiceConfiguration = new ServiceConfiguration(MixUntilAnonymitySet.Value, PrivacyLevelSome.Value, PrivacyLevelFine.Value, PrivacyLevelStrong.Value, GetBitcoinP2pEndPoint(), DustThreshold);
+ ServiceConfiguration = new ServiceConfiguration(MixUntilAnonymitySet, PrivacyLevelSome, PrivacyLevelFine, PrivacyLevelStrong, GetBitcoinP2pEndPoint(), DustThreshold);
// Just debug convenience.
_backendUri = GetCurrentBackendUri();
@@ -278,33 +275,45 @@ namespace WalletWasabi.Gui
await ToFileAsync();
}
+ public void SetP2PEndpoint(EndPoint endPoint)
+ {
+ switch (Network.Name)
+ {
+ case "Main":
+ MainNetBitcoinP2pEndPoint = endPoint;
+ break;
+ case "TestNet":
+ TestNetBitcoinP2pEndPoint = endPoint;
+ break;
+ case "RegTest":
+ RegTestBitcoinP2pEndPoint = endPoint;
+ break;
+ default:
+ throw new NotSupportedException("Unsupported network");
+ }
+ }
+
+ public EndPoint GetP2PEndpoint()
+ {
+ switch (Network.Name)
+ {
+ case "Main":
+ return MainNetBitcoinP2pEndPoint;
+ case "TestNet":
+ return TestNetBitcoinP2pEndPoint;
+ case "RegTest":
+ return RegTestBitcoinP2pEndPoint;
+ default:
+ throw new NotSupportedException("Unsupported network");
+ }
+ }
+
public async Task LoadFileAsync()
{
string jsonString = await File.ReadAllTextAsync(FilePath, Encoding.UTF8);
var config = JsonConvert.DeserializeObject<Config>(jsonString);
-
- Network = config?.Network ?? Network;
-
- MainNetBackendUriV3 = config?.MainNetBackendUriV3 ?? MainNetBackendUriV3;
- TestNetBackendUriV3 = config?.TestNetBackendUriV3 ?? TestNetBackendUriV3;
- MainNetFallbackBackendUri = config?.MainNetFallbackBackendUri ?? MainNetFallbackBackendUri;
- TestNetFallbackBackendUri = config?.TestNetFallbackBackendUri ?? TestNetFallbackBackendUri;
- RegTestBackendUriV3 = config?.RegTestBackendUriV3 ?? RegTestBackendUriV3;
-
- UseTor = config?.UseTor ?? UseTor;
- TorSocks5EndPoint = config?.TorSocks5EndPoint ?? TorSocks5EndPoint;
-
- MainNetBitcoinP2pEndPoint = config?.MainNetBitcoinP2pEndPoint ?? MainNetBitcoinP2pEndPoint;
- TestNetBitcoinP2pEndPoint = config?.TestNetBitcoinP2pEndPoint ?? TestNetBitcoinP2pEndPoint;
- RegTestBitcoinP2pEndPoint = config?.RegTestBitcoinP2pEndPoint ?? RegTestBitcoinP2pEndPoint;
-
- MixUntilAnonymitySet = config?.MixUntilAnonymitySet ?? MixUntilAnonymitySet;
- PrivacyLevelSome = config?.PrivacyLevelSome ?? PrivacyLevelSome;
- PrivacyLevelFine = config?.PrivacyLevelFine ?? PrivacyLevelFine;
- PrivacyLevelStrong = config?.PrivacyLevelStrong ?? PrivacyLevelStrong;
-
- DustThreshold = config?.DustThreshold ?? DustThreshold;
+ JsonConvert.PopulateObject(jsonString, this);
ServiceConfiguration = config?.ServiceConfiguration ?? ServiceConfiguration;
@@ -317,6 +326,12 @@ namespace WalletWasabi.Gui
}
}
+ public void CopyFrom(Config config)
+ {
+ var configSerialized = JsonConvert.SerializeObject(config);
+ JsonConvert.PopulateObject(configSerialized, this);
+ }
+
/// <inheritdoc />
public async Task<bool> CheckFileChangeAsync()
{
@@ -328,10 +343,16 @@ namespace WalletWasabi.Gui
}
string jsonString = await File.ReadAllTextAsync(FilePath, Encoding.UTF8);
- var newConfig = JsonConvert.DeserializeObject<JObject>(jsonString);
- var currentConfig = JObject.FromObject(this);
+ var newConfig = JsonConvert.DeserializeObject<Config>(jsonString);
- return !JToken.DeepEquals(newConfig, currentConfig);
+ return !AreDeepEqual(newConfig);
+ }
+
+ public bool AreDeepEqual(Config otherConfig)
+ {
+ var currentConfig = JObject.FromObject(this);
+ var otherConfigJson = JObject.FromObject(otherConfig);
+ return JToken.DeepEquals(otherConfigJson, currentConfig);
}
/// <inheritdoc />
@@ -397,13 +418,13 @@ namespace WalletWasabi.Gui
return 0;
case TargetPrivacy.Some:
- return PrivacyLevelSome.Value;
+ return PrivacyLevelSome;
case TargetPrivacy.Fine:
- return PrivacyLevelFine.Value;
+ return PrivacyLevelFine;
case TargetPrivacy.Strong:
- return PrivacyLevelStrong.Value;
+ return PrivacyLevelStrong;
}
return 0;
}

MODIFY
WalletWasabi.Gui/Global.cs
WalletWasabi.Gui/Global.cs
@@ -153,7 +153,7 @@ namespace WalletWasabi.Gui
var blocksFolderPath = Path.Combine(DataDir, $"Blocks{Network}");
var connectionParameters = new NodeConnectionParameters { UserAgent = "/Satoshi:0.18.0/" };
- if (Config.UseTor.Value)
+ if (Config.UseTor)
{
Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.TorSocks5EndPoint);
}
@@ -187,7 +187,7 @@ namespace WalletWasabi.Gui
#region TorProcessInitialization
- if (Config.UseTor.Value)
+ if (Config.UseTor)
{
TorManager = new TorProcessManager(Config.TorSocks5EndPoint, TorLogsFile);
}
@@ -408,7 +408,7 @@ namespace WalletWasabi.Gui
await Task.Delay(100, token);
}
- if (Config.UseTor.Value)
+ if (Config.UseTor)
{
ChaumianClient = new CcjClient(Synchronizer, Network, keyManager, () => Config.GetCurrentBackendUri(), Config.TorSocks5EndPoint);
}

MODIFY
WalletWasabi.Gui/Tabs/SettingsViewModel.cs
WalletWasabi.Gui/Tabs/SettingsViewModel.cs
@@ -47,24 +47,8 @@ namespace WalletWasabi.Gui.Tabs
public SettingsViewModel(Global global) : base(global, "Settings")
{
- var config = new Config(Global.Config.FilePath);
Autocopy = Global.UiConfig?.Autocopy is true;
- this.WhenAnyValue(x => x.Network)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(async _ =>
- {
- await config.LoadFileAsync();
-
- var configBitcoinP2pEndPoint = Network == Network.Main
- ? config.MainNetBitcoinP2pEndPoint
- : (Network == Network.TestNet
- ? config.TestNetBitcoinP2pEndPoint
- : config.RegTestBitcoinP2pEndPoint);
-
- BitcoinP2pEndPoint = configBitcoinP2pEndPoint.ToString(defaultPort: -1);
- });
-
this.WhenAnyValue(
x => x.Network,
x => x.UseTor)
@@ -80,11 +64,12 @@ namespace WalletWasabi.Gui.Tabs
Dispatcher.UIThread.PostLogException(async () =>
{
+ var config = new Config(Global.Config.FilePath);
await config.LoadFileAsync();
Network = config.Network;
TorSocks5EndPoint = config.TorSocks5EndPoint.ToString(-1);
- UseTor = config.UseTor.Value;
+ UseTor = config.UseTor;
SomePrivacyLevel = config.PrivacyLevelSome.ToString();
FinePrivacyLevel = config.PrivacyLevelFine.ToString();
@@ -92,6 +77,8 @@ namespace WalletWasabi.Gui.Tabs
DustThreshold = config.DustThreshold.ToString();
+ BitcoinP2pEndPoint = config.GetP2PEndpoint().ToString(defaultPort: -1);
+
IsModified = await Global.Config.CheckFileChangeAsync();
});
@@ -299,58 +286,29 @@ namespace WalletWasabi.Gui.Tabs
using (await ConfigLock.LockAsync())
{
await config.LoadFileAsync();
-
- var torSocks5EndPoint = EndPointParser.TryParse(TorSocks5EndPoint, Constants.DefaultTorSocksPort, out EndPoint torEp) ? torEp : null;
- var bitcoinP2pEndPoint = EndPointParser.TryParse(BitcoinP2pEndPoint, network.DefaultPort, out EndPoint p2pEp) ? p2pEp : null;
- var useTor = UseTor;
- var somePrivacyLevel = int.TryParse(SomePrivacyLevel, out int level) ? (int?)level : null;
- var finePrivacyLevel = int.TryParse(FinePrivacyLevel, out level) ? (int?)level : null;
- var strongPrivacyLevel = int.TryParse(StrongPrivacyLevel, out level) ? (int?)level : null;
- var dustThreshold = decimal.TryParse(DustThreshold, out var threshold) ? (decimal?)threshold : null;
-
- var configBitcoinP2pEndPoint = network == NBitcoin.Network.Main
- ? config.MainNetBitcoinP2pEndPoint
- : (network == NBitcoin.Network.TestNet
- ? config.TestNetBitcoinP2pEndPoint
- : config.RegTestBitcoinP2pEndPoint);
-
- if (config.Network != network
- || config.TorSocks5EndPoint != torSocks5EndPoint
- || config.UseTor != useTor
- || config.PrivacyLevelSome != somePrivacyLevel
- || config.PrivacyLevelFine != finePrivacyLevel
- || config.PrivacyLevelStrong != strongPrivacyLevel
- || config.DustThreshold.ToUnit(MoneyUnit.BTC) != dustThreshold
- || configBitcoinP2pEndPoint != bitcoinP2pEndPoint
- )
- {
- config.Network = network;
- config.TorSocks5EndPoint = torSocks5EndPoint;
- config.UseTor = useTor;
- config.PrivacyLevelSome = somePrivacyLevel;
- config.PrivacyLevelFine = finePrivacyLevel;
- config.PrivacyLevelStrong = strongPrivacyLevel;
- config.DustThreshold = Money.Coins(dustThreshold.Value);
-
- switch (network.Name)
- {
- case "Main":
- config.MainNetBitcoinP2pEndPoint = bitcoinP2pEndPoint;
- break;
-
- case "TestNet":
- config.TestNetBitcoinP2pEndPoint = bitcoinP2pEndPoint;
- break;
-
- case "RegTest":
- config.RegTestBitcoinP2pEndPoint = bitcoinP2pEndPoint;
- break;
+ if (Network == config.Network)
+ {
+ if (EndPointParser.TryParse(TorSocks5EndPoint, Constants.DefaultTorSocksPort, out EndPoint torEp))
+ {
+ config.TorSocks5EndPoint = torEp;
}
-
- await config.ToFileAsync();
+ if (EndPointParser.TryParse(BitcoinP2pEndPoint, network.DefaultPort, out EndPoint p2pEp))
+ {
+ config.SetP2PEndpoint(p2pEp);
}
-
- IsModified = await Global.Config.CheckFileChangeAsync();
+ config.UseTor = UseTor;
+ config.DustThreshold = decimal.TryParse(DustThreshold, out var threshold) ? Money.Coins(threshold) : Config.DefaultDustThreshold;
+ config.PrivacyLevelSome = int.TryParse(SomePrivacyLevel, out int level) ? level : Config.DefaultPrivacyLevelSome;
+ config.PrivacyLevelStrong = int.TryParse(StrongPrivacyLevel, out level) ? level : Config.DefaultPrivacyLevelStrong;
+ config.PrivacyLevelFine = int.TryParse(FinePrivacyLevel, out level) ? level : Config.DefaultPrivacyLevelFine;
+ }
+ else
+ {
+ config.Network = Network;
+ BitcoinP2pEndPoint = config.GetP2PEndpoint().ToString(defaultPort: -1);
+ }
+ await config.ToFileAsync();
+ IsModified = !Global.Config.AreDeepEqual(config);
}
});
}

MODIFY
WalletWasabi.Gui/ViewModels/StatusBarViewModel.cs
WalletWasabi.Gui/ViewModels/StatusBarViewModel.cs
@@ -74,7 +74,7 @@ namespace WalletWasabi.Gui.ViewModels
Nodes = nodes;
Synchronizer = synchronizer;
HashChain = synchronizer.BitcoinStore.HashChain;
- UseTor = Global.Config.UseTor.Value; // Do not make it dynamic, because if you change this config settings only next time will it activate.
+ UseTor = Global.Config.UseTor; // Do not make it dynamic, because if you change this config settings only next time will it activate.
_status = ActiveStatuses.WhenAnyValue(x => x.CurrentStatus)
.ObserveOn(RxApp.MainThreadScheduler)

Remove some mapping boilerplate