Skip to content

Commit 6874ede

Browse files
committed
Simulate subaddress generate duplication
1 parent 76e2f11 commit 6874ede

2 files changed

Lines changed: 119 additions & 65 deletions

File tree

BTCPayServer.Plugins.IntegrationTests/Monero/IntegrationTestUtils.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public static class IntegrationTestUtils
2727
private static readonly string ContainerWalletDir =
2828
Environment.GetEnvironmentVariable("BTCPAY_XMR_WALLET_DAEMON_WALLETDIR") ?? "/wallet";
2929

30-
public static async Task CleanUpAsync(PlaywrightTester playwrightTester)
30+
public static async Task CleanUpAsync(PlaywrightTester playwrightTester, bool dropDatabase = true)
3131
{
3232
MoneroRpcProvider moneroRpcProvider = playwrightTester.Server.PayTester.GetService<MoneroRpcProvider>();
3333
if (moneroRpcProvider.IsAvailable("XMR"))
@@ -38,16 +38,22 @@ public static async Task CleanUpAsync(PlaywrightTester playwrightTester)
3838
if (RunsInContainer)
3939
{
4040
DeleteWalletInContainer();
41-
await DropDatabaseAsync(
42-
"btcpayserver",
43-
"Host=postgres;Port=5432;Username=postgres;Database=postgres");
41+
if (dropDatabase)
42+
{
43+
await DropDatabaseAsync(
44+
"btcpayserver",
45+
"Host=postgres;Port=5432;Username=postgres;Database=postgres");
46+
}
4447
}
4548
else
4649
{
4750
await RemoveWalletFromLocalDocker();
48-
await DropDatabaseAsync(
49-
"btcpayserver",
50-
"Host=localhost;Port=39372;Username=postgres;Database=postgres");
51+
if (dropDatabase)
52+
{
53+
await DropDatabaseAsync(
54+
"btcpayserver",
55+
"Host=localhost;Port=39372;Username=postgres;Database=postgres");
56+
}
5157
}
5258
}
5359

BTCPayServer.Plugins.IntegrationTests/Monero/MoneroPluginIntegrationTest.cs

Lines changed: 106 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using BTCPayServer.Plugins.Monero.Services;
33
using BTCPayServer.Rating;
44
using BTCPayServer.Services.Rates;
5+
using BTCPayServer.Tests;
56
using BTCPayServer.Tests.Mocks;
67

78
using Xunit;
@@ -17,56 +18,7 @@ public async Task ShouldEnableMoneroPluginSuccessfully()
1718
await using var s = CreatePlaywrightTester();
1819
await s.StartAsync();
1920

20-
if (s.Server.PayTester.MockRates)
21-
{
22-
var rateProviderFactory = s.Server.PayTester.GetService<RateProviderFactory>();
23-
rateProviderFactory.Providers.Clear();
24-
25-
var coinAverageMock = new MockRateProvider();
26-
coinAverageMock.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("BTC_USD"), new BidAsk(5000m)));
27-
coinAverageMock.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("BTC_EUR"), new BidAsk(4000m)));
28-
coinAverageMock.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("XMR_BTC"), new BidAsk(4500m)));
29-
rateProviderFactory.Providers.Add("coingecko", coinAverageMock);
30-
31-
var kraken = new MockRateProvider();
32-
kraken.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("BTC_USD"), new BidAsk(0.1m)));
33-
kraken.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("XMR_USD"), new BidAsk(0.1m)));
34-
kraken.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("XMR_BTC"), new BidAsk(0.1m)));
35-
rateProviderFactory.Providers.Add("kraken", kraken);
36-
}
37-
38-
await s.RegisterNewUser(true);
39-
await s.CreateNewStore(preferredExchange: "Kraken");
40-
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
41-
await s.Page.Locator("input#PrimaryAddress")
42-
.FillAsync(
43-
"43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
44-
await s.Page.Locator("input#PrivateViewKey")
45-
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
46-
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
47-
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
48-
var message = await s.Page
49-
.GetByText("View-only wallet created. The wallet will soon become available.")
50-
.InnerTextAsync();
51-
Assert.Contains("View-only wallet created", message);
52-
await s.Page.CheckAsync("#Enabled");
53-
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "2");
54-
await s.Page.ClickAsync("#SaveButton");
55-
56-
// Set rate provider
57-
await s.Page.Locator("#menu-item-General").ClickAsync();
58-
await s.Page.Locator("#menu-item-Rates").ClickAsync();
59-
await s.Page.FillAsync("#DefaultCurrencyPairs", "BTC_USD,XMR_USD,XMR_BTC");
60-
await s.Page.SelectOptionAsync("#PrimarySource_PreferredExchange", "kraken");
61-
await s.Page.Locator("#page-primary").ClickAsync();
62-
63-
// Generate a new invoice
64-
await s.Page.Locator("a.nav-link[href*='invoices']").ClickAsync();
65-
await s.Page.Locator("#page-primary").ClickAsync();
66-
await s.Page.FillAsync("#Amount", "4.20");
67-
await s.Page.FillAsync("#BuyerEmail", "monero@monero.com");
68-
await Task.Delay(TimeSpan.FromSeconds(25)); // wallet-rpc needs some time to sync. refactor this later
69-
await s.Page.Locator("#page-primary").ClickAsync();
21+
await SetupWalletAndGenerateInvoice(s);
7022

