Replace reconnection with Reconnecter
MODIFY
WalletWasabi.Backend/Startup.cs
WalletWasabi.Backend/Startup.cs
@@ -97,27 +97,27 @@ namespace WalletWasabi.Backend
global.Coordinator?.Dispose();
Logger.LogInfo($"{nameof(global.Coordinator)} is disposed.");
- if (global.IndexBuilderService != null)
+ if (global.IndexBuilderService is { })
{
await global.IndexBuilderService.StopAsync();
Logger.LogInfo($"{nameof(global.IndexBuilderService)} is disposed.");
}
- if (global.BlockNotifier != null)
+ if (global.BlockNotifier is { })
{
await global.BlockNotifier.StopAsync();
Logger.LogInfo($"{nameof(global.BlockNotifier)} is disposed.");
}
- if (global.RoundConfigWatcher != null)
+ if (global.RoundConfigWatcher is { })
{
await global.RoundConfigWatcher.StopAsync();
Logger.LogInfo($"{nameof(global.RoundConfigWatcher)} is disposed.");
}
- if (global.P2pNode != null)
+ if (global.P2pNode is { })
{
- global.P2pNode.Dispose();
+ await global.P2pNode.DisposeAsync().ConfigureAwait(false);
Logger.LogInfo($"{nameof(global.P2pNode)} is disposed.");
}

MODIFY
WalletWasabi/BitcoinCore/CoreNode.cs
WalletWasabi/BitcoinCore/CoreNode.cs
@@ -235,12 +235,14 @@ namespace WalletWasabi.BitcoinCore
{
if (!_disposedValue)
{
- if (BlockNotifier != null)
+ if (BlockNotifier is { })
{
await BlockNotifier.StopAsync().ConfigureAwait(false);
}
-
- P2pNode?.Dispose();
+ if (P2pNode is { })
+ {
+ await P2pNode.DisposeAsync().ConfigureAwait(false);
+ }
_disposedValue = true;
}
}

ADD
WalletWasabi/BitcoinCore/Monitoring/P2pReconnector.cs
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using WalletWasabi.Bases;
+using WalletWasabi.Helpers;
+using WalletWasabi.Logging;
+
+namespace WalletWasabi.BitcoinCore.Monitoring
+{
+ public class P2pReconnector : PeriodicRunner<bool>
+ {
+ public P2pNode P2pNode { get; set; }
+
+ public P2pReconnector(TimeSpan period, P2pNode p2pNode) : base(period, false)
+ {
+ P2pNode = Guard.NotNull(nameof(p2pNode), p2pNode);
+ }
+
+ protected override async Task<bool> ActionAsync(CancellationToken cancel)
+ {
+ try
+ {
+ Logger.LogInfo("Trying to reconnect to P2P...");
+ P2pNode.Disconnect();
+ await P2pNode.ConnectAsync(cancel).ConfigureAwait(false);
+ }
+ catch
+ {
+ P2pNode.Disconnect();
+ throw;
+ }
+
+ Logger.LogInfo("Successfully reconnected to P2P.");
+ await StopAsync().ConfigureAwait(false);
+
+ // If successfully connected, return.
+ return true;
+ }
+ }
+}

