Skip to content

Commit

Permalink
Notify SoftwareVersion and LegalDocumentVersion (#12692)
Browse files Browse the repository at this point in the history
* Notify versions as part of initial ws exchange

* CR suggestions
  • Loading branch information
lontivero committed Apr 24, 2024
1 parent 2c558a0 commit f8305d2
Show file tree
Hide file tree
Showing 17 changed files with 135 additions and 247 deletions.
30 changes: 23 additions & 7 deletions WalletWasabi.Backend/Middlewares/SatoshiWebSocketHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using WalletWasabi.Blockchain.Analysis.FeesEstimation;
using WalletWasabi.Blockchain.BlockFilters;
using WalletWasabi.Extensions;
using WalletWasabi.Helpers;
using WalletWasabi.Logging;
using WalletWasabi.Services;
using WalletWasabi.Synchronization;
Expand Down Expand Up @@ -107,7 +108,8 @@ public override Task OnDisconnectedAsync(WebSocket socket, CancellationToken can
var bestKnownBlockHash = reader.ReadUInt256();
socketState.Handshaked = true;

// Send the best block height
await SendSoftwareVersionAsync(socketState.WebSocket, cancellationToken);
await SendLegalDocumentVersionAsync(socketState.WebSocket, cancellationToken);
await SendBlockHeightAsync(socketState.WebSocket, cancellationToken);
await StartSendingFiltersAsync(socketState.WebSocket, bestKnownBlockHash, cancellationToken);
}
Expand Down Expand Up @@ -151,12 +153,26 @@ private Task SendBlockHeightAsync(WebSocket webSocket, CancellationToken cancell
return webSocket.SendAsync(message.ToByteArray(), WebSocketMessageType.Binary, true, cancellationToken);
}

/// <summary>
/// SendMissingFiltersAsync sends all the filters since bestknownblockhash to the client.
/// </summary>
/// <param name="webSocket">The websocket.</param>
/// <param name="bestKnownBlockHash">The latest block id known by the client.</param>
/// <param name="cancellationToken">The cancellation token.</param>
private Task SendSoftwareVersionAsync(WebSocket webSocket, CancellationToken cancellationToken)
{
var clientVersion = Constants.ClientVersion;
var backendVersion = new Version(int.Parse(Constants.BackendMajorVersion), 0, 0);
var message = new VersionMessage(clientVersion, backendVersion);
return webSocket.SendAsync(message.ToByteArray(), WebSocketMessageType.Binary, true, cancellationToken);
}

private Task SendLegalDocumentVersionAsync(WebSocket webSocket, CancellationToken cancellationToken)
{
var message = new LegalDocumentVersionMessage(Constants.Ww2LegalDocumentsVersion);
return webSocket.SendAsync(message.ToByteArray(), WebSocketMessageType.Binary, true, cancellationToken);
}

// <summary>
// SendMissingFiltersAsync sends all the filters since bestknownblockhash to the client.
// </summary>
// <param name="webSocket">The websocket.</param>
// <param name="bestKnownBlockHash">The latest block id known by the client.</param>
// <param name="cancellationToken">The cancellation token.</param>
private async Task SendMissingFiltersAsync(
WebSocket webSocket,
uint256 bestKnownBlockHash,
Expand Down
8 changes: 3 additions & 5 deletions WalletWasabi.Daemon/Global.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,9 @@ public Global(string dataDir, string configFilePath, Config config)
var satoshiEndpointUri = new UriBuilder(satoshiUriScheme, coordinatorUri.Host, coordinatorUri.Port, "api/satoshi").Uri;
HostedServices.Register<SatoshiSynchronizer>(() => new SatoshiSynchronizer(BitcoinStore, satoshiEndpointUri, Config.UseTor ? TorSettings.SocksEndpoint : null, EventBus), "Satoshi Synchronizer");

HostedServices.Register<UpdateChecker>(() => new UpdateChecker(TimeSpan.FromHours(1), wasabiSynchronizer), "Software Update Checker");
UpdateChecker updateChecker = HostedServices.Get<UpdateChecker>();

LegalChecker = new(DataDir, updateChecker);
UpdateManager = new(DataDir, Config.DownloadNewVersion, HttpClientFactory.NewHttpClient(Mode.DefaultCircuit, maximumRedirects: 10), updateChecker);
var httpClientForUpdates = HttpClientFactory.NewHttpClient(Mode.DefaultCircuit, maximumRedirects: 10);
LegalChecker = new(DataDir, new WasabiClient(httpClientForUpdates), EventBus);
UpdateManager = new(DataDir, Config.DownloadNewVersion, httpClientForUpdates, EventBus);
TorStatusChecker = new TorStatusChecker(TimeSpan.FromHours(6), HttpClientFactory.NewHttpClient(Mode.DefaultCircuit), new XmlIssueListParser());
RoundStateUpdaterCircuit = new PersonCircuit();

Expand Down
19 changes: 0 additions & 19 deletions WalletWasabi.Tests/IntegrationTests/LiveServerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,25 +97,6 @@ public async Task GetVersionsTestsAsync(Network network)
Assert.Equal(new(1, 0), versions.LegalDocumentsVersion);
}

[Theory]
[MemberData(nameof(GetNetworks))]
public async Task CheckUpdatesTestsAsync(Network network)
{
using CancellationTokenSource ctsTimeout = new(TimeSpan.FromMinutes(2));

WasabiClient client = MakeWasabiClient(network);
UpdateStatus updateStatus = await client.CheckUpdatesAsync(ctsTimeout.Token);

Assert.True(updateStatus.BackendCompatible);
Assert.True(updateStatus.ClientUpToDate);
Assert.Equal(new Version(1, 0), updateStatus.LegalDocumentsVersion);
Assert.Equal((ushort)4, updateStatus.CurrentBackendMajorVersion);
Assert.Equal(WalletWasabi.Helpers.Constants.ClientVersion.ToString(3), updateStatus.ClientVersion.ToString());

var versions = await client.GetVersionsAsync(ctsTimeout.Token);
Assert.Equal(versions.LegalDocumentsVersion, updateStatus.LegalDocumentsVersion);
}

[Theory]
[MemberData(nameof(GetNetworks))]
public async Task GetLegalDocumentsTestsAsync(Network network)
Expand Down
9 changes: 0 additions & 9 deletions WalletWasabi.Tests/RegressionTests/BackendTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,6 @@ public async Task GetExchangeRatesAsync()
Assert.True(rate.Rate > 0);
}