7123
// View the invoice
7224
var href = await s.Page.Locator("a[href^='/i/']").GetAttributeAsync("href");
@@ -104,6 +56,44 @@ await s.Page.Locator("input#PrivateViewKey")
10456
await IntegrationTestUtils.CleanUpAsync(s);
10557
}
10658

59+
[Fact]
60+
public async Task ShouldAdvanceSubaddressIndexWhenOutOfSync()
61+
{
62+
await using var s = CreatePlaywrightTester();
63+
await s.StartAsync();
64+
65+
await SetupWalletAndGenerateInvoice(s);
66+
67+
await IntegrationTestUtils.CleanUpAsync(s, false);
68+
69+
MoneroRpcProvider moneroRpcProvider = s.Server.PayTester.GetService<MoneroRpcProvider>();
70+
await moneroRpcProvider.WalletRpcClients["XMR"]
71+
.SendCommandAsync<GenerateFromKeysRequest, GenerateFromKeysResponse>("generate_from_keys",
72+
new GenerateFromKeysRequest
73+
{
74+
PrimaryAddress =
75+
"43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L",
76+
PrivateViewKey = "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e",
77+
WalletFileName = "wallet",
78+
Password = ""
79+
});
80+
81+
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
82+
83+
// Generate a new invoice
84+
await s.Page.Locator("a.nav-link[href*='invoices']").ClickAsync();
85+
await s.Page.Locator("#page-primary").ClickAsync();
86+
await s.Page.FillAsync("#Amount", "4.20");
87+
await s.Page.FillAsync("#BuyerEmail", "monero@monero.com");
88+
await Task.Delay(TimeSpan.FromSeconds(25)); // wallet-rpc needs some time to sync. refactor this later
89+
await s.Page.Locator("#page-primary").ClickAsync();
90+
91+
// Fails to view the second invoice
92+
await s.Page.Locator("a[href^='/i/']").GetAttributeAsync("href");
93+
94+
await IntegrationTestUtils.CleanUpAsync(s);
95+
}
96+
10797
[Fact]
10898
public async Task ShouldFailWhenWrongPrimaryAddress()
10999
{
@@ -135,20 +125,24 @@ public async Task ShouldFailWhenWalletFileAlreadyExists()
135125
await s.StartAsync();
136126

137127
MoneroRpcProvider moneroRpcProvider = s.Server.PayTester.GetService<MoneroRpcProvider>();
138-
await moneroRpcProvider.WalletRpcClients["XMR"].SendCommandAsync<GenerateFromKeysRequest, GenerateFromKeysResponse>("generate_from_keys", new GenerateFromKeysRequest
139-
{
140-
PrimaryAddress = "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L",
141-
PrivateViewKey = "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e",
142-
WalletFileName = "wallet",
143-
Password = ""
144-
});
128+
await moneroRpcProvider.WalletRpcClients["XMR"]
129+
.SendCommandAsync<GenerateFromKeysRequest, GenerateFromKeysResponse>("generate_from_keys",
130+
new GenerateFromKeysRequest
131+
{
132+
PrimaryAddress =
133+
"43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L",
134+
PrivateViewKey = "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e",
135+
WalletFileName = "wallet",
136+
Password = ""
137+
});
145138
await moneroRpcProvider.CloseWallet("XMR");
146139

147140
await s.RegisterNewUser(true);
148141
await s.CreateNewStore();
149142
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
150143
await s.Page.Locator("input#PrimaryAddress")
151-
.FillAsync("43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
144+
.FillAsync(
145+
"43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
152146
await s.Page.Locator("input#PrivateViewKey")
153147
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
154148
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
@@ -198,4 +192,58 @@ public async Task ShouldLoadViewWalletWithPasswordOnStartUpIfExists()
198192

199193
await IntegrationTestUtils.CleanUpAsync(s);
200194
}
195+
196+
static async Task SetupWalletAndGenerateInvoice(PlaywrightTester s)
197+
{
198+
if (s.Server.PayTester.MockRates)
199+
{
200+
var rateProviderFactory = s.Server.PayTester.GetService<RateProviderFactory>();
201+
rateProviderFactory.Providers.Clear();
202+
203+
var coinAverageMock = new MockRateProvider();
204+
coinAverageMock.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("BTC_USD"), new BidAsk(5000m)));
205+
coinAverageMock.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("BTC_EUR"), new BidAsk(4000m)));
206+
coinAverageMock.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("XMR_BTC"), new BidAsk(4500m)));
207+
rateProviderFactory.Providers.Add("coingecko", coinAverageMock);
208+
209+
var kraken = new MockRateProvider();
210+
kraken.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("BTC_USD"), new BidAsk(0.1m)));
211+
kraken.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("XMR_USD"), new BidAsk(0.1m)));
212+
kraken.ExchangeRates.Add(new PairRate(CurrencyPair.Parse("XMR_BTC"), new BidAsk(0.1m)));
213+
rateProviderFactory.Providers.Add("kraken", kraken);
214+
}
215+
216+
await s.RegisterNewUser(true);
217+
await s.CreateNewStore(preferredExchange: "Kraken");
218+
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
219+
await s.Page.Locator("input#PrimaryAddress")
220+
.FillAsync(
221+
"43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
222+
await s.Page.Locator("input#PrivateViewKey")
223+
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
224+
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
225+
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
226+
var message = await s.Page
227+
.GetByText("View-only wallet created. The wallet will soon become available.")
228+
.InnerTextAsync();
229+
Assert.Contains("View-only wallet created", message);
230+
await s.Page.CheckAsync("#Enabled");
231+
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "2");
232+
await s.Page.ClickAsync("#SaveButton");
233+
234+
// Set rate provider
235+
await s.Page.Locator("#menu-item-General").ClickAsync();
236+
await s.Page.Locator("#menu-item-Rates").ClickAsync();
237+
await s.Page.FillAsync("#DefaultCurrencyPairs", "BTC_USD,XMR_USD,XMR_BTC");
238+
await s.Page.SelectOptionAsync("#PrimarySource_PreferredExchange", "kraken");
239+
await s.Page.Locator("#page-primary").ClickAsync();
240+
241+
// Generate a new invoice
242+
await s.Page.Locator("a.nav-link[href*='invoices']").ClickAsync();
243+
await s.Page.Locator("#page-primary").ClickAsync();
244+
await s.Page.FillAsync("#Amount", "4.20");
245+
await s.Page.FillAsync("#BuyerEmail", "monero@monero.com");
246+
await Task.Delay(TimeSpan.FromSeconds(25)); // wallet-rpc needs some time to sync. refactor this later
247+
await s.Page.Locator("#page-primary").ClickAsync();
248+
}
201249
}

0 commit comments

Comments
 (0)