Skip to content

Commit

Permalink
life by a thousand tiny fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Kukks committed Sep 9, 2024
1 parent 6dab1df commit 1a9a8c8
Show file tree
Hide file tree
Showing 15 changed files with 560 additions and 238 deletions.
358 changes: 199 additions & 159 deletions BTCPayApp.Core/Attempt2/BTCPayConnectionManager.cs

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions BTCPayApp.Core/Attempt2/LightningNodeService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,16 @@ public async Task CleanseTask()
public async Task Generate()
{
await _controlSemaphore.WaitAsync();
_logger.LogInformation("Generating lightning node");
try
{
if (State != LightningNodeState.NotConfigured) return;
if (!IsHubConnected)
throw new InvalidOperationException("Cannot configure lightning node without BTCPay connection");
if (!IsOnchainConfigured)
throw new InvalidOperationException("Cannot configure lightning node without on-chain wallet configuration");
if (IsOnchainLightningDerivationConfigured)
throw new InvalidOperationException("On-chain wallet is already configured with a lightning derivation");

_logger.LogInformation("Generating lightning node");
await _onChainWalletManager.AddDerivation(WalletDerivation.LightningScripts, "Lightning", null);
// await _onChainWalletManager.AddDerivation(WalletDerivation.SpendableOutputs, "Lightning Spendables", null);
State = LightningNodeState.WaitingForConnection;
Expand Down Expand Up @@ -196,6 +195,9 @@ private async Task OnStateChanged(object? sender, (LightningNodeState Old, Light
{
switch (state.New)
{
case LightningNodeState.Init:
newState = LightningNodeState.WaitingForConnection;
break;
case LightningNodeState.WaitingForConnection:
{
if (IsHubConnected)
Expand All @@ -219,10 +221,7 @@ private async Task OnStateChanged(object? sender, (LightningNodeState Old, Light
break;

case LightningNodeState.NotConfigured:
if (CanConfigureLightningNode)
{
await Generate();
}

break;
}
}
Expand All @@ -237,6 +236,7 @@ protected override async Task ExecuteStartAsync(CancellationToken cancellationTo
{
State = LightningNodeState.Init;
StateChanged += OnStateChanged;
await StateChanged.Invoke(this, (LightningNodeState.Init, LightningNodeState.Init));
_btcPayConnectionManager.ConnectionChanged += OnConnectionChanged;
_onChainWalletManager.StateChanged += OnChainWalletManagerOnStateChanged;
}
Expand Down
7 changes: 2 additions & 5 deletions BTCPayApp.Core/Attempt2/OnChainWalletManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,7 @@ protected override async Task ExecuteStartAsync(CancellationToken cancellationTo

private async Task OnStateChanged(object? sender, (OnChainWalletState Old, OnChainWalletState New) e)
{
if (e is { New: OnChainWalletState.NotConfigured } && CanConfigureWallet)
{
await Generate();
}


if (e is {New: OnChainWalletState.Loaded} && IsConfigured)
{
Expand All @@ -105,11 +102,11 @@ public async Task Generate()
try
{

_logger.LogInformation("Generating wallet");
if (State != OnChainWalletState.NotConfigured || IsConfigured || !IsHubConnected)
{
throw new InvalidOperationException("Cannot generate wallet in current state");
}
_logger.LogInformation("Generating wallet");

var mnemonic = new Mnemonic(Wordlist.English, WordCount.Twelve);
var mainnet = _btcPayConnectionManager.ReportedNetwork == Network.Main;
Expand Down
13 changes: 13 additions & 0 deletions BTCPayApp.Core/Helpers/BaseHostedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,17 @@ public virtual void Dispose()
_cancellationTokenSource?.Dispose();
_controlSemaphore?.Dispose();
}

protected async Task WrapInLock(Func<Task> act, CancellationToken cancellationToken)
{
await _controlSemaphore.WaitAsync(cancellationToken);
try
{
await act();
}
finally
{
_controlSemaphore.Release();
}
}
}
19 changes: 15 additions & 4 deletions BTCPayApp.Core/StartupExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
using BTCPayApp.Core.Data;
using BTCPayApp.Core.LDK;
using Laraue.EfCoreTriggers.SqlLite.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

Expand All @@ -31,16 +34,24 @@ public static IServiceCollection ConfigureBTCPayAppCore(this IServiceCollection
serviceCollection.AddSingleton<LightningNodeManager>();
serviceCollection.AddSingleton<OnChainWalletManager>();
serviceCollection.AddSingleton<BTCPayAppServerClient>();
serviceCollection.AddSingleton<IBTCPayAppHubClient>(provider => provider.GetRequiredService<BTCPayAppServerClient>());
serviceCollection.AddSingleton<IHostedService>(provider => provider.GetRequiredService<BTCPayConnectionManager>());
serviceCollection.AddSingleton<IBTCPayAppHubClient>(provider =>
provider.GetRequiredService<BTCPayAppServerClient>());
serviceCollection.AddSingleton<IHostedService>(provider =>
provider.GetRequiredService<BTCPayConnectionManager>());
serviceCollection.AddSingleton<IHostedService>(provider => provider.GetRequiredService<LightningNodeManager>());
serviceCollection.AddSingleton<IHostedService>(provider => provider.GetRequiredService<OnChainWalletManager>());
serviceCollection.AddSingleton<AuthStateProvider>();
serviceCollection.AddSingleton<AuthenticationStateProvider, AuthStateProvider>( provider => provider.GetRequiredService<AuthStateProvider>());
serviceCollection.AddSingleton<AuthenticationStateProvider, AuthStateProvider>(provider =>
provider.GetRequiredService<AuthStateProvider>());
serviceCollection.AddSingleton<IHostedService>(provider => provider.GetRequiredService<AuthStateProvider>());
serviceCollection.AddSingleton(sp => (IAccountManager)sp.GetRequiredService<AuthenticationStateProvider>());
serviceCollection.AddSingleton(sp => (IAccountManager) sp.GetRequiredService<AuthenticationStateProvider>());
serviceCollection.AddSingleton<IConfigProvider, DatabaseConfigProvider>();
serviceCollection.AddLDK();
serviceCollection.AddSingleton<IAuthorizationHandler, BearerAuthorizationHandler>();
serviceCollection.AddAuthorizationCore(options =>
{
options.AddBTCPayPolicies();
});
return serviceCollection;
}
}
4 changes: 2 additions & 2 deletions BTCPayApp.Desktop/StartupExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static IServiceCollection ConfigureBTCPayAppDesktop(this IServiceCollecti
serviceCollection.AddSingleton<IDataDirectoryProvider, DesktopDataDirectoryProvider>();
// serviceCollection.AddSingleton<IConfigProvider, DesktopConfigProvider>();
serviceCollection.AddSingleton<ISecureConfigProvider, DesktopSecureConfigProvider>();
serviceCollection.AddSingleton<IFingerprint, FingerprintProvider>();
serviceCollection.AddSingleton<IFingerprint, StubFingerprintProvider>();
return serviceCollection;
}
}
Expand Down Expand Up @@ -85,7 +85,7 @@ public async Task<IEnumerable<string>> List(string prefix)
protected Task<string> WriteFromRaw(string str) => Task.FromResult(_dataProtector.Protect(str));
}

public class FingerprintProvider: IFingerprint
public class StubFingerprintProvider: IFingerprint
{
public Task<FingerprintAvailability> GetAvailabilityAsync(bool allowAlternativeAuthentication = false)
{
Expand Down
3 changes: 3 additions & 0 deletions BTCPayApp.Tests/BTCPayApp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@
<ItemGroup>
<ProjectReference Include="..\BTCPayApp.Server\BTCPayApp.Server.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

</Project>
56 changes: 1 addition & 55 deletions BTCPayApp.Tests/BTCPayAppTestServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,59 +149,5 @@ public override async ValueTask DisposeAsync()
}
}

public void Eventually(Action act, int ms = 20_000)
{
var cts = new CancellationTokenSource(ms);
while (true)
{
try
{
act();
break;
}
catch (PlaywrightException) when (!cts.Token.IsCancellationRequested)
{
cts.Token.WaitHandle.WaitOne(500);
}
catch (XunitException) when (!cts.Token.IsCancellationRequested)
{
cts.Token.WaitHandle.WaitOne(500);
}
}
}

public static async Task EventuallyAsync(Func<Task> act, int delay = 20000)
{
CancellationTokenSource cts = new CancellationTokenSource(delay);
while (true)
{
try
{
await act();
break;
}
catch (PlaywrightException) when (!cts.Token.IsCancellationRequested)
{
bool timeout =false;
try
{
await Task.Delay(500, cts.Token);
}
catch { timeout = true; }
if (timeout)
throw;
}
catch (XunitException) when (!cts.Token.IsCancellationRequested)
{
bool timeout =false;
try
{
await Task.Delay(500, cts.Token);
}
catch { timeout = true; }
if (timeout)
throw;
}
}
}

}
97 changes: 97 additions & 0 deletions BTCPayApp.Tests/CoreTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using BTCPayApp.Core.Attempt2;
using BTCPayApp.Core.Auth;
using BTCPayApp.Core.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit.Abstractions;

namespace BTCPayApp.Tests;

public class CoreTests
{
private readonly ITestOutputHelper _output;

public CoreTests(ITestOutputHelper output)
{
_output = output;
}



[Fact]
public async Task CanStartAppCore()
{
var btcpayUri = new Uri("https://localhost:14142");
using var node = new HeadlessTestNode(_output);
var connectionManager = node.App.Services.GetRequiredService<BTCPayConnectionManager>();
var lnManager = node.App.Services.GetRequiredService<LightningNodeManager>();
var onChainWalletManager = node.App.Services.GetRequiredService<OnChainWalletManager>();
var accountManager = node.App.Services.GetRequiredService<IAccountManager>();
var authStateProvider = node.App.Services.GetRequiredService<AuthStateProvider>();

TestUtils.Eventually(() => Assert.Equal(BTCPayConnectionState.Init, connectionManager.ConnectionState));
TestUtils.Eventually(() => Assert.Equal(LightningNodeState.Init, lnManager.State));
TestUtils.Eventually(() => Assert.Equal(OnChainWalletState.Init, onChainWalletManager.State));


var appTask = node.App.StartAsync();
//throw is this task faults in the bg

await Task.WhenAny(appTask,
node.App.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStarted.AsTask());

TestUtils.Eventually(
() => Assert.Equal(BTCPayConnectionState.WaitingForAuth, connectionManager.ConnectionState));
TestUtils.Eventually(() => Assert.Equal(OnChainWalletState.WaitingForConnection, onChainWalletManager.State));
TestUtils.Eventually(() => Assert.Equal(LightningNodeState.WaitingForConnection, lnManager.State));


await Assert.ThrowsAsync<InvalidOperationException>(() => onChainWalletManager.Generate());
await Assert.ThrowsAsync<InvalidOperationException>(() => lnManager.Generate());


var username = Guid.NewGuid() + "@gg.com";

Assert.True((await accountManager.Register(btcpayUri.AbsoluteUri, username, username)).Succeeded);
Assert.True(await authStateProvider.CheckAuthenticated());
await accountManager.Logout();
Assert.False(await authStateProvider.CheckAuthenticated());
Assert.True((await accountManager.Login(btcpayUri.AbsoluteUri, username, username, null)).Succeeded);
Assert.True(await authStateProvider.CheckAuthenticated());
Assert.NotNull(accountManager.GetAccount()?.RefreshToken);

TestUtils.Eventually(() => Assert.Equal(BTCPayConnectionState.Connecting, connectionManager.ConnectionState));
TestUtils.Eventually(() =>
Assert.Equal(BTCPayConnectionState.ConnectedAsMaster, connectionManager.ConnectionState));
TestUtils.Eventually(() => Assert.Equal(LightningNodeState.NotConfigured, lnManager.State));
TestUtils.Eventually(() => Assert.Equal(OnChainWalletState.NotConfigured, onChainWalletManager.State));
Assert.Null(onChainWalletManager.WalletConfig);

Assert.False(lnManager.CanConfigureLightningNode);
await onChainWalletManager.Generate();
await Assert.ThrowsAsync<InvalidOperationException>(() => onChainWalletManager.Generate());

TestUtils.Eventually(() => Assert.Equal(OnChainWalletState.Loaded, onChainWalletManager.State));
TestUtils.Eventually(() => Assert.Equal(LightningNodeState.NotConfigured, lnManager.State));

Assert.NotNull(onChainWalletManager.WalletConfig);
Assert.NotNull(onChainWalletManager.WalletConfig?.Derivations);
Assert.False(onChainWalletManager.WalletConfig?.Derivations.ContainsKey(WalletDerivation.LightningScripts));
WalletDerivation? segwitDerivation = null;
Assert.True(onChainWalletManager.WalletConfig?.Derivations.TryGetValue(WalletDerivation.NativeSegwit, out segwitDerivation));
Assert.False(string.IsNullOrEmpty(onChainWalletManager.WalletConfig.Fingerprint));
Assert.NotNull(segwitDerivation.Identifier);
Assert.NotNull(segwitDerivation.Descriptor);
Assert.NotNull(segwitDerivation.Name);


Assert.True(lnManager.CanConfigureLightningNode);


await lnManager.Generate();
TestUtils.Eventually(() => Assert.Equal(LightningNodeState.Loaded, lnManager.State));
await Assert.ThrowsAsync<InvalidOperationException>(() => lnManager.Generate());


}
}
Loading

0 comments on commit 1a9a8c8

Please sign in to comment.