[Fact]
public async Task GetClientVersionAsync()
{
WasabiClient client = new(BackendHttpClient);
var uptodate = await client.CheckUpdatesAsync(CancellationToken.None);
Assert.True(uptodate.BackendCompatible);
Assert.True(uptodate.ClientUpToDate);
}

[Fact]
public async Task BroadcastReplayTxAsync()
{
Expand Down
48 changes: 0 additions & 48 deletions WalletWasabi.Tests/UnitTests/UpdateStatusTests.cs

This file was deleted.

18 changes: 17 additions & 1 deletion WalletWasabi/Extensions/StreamReaderWriterExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.IO;
using NBitcoin;
using NBitcoin.RPC;
using WalletWasabi.Backend.Models;
using WalletWasabi.Blockchain.Analysis.FeesEstimation;
using WalletWasabi.Blockchain.Blocks;
Expand Down Expand Up @@ -83,4 +82,21 @@ public static AllFeeEstimate ReadMiningFeeRates(this BinaryReader reader)

return new AllFeeEstimate(estimations);
}

public static void Write(this BinaryWriter writer, Version version)
{
writer.Write(version.Major);
writer.Write(version.Minor);
writer.Write(version.Build);
}

public static Version ReadVersion(this BinaryReader reader)
{
var major = reader.ReadInt32();
var minor = reader.ReadInt32();
var build = reader.ReadInt32();
return build >= 0
? new Version(major, minor, build)
: new Version(major, minor);
}
}
36 changes: 1 addition & 35 deletions WalletWasabi/Models/UpdateStatus.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,3 @@
namespace WalletWasabi.Models;