MODIFY
WalletWasabi/BitcoinCore/P2pNode.cs
WalletWasabi/BitcoinCore/P2pNode.cs
using NBitcoin;
using NBitcoin.Protocol;
+using Nito.AsyncEx;
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.BitcoinCore.Monitoring;
using WalletWasabi.Blockchain.Blocks;
using WalletWasabi.Blockchain.Mempool;
using WalletWasabi.Blockchain.P2p;
@@ -14,7 +17,7 @@ using WalletWasabi.Logging;
namespace WalletWasabi.BitcoinCore
{
- public class P2pNode : IDisposable
+ public class P2pNode
{
private Node Node { get; set; }
private TrustedP2pBehavior TrustedP2pBehavior { get; set; }
@@ -28,6 +31,8 @@ namespace WalletWasabi.BitcoinCore
private object SubscriptionLock { get; }
private CancellationTokenSource Stop { get; set; }
+ private P2pReconnector Reconnector { get; set; }
+ private AsyncLock ReconnectorLock { get; }
public P2pNode(Network network, EndPoint endPoint, MempoolService mempoolService, string userAgent)
{
@@ -39,6 +44,8 @@ namespace WalletWasabi.BitcoinCore
Stop = new CancellationTokenSource();
NodeEventsSubscribed = false;
SubscriptionLock = new object();
+ Reconnector = null;
+ ReconnectorLock = new AsyncLock();
}
public async Task ConnectAsync(CancellationToken cancel)
@@ -81,54 +88,45 @@ namespace WalletWasabi.BitcoinCore
}
}
- private bool Reconnecting { get; set; }
- private object ReconnectingLock { get; set; } = new object();
-
private async void Node_DisconnectedAsync(Node node)
{
- lock (ReconnectingLock)
- {
- if (Reconnecting)
- {
- return;
- }
- Reconnecting = true;
- }
try
{
- while (true)
+ using (await ReconnectorLock.LockAsync(Stop.Token).ConfigureAwait(false))
{
- try
+ if (Reconnector is { })
{
- Logger.LogInfo("Trying to reconnect to P2P...");
- Disconnect();
- await ConnectAsync(Stop.Token).ConfigureAwait(false);
- Logger.LogInfo("Successfully reconnected to P2P...");
-
- // If successfully connected, return.
return;
}
- catch (Exception ex)
- {
- Stop.Token.ThrowIfCancellationRequested();
- Logger.LogError(ex);
- // Make sure things are disposed properly.
- Disconnect();
- await Task.Delay(TimeSpan.FromSeconds(7), Stop.Token).ConfigureAwait(false);
- }
+ Reconnector = new P2pReconnector(TimeSpan.FromSeconds(7), this);
+ Reconnector.PropertyChanged += Reconnector_PropertyChangedAsync;
+ Reconnector.Start();
}
}
- catch (Exception ex) when (ex is OperationCanceledException || ex is TaskCanceledException || ex is TimeoutException)
+ catch (Exception ex)
{
- Logger.LogTrace(ex);
+ Logger.LogDebug(ex);
}
- finally
+ }
+
+ private async void Reconnector_PropertyChangedAsync(object sender, PropertyChangedEventArgs e)
+ {
+ try
{
- lock (ReconnectingLock)
+ using (await ReconnectorLock.LockAsync(Stop.Token).ConfigureAwait(false))
{
- Reconnecting = false;
+ if (e.PropertyName == nameof(Reconnector.Status) && Reconnector.Status)
+ {
+ Reconnector.PropertyChanged -= Reconnector_PropertyChangedAsync;
+ await Reconnector.StopAsync().ConfigureAwait(false);
+ Reconnector = null;
+ }
+ }
}
+ catch (Exception ex)
+ {
+ Logger.LogDebug(ex);
}
}
@@ -150,27 +148,27 @@ namespace WalletWasabi.BitcoinCore
}
}
- #region IDisposable Support
-
- private volatile bool _disposedValue = false; // To detect redundant calls
-
- protected virtual void Dispose(bool disposing)
+ public async Task DisposeAsync()
{
- if (!_disposedValue)
+ Stop?.Cancel();
+ using (await ReconnectorLock.LockAsync().ConfigureAwait(false))
{
- if (disposing)
+ if (Reconnector is { })
{
- Stop?.Cancel();
+ Reconnector.PropertyChanged -= Reconnector_PropertyChangedAsync;
+ await Reconnector.StopAsync().ConfigureAwait(false);
+ Reconnector = null;
+ }
+ }
Disconnect();
Stop?.Dispose();
Stop = null;
}
- _disposedValue = true;
- }
- }
-
- private void Disconnect()
+ /// <summary>
+ /// It is not equivalent to Dispose, but it is being called from Dispose.
+ /// </summary>
+ public void Disconnect()
{
lock (SubscriptionLock)
{
@@ -212,14 +210,5 @@ namespace WalletWasabi.BitcoinCore
}
}
}
-
- // This code added to correctly implement the disposable pattern.
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- Dispose(true);
- }
-
- #endregion IDisposable Support
}
}

Replace reconnection with Reconnecter