native nostr coinjoins

This commit is contained in:
Kukks
2023-10-19 14:41:13 +02:00
parent 16880b6c71
commit edbb47fd2a
8 changed files with 297 additions and 79 deletions

View File

@@ -206,7 +206,7 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
//if we're less than the max output registration, we should be more aggressive in adding coins
var chance = consolidationMode ? (isLessThanMaxOutputRegistration? 100: 90 ): 100m - Math.Min(maxCoinCapacityPercentage, isLessThanMaxOutputRegistration ? 10m : maxCoinCapacityPercentage);
_logger.LogDebug(
$"coin selection: no payms left but at {solution.Coins.Count()} coins. random chance to add another coin if: {chance} <= {rand} (random 0-100) ");
$"coin selection: no payms left but at {solution.Coins.Count()} coins. random chance to add another coin if: {chance} <= {rand} (random 0-100) {chance <= rand} ");
if (chance <= rand)
{
break;

View File

@@ -93,11 +93,22 @@ public class WabisabiCoordinatorService : PeriodicRunner
break;
}
}
else if (existing.Enabled &&
_instanceManager.HostedServices.TryGetValue("local", out var instance))
else if (existing.Enabled)
{
if (_instanceManager.HostedServices.TryGetValue("local", out var instance))
{
instance.TermsConditions = wabisabiCoordinatorSettings.TermsConditions;
}
if(wabisabiCoordinatorSettings.Enabled &&
(existing.NostrIdentity != wabisabiCoordinatorSettings.NostrIdentity || existing.NostrRelay != wabisabiCoordinatorSettings.NostrRelay))
{
var nostr = HostedServices.Get<NostrWabisabiApiServer>();
nostr.UpdateSettings(wabisabiCoordinatorSettings);
await nostr.StopAsync(CancellationToken.None);
await nostr.StartAsync(CancellationToken.None);
}
}
await _settingsRepository.UpdateSetting(wabisabiCoordinatorSettings, nameof(WabisabiCoordinatorSettings));
@@ -202,7 +213,10 @@ public class WabisabiCoordinatorService : PeriodicRunner
WabiSabiCoordinator = new WabiSabiCoordinator(coordinatorParameters, rpc, coinJoinIdStore, coinJoinScriptStore,
_httpClientFactory);
HostedServices.Register<WabiSabiCoordinator>(() => WabiSabiCoordinator, "WabiSabi Coordinator");
var settings = await GetSettings();
WabisabiApiServer = new NostrWabisabiApiServer(WabiSabiCoordinator.Arena, settings, _logger);
HostedServices.Register<NostrWabisabiApiServer>(() => WabisabiApiServer, "WabiSabi Coordinator Nostr");
if (settings.Enabled)
{
@@ -218,6 +232,8 @@ public class WabisabiCoordinatorService : PeriodicRunner
await base.StartAsync(cancellationToken);
}
public NostrWabisabiApiServer WabisabiApiServer { get; set; }
public async Task StartCoordinator(CancellationToken cancellationToken)
{
_logger.LogInformation("Starting local coordinator");

View File

@@ -1,6 +1,8 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
@@ -10,6 +12,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NNostr.Client;
using WalletWasabi.Logging;
using WalletWasabi.Tor.Socks5.Pool.Circuits;
using WalletWasabi.WabiSabi;
using WalletWasabi.WabiSabi.Backend.Models;
using WalletWasabi.WabiSabi.Backend.PostRequests;
@@ -18,36 +21,65 @@ using WalletWasabi.WabiSabi.Models.Serialization;
namespace BTCPayServer.Plugins.Wabisabi;
public class NostrWabiSabiApiClient : IWabiSabiApiRequestHandler, IHostedService
public class NostrWabiSabiApiClient : IWabiSabiApiRequestHandler, IHostedService, IDisposable
{
public static int RoundStateKind = 15750;
public static int CommunicationKind = 25750;
private readonly NostrClient _client;
private NostrClient _client;
private readonly Uri _relay;
private readonly WebProxy _webProxy;
private readonly ECXOnlyPubKey _coordinatorKey;
private readonly INamedCircuit _circuit;
private string _coordinatorKeyHex => _coordinatorKey.ToHex();
private readonly string _coordinatorFilterId;
public NostrWabiSabiApiClient(NostrClient client, ECXOnlyPubKey coordinatorKey)
public NostrWabiSabiApiClient(Uri relay, WebProxy webProxy , ECXOnlyPubKey coordinatorKey, INamedCircuit? circuit)
{
_client = client;
_relay = relay;
_webProxy = webProxy;
_coordinatorKey = coordinatorKey;
_circuit = circuit;
_coordinatorFilterId = new Guid().ToString();
}
public async Task StartAsync(CancellationToken cancellationToken)
{
if (!_circuit.IsActive)
{
Dispose();
}
if (_circuit is OneOffCircuit)
{
return;
// we dont bootstrap, we do it on demand for a request instead
}
await Init(cancellationToken, _circuit);
}
private async Task Init(CancellationToken cancellationToken, INamedCircuit circuit)
{
_client = CreateClient(_relay, _webProxy, circuit);
_ = _client.ListenForMessages();
var filter = new NostrSubscriptionFilter()
{
Authors = new[] {_coordinatorKey.ToHex()},
Kinds = new[] {RoundStateKind, CommunicationKind},
Since = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromHours(1))
Since = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromHours(1)),
Limit = 0
};
await _client.CreateSubscription(_coordinatorFilterId, new[] {filter}, cancellationToken);
_client.EventsReceived += EventsReceived;
await _client.ConnectAndWaitUntilConnected(cancellationToken);
_circuit.IsolationIdChanged += (_, _) =>
{
_client.Dispose();
_ = StartAsync(CancellationToken.None);
};
}
private RoundStateResponse _lastRoundState { get; set; }
@@ -77,6 +109,16 @@ public class NostrWabiSabiApiClient : IWabiSabiApiRequestHandler, IHostedService
private async Task<TResponse> SendAndWaitForReply<TRequest, TResponse>(RemoteAction action, TRequest request,
CancellationToken cancellationToken)
{
if(_circuit is OneOffCircuit)
{
using var subClient =
new NostrWabiSabiApiClient(_relay, _webProxy, _coordinatorKey, new PersonCircuit());
await subClient.StartAsync(cancellationToken);
return await subClient.SendAndWaitForReply<TRequest, TResponse>(action, request, cancellationToken);
}
var newKey = ECPrivKey.Create(RandomUtils.GetBytes(32));
var pubkey = newKey.CreateXOnlyPubKey();
var evt = new NostrEvent()
@@ -164,14 +206,14 @@ public class NostrWabiSabiApiClient : IWabiSabiApiRequestHandler, IHostedService
catch (OperationCanceledException e)
{
_client.EventsReceived -= OnClientEventsReceived;
_circuit.IncrementIsolationId();
throw;
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _client.CloseSubscription(_coordinatorFilterId, cancellationToken);
_client.EventsReceived -= EventsReceived;
Dispose();
}
public async Task<RoundStateResponse> GetStatusAsync(RoundStateRequest request, CancellationToken cancellationToken)
@@ -237,4 +279,23 @@ public class NostrWabiSabiApiClient : IWabiSabiApiRequestHandler, IHostedService
GetStatus,
ReadyToSign
}
public void Dispose()
{
_client?.Dispose();
}
public static NostrClient CreateClient(Uri relay, WebProxy webProxy, INamedCircuit namedCircuit )
{
return new NostrClient(relay, socket =>
{
if (socket is ClientWebSocket clientWebSocket && webProxy is { })
{
var proxy = new WebProxy(webProxy.Address, true, null,
new NetworkCredential(namedCircuit.Name,
namedCircuit.IsolationId.ToString()));
clientWebSocket.Options.Proxy = proxy;
}
});
}
}