public class UpdateStatus : IEquatable<UpdateStatus>
{
public UpdateStatus(bool backendCompatible, bool clientUpToDate, Version legalDocumentsVersion, ushort currentBackendMajorVersion, Version clientVersion)
{
BackendCompatible = backendCompatible;
ClientUpToDate = clientUpToDate;
LegalDocumentsVersion = legalDocumentsVersion;
CurrentBackendMajorVersion = currentBackendMajorVersion;
ClientVersion = clientVersion;
}

public bool ClientUpToDate { get; }
public bool BackendCompatible { get; }
public bool IsReadyToInstall { get; set; }

public Version LegalDocumentsVersion { get; }
public ushort CurrentBackendMajorVersion { get; }

public Version ClientVersion { get; set; }

#region EqualityAndComparison

public static bool operator ==(UpdateStatus? x, UpdateStatus? y)
=> (x?.ClientUpToDate, x?.BackendCompatible, x?.LegalDocumentsVersion, x?.CurrentBackendMajorVersion, x?.ClientVersion) == (y?.ClientUpToDate, y?.BackendCompatible, y?.LegalDocumentsVersion, y?.CurrentBackendMajorVersion, y?.ClientVersion);

public static bool operator !=(UpdateStatus? x, UpdateStatus? y) => !(x == y);

public override bool Equals(object? obj) => Equals(obj as UpdateStatus);

public bool Equals(UpdateStatus? other) => this == other;

public override int GetHashCode() => (ClientUpToDate, BackendCompatible, LegalDocumentsVersion, CurrentBackendMajorVersion, ClientVersion).GetHashCode();

#endregion EqualityAndComparison
}
public record UpdateStatus(bool ClientUpToDate, bool BackendCompatible, bool IsReadyToInstall, Version ClientVersion);
5 changes: 3 additions & 2 deletions WalletWasabi/Services/Events/Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

namespace WalletWasabi.Services.Events;

public record ExchangeRateChanged(decimal UsdBtcRate);

public enum FeeRateSource
{
Backend,
LocalNodeRpc,
}

public record ExchangeRateChanged(decimal UsdBtcRate);
public record MiningFeeRatesChanged(FeeRateSource Source, AllFeeEstimate AllFeeEstimate);
public record ServerTipHeightChanged(uint Height);
public record ConnectionStateChanged(bool Connected);
public record SoftwareVersionChanged(Version ClientVersion, Version ServerVersion);
public record LegalDocumentVersionChanged(Version Version);
36 changes: 13 additions & 23 deletions WalletWasabi/Services/LegalChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
using System.Threading.Tasks;
using WalletWasabi.Legal;
using WalletWasabi.Logging;
using WalletWasabi.Models;
using WalletWasabi.Services.Events;
using WalletWasabi.WebClients.Wasabi;

namespace WalletWasabi.Services;

Expand All @@ -16,21 +17,20 @@ public class LegalChecker : IDisposable

private bool _disposedValue;

public LegalChecker(string dataDir, UpdateChecker updateChecker)
public LegalChecker(string dataDir, WasabiClient wasabiClient, EventBus eventBus)
{
LegalFolder = Path.Combine(dataDir, LegalFolderName);
ProvisionalLegalFolder = Path.Combine(LegalFolder, ProvisionalLegalFolderName);
UpdateChecker = updateChecker;
WasabiClient = wasabiClient;
LegalDocumentVersionSubscription = eventBus.Subscribe<LegalDocumentVersionChanged>(OnLegalDocumentVersionChanged);
}

public event EventHandler<LegalDocuments>? AgreedChanged;

public event EventHandler<LegalDocuments>? ProvisionalChanged;
public IDisposable LegalDocumentVersionSubscription { get; }

/// <remarks>Lock object to guard <see cref="CurrentLegalDocument"/> and <see cref="ProvisionalLegalDocument"/> property.</remarks>
private AsyncLock LegalDocumentLock { get; } = new();

