Add wabisabi request statista
ADD
WalletWasabi.Backend/Controllers/WabiSabi/RequestTimeStatista.cs
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using WalletWasabi.Logging;
+
+namespace WalletWasabi.Backend.Controllers.WabiSabi;
+
+public class RequestTimeStatista
+{
+ private Dictionary<string, List<(DateTimeOffset Time, TimeSpan Duration)>> Requests { get; } = new();
+ private object Lock { get; } = new();
+ private DateTimeOffset LastDisplayed { get; set; } = DateTimeOffset.UtcNow;
+ private TimeSpan DisplayFrequency { get; } = TimeSpan.FromMinutes(10);
+
+ public void Add(string request, TimeSpan duration)
+ {
+ try
+ {
+ var toDisplay = false;
+ lock (Lock)
+ {
+ if (Requests.ContainsKey(request))
+ {
+ Requests[request].Add((DateTimeOffset.UtcNow, duration));
+ }
+ else
+ {
+ Requests.Add(request, new() { (DateTimeOffset.UtcNow, duration) });
+ }
+
+ if ((DateTimeOffset.UtcNow - LastDisplayed) > DisplayFrequency)
+ {
+ toDisplay = true;
+ }
+ }
+
+ if (toDisplay)
+ {
+ Display();
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError(ex);
+ }
+ }
+
+ private void Display()
+ {
+ lock (Lock)
+ {
+ Logger.LogInfo($"Response times for the last {(int)(DateTimeOffset.UtcNow - LastDisplayed).TotalMinutes} minutes:");
+ foreach (var request in Requests.OrderByDescending(x => x.Value.Count))
+ {
+ var seconds = request.Value.Select(x => x.Duration.TotalSeconds);
+ Logger.LogInfo($"Responded to '{request.Key}'\t {request.Value.Count} times. Median: {seconds.Median():0.0}s Average: {seconds.Average():0.0}s Largest {seconds.Max():0.0}s");
+ }
+
+ LastDisplayed = DateTimeOffset.UtcNow;
+ Requests.Clear();
+ }
+ }
+}

MODIFY
WalletWasabi.Backend/Controllers/WabiSabiController.cs
WalletWasabi.Backend/Controllers/WabiSabiController.cs
@@ -28,55 +28,92 @@ public class WabiSabiController : ControllerBase, IWabiSabiApiRequestHandler
private IdempotencyRequestCache IdempotencyRequestCache { get; }
private Arena Arena { get; }
private CoinJoinFeeRateStatStore CoinJoinFeeRateStatStore { get; }
+ private static RequestTimeStatista RequestTimeStatista { get; } = new RequestTimeStatista();
[HttpPost("status")]
public async Task<RoundStateResponse> GetStatusAsync(RoundStateRequest request, CancellationToken cancellationToken)
{
+ var before = DateTimeOffset.UtcNow;
var response = await Arena.GetStatusAsync(request, cancellationToken);
var medians = CoinJoinFeeRateStatStore.GetDefaultMedians();
- return new RoundStateResponse(response.RoundStates, medians);
+ var ret = new RoundStateResponse(response.RoundStates, medians);
+
+ var duration = DateTimeOffset.UtcNow - before;
+ RequestTimeStatista.Add("status", duration);
+ return ret;
}
[HttpPost("connection-confirmation")]
public async Task<ConnectionConfirmationResponse> ConfirmConnectionAsync(ConnectionConfirmationRequest request, CancellationToken cancellationToken)
{
- return await IdempotencyRequestCache.GetCachedResponseAsync(request, action: (request, token) => Arena.ConfirmConnectionAsync(request, token), cancellationToken);
+ var before = DateTimeOffset.UtcNow;
+ var ret = await IdempotencyRequestCache.GetCachedResponseAsync(request, action: (request, token) => Arena.ConfirmConnectionAsync(request, token), cancellationToken);
+
+ var duration = DateTimeOffset.UtcNow - before;
+ RequestTimeStatista.Add("connection-confirmation", duration);
+ return ret;
}
[HttpPost("input-registration")]
public async Task<InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellationToken)
{
- return await IdempotencyRequestCache.GetCachedResponseAsync(request, action: (request, token) => Arena.RegisterInputAsync(request, token), cancellationToken);
+ var before = DateTimeOffset.UtcNow;
+ var ret = await IdempotencyRequestCache.GetCachedResponseAsync(request, action: (request, token) => Arena.RegisterInputAsync(request, token), cancellationToken);
+
+ var duration = DateTimeOffset.UtcNow - before;
+ RequestTimeStatista.Add("connection-confirmation", duration);
+ return ret;
}
[HttpPost("output-registration")]
public async Task RegisterOutputAsync(OutputRegistrationRequest request, CancellationToken cancellationToken)
{
+ var before = DateTimeOffset.UtcNow;
await IdempotencyRequestCache.GetCachedResponseAsync(request, action: (request, token) => Arena.RegisterOutputCoreAsync(request, token), cancellationToken);
+
+ var duration = DateTimeOffset.UtcNow - before;
+ RequestTimeStatista.Add("output-registration", duration);
}
[HttpPost("credential-issuance")]
public async Task<ReissueCredentialResponse> ReissuanceAsync(ReissueCredentialRequest request, CancellationToken cancellationToken)
{
- return await IdempotencyRequestCache.GetCachedResponseAsync(request, action: (request, token) => Arena.ReissuanceAsync(request, token), cancellationToken);
+ var before = DateTimeOffset.UtcNow;
+ var ret = await IdempotencyRequestCache.GetCachedResponseAsync(request, action: (request, token) => Arena.ReissuanceAsync(request, token), cancellationToken);
+
+ var duration = DateTimeOffset.UtcNow - before;
+ RequestTimeStatista.Add("credential-issuance", duration);
+ return ret;
}
[HttpPost("input-unregistration")]
public async Task RemoveInputAsync(InputsRemovalRequest request, CancellationToken cancellableToken)
{
+ var before = DateTimeOffset.UtcNow;
await Arena.RemoveInputAsync(request, cancellableToken);
+
+ var duration = DateTimeOffset.UtcNow - before;
+ RequestTimeStatista.Add("input-unregistration", duration);
}
[HttpPost("transaction-signature")]
public async Task SignTransactionAsync(TransactionSignaturesRequest request, CancellationToken cancellableToken)
{
+ var before = DateTimeOffset.UtcNow;
await Arena.SignTransactionAsync(request, cancellableToken);
+
+ var duration = DateTimeOffset.UtcNow - before;
+ RequestTimeStatista.Add("transaction-signature", duration);
}
[HttpPost("ready-to-sign")]
public async Task ReadyToSignAsync(ReadyToSignRequestRequest request, CancellationToken cancellableToken)
{
+ var before = DateTimeOffset.UtcNow;
await Arena.ReadyToSignAsync(request, cancellableToken);
+
+ var duration = DateTimeOffset.UtcNow - before;
+ RequestTimeStatista.Add("ready-to-sign", duration);
}
/// <summary>

MODIFY
WalletWasabi/Crypto/Extensions.cs
WalletWasabi/Crypto/Extensions.cs
@@ -37,4 +37,14 @@ public static class Extensions
yield return resultSelector(e1.Current, e2.Current, e3.Current);
}
}
+
+ public static double Median(this IEnumerable<double> me)
+ {
+ if (!me.Any())
+ {
+ return 0;
+ }
+ var sorted = me.OrderBy(x => x).ToArray();
+ return sorted[sorted.Length / 2];
+ }
}

Add wabisabi request statista