Make sure postrequest handler disposal is correct.
ADD
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/InputRegistrationTests.cs
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using WalletWasabi.WabiSabi.Backend;
+using WalletWasabi.WabiSabi.Backend.Banning;
+using WalletWasabi.WabiSabi.Backend.PostRequests;
+using WalletWasabi.WabiSabi.Models;
+using Xunit;
+
+namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
+{
+ public class InputRegistrationTests
+ {
+ //[Fact]
+ //public async Task FooAsync()
+ //{
+ // PostRequestHandler postRequestHandler;
+ // await using (postRequestHandler = new(new WabiSabiConfig(), new Prison()))
+ // {
+ // postRequestHandler.RegisterInput(new InputsRegistrationRequest(Guid.NewGuid(), null, null, null));
+ // }
+ //}
+ }
+}

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/UtxoPrisonTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/UtxoPrisonTests.cs
@@ -14,7 +14,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public void EmptyPrison()
{
- var p = new Prison(Enumerable.Empty<Inmate>());
+ var p = new Prison();
Assert.Empty(p.GetInmates());
Assert.Equal(0, p.CountInmates().noted);
Assert.Equal(0, p.CountInmates().banned);
@@ -24,7 +24,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public void PrisonChangeTracking()
{
- var p = new Prison(Enumerable.Empty<Inmate>());
+ var p = new Prison();
var currentChangeId = p.ChangeId;
// Make sure we set them to the past so the release method that looks at the time evaluates to true.
@@ -60,7 +60,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
[Fact]
public void PrisonOperations()
{
- var p = new Prison(Enumerable.Empty<Inmate>());
+ var p = new Prison();
var guid1 = Guid.NewGuid();

ADD
WalletWasabi/Nito/AsyncEx/RunningTasks.cs
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WalletWasabi.Nito.AsyncEx
+{
+ public class RunningTasks : IDisposable
+ {
+ public RunningTasks(AbandonedTasks taskCollection)
+ {
+ taskCollection.AddAndClearCompleted(Completion.Task);
+ }
+
+ private bool DisposedValue { get; set; } = false;
+ public static TaskCompletionSource Completion { get; } = new();
+
+ public static IDisposable RememberWith(AbandonedTasks taskCollection) => new RunningTasks(taskCollection);
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!DisposedValue)
+ {
+ if (disposing)
+ {
+ Completion.TrySetResult();
+ }
+
+ DisposedValue = true;
+ }
+ }
+
+ public void Dispose() => Dispose(true);
+ }
+}

MODIFY
WalletWasabi/WabiSabi/Backend/Banning/Prison.cs
WalletWasabi/WabiSabi/Backend/Banning/Prison.cs
@@ -11,6 +11,10 @@ namespace WalletWasabi.WabiSabi.Backend.Banning
/// </summary>
public class Prison
{
+ public Prison() : this(Enumerable.Empty<Inmate>())
+ {
+ }
+
public Prison(IEnumerable<Inmate> inmates)
{
Inmates = inmates.ToDictionary(x => x.Utxo, x => x);

MODIFY
WalletWasabi/WabiSabi/Backend/PostRequests/PostRequestHandler.cs
WalletWasabi/WabiSabi/Backend/PostRequests/PostRequestHandler.cs
@@ -4,12 +4,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using WalletWasabi.Nito.AsyncEx;
using WalletWasabi.WabiSabi.Backend.Banning;
using WalletWasabi.WabiSabi.Models;
namespace WalletWasabi.WabiSabi.Backend.PostRequests
{
- public class PostRequestHandler
+ public class PostRequestHandler : IAsyncDisposable
{
public PostRequestHandler(WabiSabiConfig config, Prison prison)
{
@@ -17,32 +18,75 @@ namespace WalletWasabi.WabiSabi.Backend.PostRequests
Prison = prison;
}
+ private bool DisposeStarted { get; set; } = false;
+ private object DisposeStartedLock { get; } = new();
+ private AbandonedTasks RunningRequests { get; } = new();
public WabiSabiConfig Config { get; }
public Prison Prison { get; }
public InputsRegistrationResponse RegisterInput(InputsRegistrationRequest request)
+ {
+ DisposeGuard();
+ using (RunningTasks.RememberWith(RunningRequests))
{
throw new NotImplementedException();
}
+ }
public void RemoveInput(InputsRemovalRequest request)
+ {
+ DisposeGuard();
+ using (RunningTasks.RememberWith(RunningRequests))
{
throw new NotImplementedException();
}
+ }
public ConnectionConfirmationResponse ConfirmConnection(ConnectionConfirmationRequest request)
+ {
+ DisposeGuard();
+ using (RunningTasks.RememberWith(RunningRequests))
{
throw new NotImplementedException();
}
+ }
public OutputRegistrationResponse RegisterOutput(OutputRegistrationRequest request)
+ {
+ DisposeGuard();
+ using (RunningTasks.RememberWith(RunningRequests))
{
throw new NotImplementedException();
}
+ }
public void SignTransaction(TransactionSignaturesRequest request)
+ {
+ DisposeGuard();
+ using (RunningTasks.RememberWith(RunningRequests))
{
throw new NotImplementedException();
}
}
+
+ private void DisposeGuard()
+ {
+ lock (DisposeStartedLock)
+ {
+ if (DisposeStarted)
+ {
+ throw new ObjectDisposedException(nameof(PostRequestHandler));
+ }
+ }
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ lock (DisposeStartedLock)
+ {
+ DisposeStarted = true;
+ }
+ await RunningRequests.WhenAllAsync().ConfigureAwait(false);
+ }
+ }
}

MODIFY
WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
WalletWasabi/WabiSabi/WabiSabiCoordinator.cs
@@ -44,6 +44,7 @@ namespace WalletWasabi.WabiSabi
public override async Task StopAsync(CancellationToken cancellationToken)
{
+ await Postman.DisposeAsync().ConfigureAwait(false);
await base.StopAsync(cancellationToken).ConfigureAwait(false);
await ConfigWatcher.StopAsync(cancellationToken).ConfigureAwait(false);
await Warden.StopAsync(cancellationToken).ConfigureAwait(false);

Make sure postrequest handler disposal is correct.