private UpdateChecker UpdateChecker { get; }
private WasabiClient WasabiClient { get; }
public string LegalFolder { get; }
public string ProvisionalLegalFolder { get; }
public LegalDocuments? CurrentLegalDocument { get; private set; }
Expand All @@ -39,7 +39,6 @@ public LegalChecker(string dataDir, UpdateChecker updateChecker)

public async Task InitializeAsync()
{
UpdateChecker.UpdateStatusChanged += UpdateChecker_UpdateStatusChangedAsync;
CurrentLegalDocument = await LegalDocuments.LoadAgreedAsync(LegalFolder).ConfigureAwait(false);
ProvisionalLegalDocument = await LegalDocuments.LoadAgreedAsync(ProvisionalLegalFolder).ConfigureAwait(false);

Expand Down Expand Up @@ -80,33 +79,29 @@ public bool TryGetNewLegalDocs([NotNullWhen(true)] out LegalDocuments? legalDocu
return false;
}

private async void UpdateChecker_UpdateStatusChangedAsync(object? _, UpdateStatus updateStatus)
private async void OnLegalDocumentVersionChanged(LegalDocumentVersionChanged evnt)
{
var legalDocumentsVersion = evnt.Version;
try
{
LegalDocuments? provisionalLegalDocument = null;

using (await LegalDocumentLock.LockAsync().ConfigureAwait(false))
{
// If we don't have it or there is a new one.
if (CurrentLegalDocument is null || CurrentLegalDocument.Version < updateStatus.LegalDocumentsVersion)
if (CurrentLegalDocument is null || CurrentLegalDocument.Version < legalDocumentsVersion)
{
// UpdateChecker cannot be null as the event called by it.
var content = await UpdateChecker!.WasabiClient.GetLegalDocumentsAsync(CancellationToken.None).ConfigureAwait(false);
var content = await WasabiClient.GetLegalDocumentsAsync(CancellationToken.None).ConfigureAwait(false);

// Save it as a provisional legal document.
provisionalLegalDocument = new(updateStatus.LegalDocumentsVersion, content);
provisionalLegalDocument = new(legalDocumentsVersion, content);
await provisionalLegalDocument.ToFileAsync(ProvisionalLegalFolder).ConfigureAwait(false);

ProvisionalLegalDocument = provisionalLegalDocument;
LatestDocumentTaskCompletion.TrySetResult(ProvisionalLegalDocument);
}
}

if (provisionalLegalDocument is { })
{
ProvisionalChanged?.Invoke(this, provisionalLegalDocument);
}
}
catch (Exception ex)
{
Expand All @@ -129,8 +124,6 @@ public async Task AgreeAsync()
CurrentLegalDocument = ProvisionalLegalDocument;
ProvisionalLegalDocument = null;
}

AgreedChanged?.Invoke(this, CurrentLegalDocument);
}

protected virtual void Dispose(bool disposing)
Expand All @@ -139,10 +132,7 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (UpdateChecker is { } updateChecker)
{
updateChecker.UpdateStatusChanged -= UpdateChecker_UpdateStatusChangedAsync;
}
LegalDocumentVersionSubscription.Dispose();
LatestDocumentTaskCompletion.TrySetCanceled();
}

Expand Down
11 changes: 11 additions & 0 deletions WalletWasabi/Services/SatoshiSynchronizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@ async Task StartReceivingMessagesAsync(WebSocket ws)
_eventBus.Publish(new ServerTipHeightChanged(height));
break;

case ResponseMessage.SoftwareVersion:
var clientVersion = reader.ReadVersion();
var serverVersion = reader.ReadVersion();
_eventBus.Publish(new SoftwareVersionChanged(clientVersion, serverVersion));
break;

case ResponseMessage.LegalDocumentVersion:
var version = reader.ReadVersion();
_eventBus.Publish(new LegalDocumentVersionChanged(version));
break;

case ResponseMessage.Filter:
var filter = reader.ReadFilterModel();
if (localChain.TipHeight + 1 != filter.Header.Height)
Expand Down

0 comments on commit f8305d2

Please sign in to comment.