View File

@@ -5,12 +5,14 @@ using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NBitcoin;
using NBitcoin.Secp256k1;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NNostr.Client;
using WabiSabi.Crypto;
using WalletWasabi.Backend.Controllers;
using WalletWasabi.Logging;
using WalletWasabi.WabiSabi;
using WalletWasabi.WabiSabi.Backend.Models;
@@ -26,17 +28,18 @@ public class NostrWabisabiApiServer: IHostedService
public static int RoundStateKind = 15750;
public static int CommunicationKind = 25750;
private readonly Arena _arena;
private readonly NostrClient _client;
private readonly ECPrivKey _coordinatorKey;
private string _coordinatorKeyHex => _coordinatorKey.CreateXOnlyPubKey().ToHex();
private WabisabiCoordinatorSettings _coordinatorSettings;
private NostrClient _client;
private readonly ILogger _logger;
private readonly string _coordinatorFilterId;
private Channel<NostrEvent> PendingEvents { get; } = Channel.CreateUnbounded<NostrEvent>();
public NostrWabisabiApiServer(Arena arena,NostrClient client, ECPrivKey coordinatorKey)
public NostrWabisabiApiServer(Arena arena, WabisabiCoordinatorSettings coordinatorSettings,
ILogger logger)
{
_arena = arena;
_client = client;
_coordinatorKey = coordinatorKey;
_coordinatorSettings = coordinatorSettings;
_logger = logger;
_coordinatorFilterId = new Guid().ToString();
_serializer = JsonSerializer.Create(JsonSerializationOptions.Default.Settings);
}
@@ -44,12 +47,20 @@ public class NostrWabisabiApiServer: IHostedService
public async Task StartAsync(CancellationToken cancellationToken)
{
_ = _client.ListenForMessages();
if (_coordinatorSettings.NostrRelay is null || string.IsNullOrEmpty(_coordinatorSettings.NostrIdentity))
{
_logger.LogInformation("NOSTR SERVER: No Nostr relay/identity configured, skipping");
return;
}
_client = new NostrClient(_coordinatorSettings.NostrRelay);
await _client.Connect(cancellationToken);
_logger.LogInformation($"NOSTR SERVER: CONNECTED TO {_coordinatorSettings.NostrRelay}");
var filter = new NostrSubscriptionFilter()
{
ReferencedPublicKeys = new[] {_coordinatorKey.ToHex()},
ReferencedPublicKeys = new[] {_coordinatorSettings.GetPubKey().ToHex()},
Kinds = new[] { CommunicationKind},
Since = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromHours(1))
Limit = 0
};
await _client.CreateSubscription(_coordinatorFilterId, new[] {filter}, cancellationToken);
_client.EventsReceived += EventsReceived;
@@ -65,7 +76,7 @@ public class NostrWabisabiApiServer: IHostedService
if (e.subscriptionId != _coordinatorFilterId) return;
var requests = e.events.Where(evt =>
evt.Kind == CommunicationKind &&
evt.GetTaggedData("p").Any(s => s == _coordinatorKeyHex) && evt.Verify());
evt.GetTaggedData("p").Any(s => s == _coordinatorSettings.GetPubKey().ToHex()) && evt.Verify());
foreach (var request in requests)
PendingEvents.Writer.TryWrite(request);
}
@@ -79,11 +90,12 @@ public class NostrWabisabiApiServer: IHostedService
var nostrEvent = new NostrEvent()
{
Kind = RoundStateKind,
PublicKey = _coordinatorKeyHex,
PublicKey = _coordinatorSettings.GetPubKey().ToHex(),
CreatedAt = DateTimeOffset.Now,
Content = Serialize(response)
};
await _client.PublishEvent(nostrEvent, cancellationToken);
_logger.LogInformation($"NOSTR SERVER: PUBLISHED ROUND STATE {nostrEvent.Id}");
await Task.Delay(1000, cancellationToken);
}
}
@@ -95,7 +107,7 @@ public class NostrWabisabiApiServer: IHostedService
PendingEvents.Reader.TryRead(out var evt))
{
evt.Kind = 4;
var content = JObject.Parse(await evt.DecryptNip04EventAsync(_coordinatorKey));
var content = JObject.Parse(await evt.DecryptNip04EventAsync(_coordinatorSettings.GetKey()));
if (content.TryGetValue("action", out var actionJson) &&
actionJson.Value<string>(actionJson) is { } actionString &&
Enum.TryParse<RemoteAction>(actionString, out var action) &&
@@ -103,6 +115,7 @@ public class NostrWabisabiApiServer: IHostedService
{
try
{
_logger.LogInformation($"NOSTR SERVER: Received request {evt.Id} {action}");
switch (action)
{
case RemoteAction.GetStatus:
@@ -191,26 +204,33 @@ public class NostrWabisabiApiServer: IHostedService
private async Task Reply<TResponse>(NostrEvent originaltEvent,TResponse response,
CancellationToken cancellationToken)
{
_logger.LogInformation($"NOSTR SERVER: REPLYING TO {originaltEvent.Id} WITH {response}");
var evt = new NostrEvent()
{
Content = Serialize(response),
PublicKey = _coordinatorKeyHex,
PublicKey = _coordinatorSettings.GetPubKey().ToHex(),
Kind = 4,
CreatedAt = DateTimeOffset.Now
};
evt.SetTag("p", originaltEvent.PublicKey);
evt.SetTag("e", originaltEvent.Id);
await evt.EncryptNip04EventAsync(_coordinatorKey);
await evt.EncryptNip04EventAsync(_coordinatorSettings.GetKey());
evt.Kind = CommunicationKind;
await evt.ComputeIdAndSignAsync(_coordinatorKey);
await evt.ComputeIdAndSignAsync(_coordinatorSettings.GetKey());
await _client.PublishEvent(evt, cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (_client is not null)
{
await _client.CloseSubscription(_coordinatorFilterId, cancellationToken);
_client.EventsReceived -= EventsReceived;
_client = null;
}
}
private static string Serialize<T>(T obj)
@@ -226,4 +246,9 @@ public class NostrWabisabiApiServer: IHostedService
GetStatus,
ReadyToSign
}
public void UpdateSettings(WabisabiCoordinatorSettings wabisabiCoordinatorSettings)
{
_coordinatorSettings = wabisabiCoordinatorSettings;
}
}

View File

@@ -1,7 +1,10 @@

@using BTCPayServer.Plugins.Wabisabi
@using NNostr.Client
@using NNostr.Client.Protocols
@using WalletWasabi.Backend.Controllers
@model WalletWasabi.Backend.Controllers.WabisabiCoordinatorSettings
@inject WabisabiCoordinatorService WabisabiCoordinatorService
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData["NavPartialName"] = "../UIServer/_Nav";
@@ -59,6 +62,28 @@
<button name="command" value="generate-nostr-key" type="submit" class="btn btn-secondary btn-sm">Generate</button>
</div>
</div>
@if(WabisabiCoordinatorService.Started && WabisabiCoordinatorService.WabisabiApiServer != null && Model.NostrRelay is not null && Model.NostrIdentity is not null)
{
var nprofile = new NIP19.NosteProfileNote()
{
PubKey = Model.GetPubKey().ToHex(),
Relays = new[] {Model.NostrRelay.ToString()}
}.ToNIP19();
<div class="form-group mt-4" >
<label class="form-label">EXPERIMENTAL: NOSTR COORDINATOR ENDPOINT ACTIVE</label>
<div class="input-group">
<input type="text" id="ss-result-txt" class="form-control" readonly="readonly" value="nostr:@nprofile"/>
<button type="button" class="btn btn-secondary" data-clipboard-target="#ss-result-txt">
<vc:icon symbol="copy"/>
</button> <button type="button" class="btn btn-secondary" id="advertise-nostr" onclick="document.getElementById('UriToAdvertise').value='nostr:@nprofile'">
Set as url to advertise
</button>
</div>
<p id="ss-result-additional-info"></p>
</div>
}
<div class="form-group">
<label asp-for="CoordinatorDescription" class="form-label">Description</label>
<textarea asp-for="CoordinatorDescription" class="form-control"></textarea>

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
@@ -7,10 +8,13 @@ using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Payments.PayJoin;
using BTCPayServer.Services;
using ExchangeSharp;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NNostr.Client;
using NNostr.Client.Protocols;
using WalletWasabi.Backend.Controllers;
using WalletWasabi.Tor.Socks5.Pool.Circuits;
using WalletWasabi.Userfacing;
@@ -21,6 +25,7 @@ using WalletWasabi.WabiSabi.Client.RoundStateAwaiters;
using WalletWasabi.WabiSabi.Client.StatusChangedEvents;
using WalletWasabi.Wallets;
using WalletWasabi.WebClients.Wasabi;
using ClientWebSocket = System.Net.WebSockets.ClientWebSocket;
namespace BTCPayServer.Plugins.Wabisabi;
@@ -105,7 +110,7 @@ public class WabisabiCoordinatorClientInstanceManager:IHostedService
var instance = new WabisabiCoordinatorClientInstance(
displayName,
name, url is null? null: new Uri(url), _provider.GetService<ILoggerFactory>(), _provider, UTXOLocker,
_provider.GetService<WalletProvider>(), termsConditions, description);
_provider.GetService<WalletProvider>(), termsConditions, description,_provider.GetRequiredService<Socks5HttpClientHandler>());
if (HostedServices.TryAdd(instance.CoordinatorName, instance))
{
if(started)
@@ -127,7 +132,82 @@ public class WabisabiCoordinatorClientInstanceManager:IHostedService
}
}
public class WabisabiCoordinatorClientInstance
public class NostrWabisabiClientFactory: IWasabiHttpClientFactory, IHostedService
{
private readonly Socks5HttpClientHandler _socks5HttpClientHandler;
private readonly NIP19.NosteProfileNote _nostrProfileNote;
public NostrWabisabiClientFactory(Socks5HttpClientHandler socks5HttpClientHandler,
NIP19.NosteProfileNote nostrProfileNote)
{
_socks5HttpClientHandler = socks5HttpClientHandler;
_nostrProfileNote = nostrProfileNote;
}
private ConcurrentDictionary<string, NostrWabiSabiApiClient> _clients = new();
private bool _started = false;
public async Task StartAsync(CancellationToken cancellationToken)
{
await Task.WhenAll(_clients.Select(pair => pair.Value.StartAsync(cancellationToken)));
_started = true;
}
public Task StopAsync(CancellationToken cancellationToken)
{
foreach (var nostrWabiSabiApiClient in _clients)
{
nostrWabiSabiApiClient.Value.Dispose();
}
_clients.Clear();
_started = false;
return Task.CompletedTask;
}
public IWabiSabiApiRequestHandler NewWabiSabiApiRequestHandler(Mode mode, ICircuit circuit = null)
{
if (mode == Mode.DefaultCircuit || _socks5HttpClientHandler.Proxy is null)
{
circuit = DefaultCircuit.Instance;
}
if (mode == Mode.NewCircuitPerRequest)
{
circuit = new OneOffCircuit();
}
if (circuit is not INamedCircuit namedCircuit)
throw new ArgumentException("circuit must be a INamedCircuit");
var result = _clients.GetOrAdd(namedCircuit.Name, name =>
{
var result = new NostrWabiSabiApiClient(new Uri(_nostrProfileNote.Relays.First()),
_socks5HttpClientHandler.Proxy as WebProxy, NostrExtensions.ParsePubKey(_nostrProfileNote.PubKey),
namedCircuit);
return result;
});
return result;
}
}
public class LocalWabisabiClientFactory: IWasabiHttpClientFactory
{
private readonly WabiSabiController _wabiSabiController;
public LocalWabisabiClientFactory(WabiSabiController wabiSabiController)
{
_wabiSabiController = wabiSabiController;
}
public IWabiSabiApiRequestHandler NewWabiSabiApiRequestHandler(Mode mode, ICircuit circuit = null)
{
return _wabiSabiController;
}
}
public class WabisabiCoordinatorClientInstance:IHostedService
{
private readonly IUTXOLocker _utxoLocker;
private readonly ILogger _logger;
@@ -136,12 +216,13 @@ public class WabisabiCoordinatorClientInstance
public Uri Coordinator { get; set; }
public WalletProvider WalletProvider { get; }
public string TermsConditions { get; set; }
public WasabiHttpClientFactory WasabiHttpClientFactory { get; set; }
public IWasabiHttpClientFactory WasabiHttpClientFactory { get; set; }
public RoundStateUpdater RoundStateUpdater { get; set; }
public CoinPrison CoinPrison { get; private set; }
public WasabiCoordinatorStatusFetcher WasabiCoordinatorStatusFetcher { get; set; }
public CoinJoinManager CoinJoinManager { get; set; }
public string Description { get; set; }
private readonly WalletWasabi.Services.HostedServices _hostedServices = new();
public WabisabiCoordinatorClientInstance(string coordinatorDisplayName,
string coordinatorName,
@@ -149,7 +230,9 @@ public class WabisabiCoordinatorClientInstance
ILoggerFactory loggerFactory,
IServiceProvider serviceProvider,
IUTXOLocker utxoLocker,
WalletProvider walletProvider, string termsConditions, string description,string coordinatorIdentifier = "CoinJoinCoordinatorIdentifier")
WalletProvider walletProvider, string termsConditions, string description,
Socks5HttpClientHandler socks5HttpClientHandler, string coordinatorIdentifier = "CoinJoinCoordinatorIdentifier"
)
{
_utxoLocker = utxoLocker;
@@ -160,6 +243,7 @@ public class WabisabiCoordinatorClientInstance
{
torEndpoint = new IPEndPoint(Dns.GetHostAddresses(dnsEndPoint.Host).First(), dnsEndPoint.Port);
}
CoordinatorDisplayName = coordinatorDisplayName;
CoordinatorName = coordinatorName;
Coordinator = coordinator;
@@ -167,22 +251,37 @@ public class WabisabiCoordinatorClientInstance
TermsConditions = termsConditions;
Description = description;
_logger = loggerFactory.CreateLogger(coordinatorName);
IWabiSabiApiRequestHandler sharedWabisabiClient;
IWabiSabiApiRequestHandler sharedWabisabiClient = null;
var roundStateUpdaterCircuit = new PersonCircuit();
if (coordinatorName == "local")
{
sharedWabisabiClient = serviceProvider.GetRequiredService<WabiSabiController>();
WasabiHttpClientFactory = new LocalWabisabiClientFactory( serviceProvider.GetRequiredService<WabiSabiController>());
}
else if (coordinator.Scheme == "nostr" &&
coordinator.Host.FromNIP19Note() is NIP19.NosteProfileNote nostrProfileNote)
{
var factory = new NostrWabisabiClientFactory(socks5HttpClientHandler, nostrProfileNote);
WasabiHttpClientFactory = factory;
_hostedServices.Register<NostrWabisabiClientFactory>(() => factory, "NostrWabisabiClientFactory");
}
else
{
WasabiHttpClientFactory = new WasabiHttpClientFactory(torEndpoint, () => Coordinator);
var roundStateUpdaterCircuit = new PersonCircuit();
var roundStateUpdaterHttpClient =
WasabiHttpClientFactory.NewHttpClient(Mode.SingleCircuitPerLifetime, roundStateUpdaterCircuit);
if (termsConditions is null)
}
sharedWabisabiClient =
WasabiHttpClientFactory.NewWabiSabiApiRequestHandler(Mode.SingleCircuitPerLifetime,
roundStateUpdaterCircuit);
if (termsConditions is null && sharedWabisabiClient is WabiSabiHttpApiClient wabiSabiHttpApiClient)
{
_ = new WasabiClient(roundStateUpdaterHttpClient)
.GetLegalDocumentsAsync(CancellationToken.None)
_ = wabiSabiHttpApiClient.GetLegalDocumentsAsync(CancellationToken.None)
.ContinueWith(task =>
{
if (task.Status == TaskStatus.RanToCompletion)
@@ -191,29 +290,24 @@ public class WabisabiCoordinatorClientInstance
}
});
}
sharedWabisabiClient = new WabiSabiHttpApiClient(roundStateUpdaterHttpClient);
}
WasabiCoordinatorStatusFetcher = new WasabiCoordinatorStatusFetcher(sharedWabisabiClient, _logger);
RoundStateUpdater = new RoundStateUpdater(TimeSpan.FromSeconds(5),sharedWabisabiClient, WasabiCoordinatorStatusFetcher);
RoundStateUpdater =
new RoundStateUpdater(TimeSpan.FromSeconds(5), sharedWabisabiClient, WasabiCoordinatorStatusFetcher);
CoinPrison = SettingsCoinPrison.CreateFromCoordinatorName(serviceProvider.GetRequiredService<SettingsRepository>(),
CoinPrison = SettingsCoinPrison.CreateFromCoordinatorName(
serviceProvider.GetRequiredService<SettingsRepository>(),
CoordinatorName).GetAwaiter().GetResult();
if (coordinatorName == "local")
{
CoinJoinManager = new CoinJoinManager(coordinatorName, WalletProvider, RoundStateUpdater,
sharedWabisabiClient, null,
WasabiCoordinatorStatusFetcher, coordinatorIdentifier, CoinPrison);
}
else
{
CoinJoinManager = new CoinJoinManager(coordinatorName,WalletProvider, RoundStateUpdater,null, WasabiHttpClientFactory,
WasabiCoordinatorStatusFetcher, coordinatorIdentifier, CoinPrison);
}
CoinJoinManager = new CoinJoinManager(coordinatorName, WalletProvider, RoundStateUpdater,
WasabiHttpClientFactory,
WasabiCoordinatorStatusFetcher, coordinatorIdentifier, CoinPrison);
CoinJoinManager.StatusChanged += OnStatusChanged;
_hostedServices.Register<RoundStateUpdater>(() => RoundStateUpdater, "RoundStateUpdater");
_hostedServices.Register<WasabiCoordinatorStatusFetcher>(() => WasabiCoordinatorStatusFetcher, "WasabiCoordinatorStatusFetcher");
_hostedServices.Register<CoinJoinManager>(() => CoinJoinManager, "WasabiCoordinatorStatusFetcher");
}
public async Task StopWallet(IWallet wallet)
@@ -274,17 +368,14 @@ public class WabisabiCoordinatorClientInstance
public Task StartAsync(CancellationToken cancellationToken)
{
RoundStateUpdater.StartAsync(cancellationToken);
WasabiCoordinatorStatusFetcher.StartAsync(cancellationToken);
CoinJoinManager.StartAsync(cancellationToken);
_ = _hostedServices.StartAllAsync(cancellationToken);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
RoundStateUpdater.StopAsync(cancellationToken);
WasabiCoordinatorStatusFetcher.StopAsync(cancellationToken);
CoinJoinManager.StopAsync(cancellationToken);
_ = _hostedServices.StopAllAsync(cancellationToken);
return Task.CompletedTask;
}
}