Skip to content

Commit 7b54b82

Browse files
Add administration methods
1 parent 257031f commit 7b54b82

20 files changed

+547
-15
lines changed

Monero.Lws.IntegrationTests/MoneroLwsServiceIntegrationTest.cs

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Monero.Lws.IntegrationTests;
66
public class MoneroLwsServiceIntegrationTest
77
{
88
private static readonly string Address = TestUtils.Address;
9-
private static readonly string ViewKey = TestUtils.ViewKey;
9+
private static readonly string ViewKey = TestUtils.PrivateViewKey;
1010
private static readonly MoneroLwsService Lws = TestUtils.GetLwsService();
1111

1212
[Fact]
@@ -26,6 +26,18 @@ public async Task TestGetVersion()
2626
Assert.False(response.Testnet);
2727
}
2828

29+
[Fact]
30+
public async Task GetDaemonStatus()
31+
{
32+
var response = await Lws.GetDaemonStatus();
33+
Assert.True(response.OutgoingConnectionsCount >= 0);
34+
Assert.True(response.IncomingConnectionsCount >= 0);
35+
Assert.True(response.Height >= 0);
36+
Assert.True(response.TargetHeight >= 0);
37+
Assert.False(string.IsNullOrEmpty(response.Network));
38+
Assert.False(string.IsNullOrEmpty(response.State));
39+
}
40+
2941
[Fact]
3042
public async Task TestLogin()
3143
{
@@ -43,6 +55,33 @@ public async Task TestLogin()
4355
Assert.Null(response.StartHeight);
4456
}
4557
}
58+
59+
[Fact]
60+
public async Task TestAcceptRequests()
61+
{
62+
var requests = await Lws.ListRequests();
63+
List<string> addressesToCreate = [];
64+
65+
foreach (var createRequest in requests.Create)
66+
{
67+
addressesToCreate.Add(createRequest.Address);
68+
}
69+
70+
var created = await Lws.AcceptRequests("create", addressesToCreate);
71+
72+
Assert.Equal(addressesToCreate.Count, created.UpdatedAddresses.Count);
73+
74+
List<string> addressesToImport = [];
75+
76+
foreach (var importRequest in requests.Import)
77+
{
78+
addressesToImport.Add(importRequest.Address);
79+
}
80+
81+
var imported = await Lws.AcceptRequests("import", addressesToImport);
82+
83+
Assert.Equal(addressesToImport.Count, imported.UpdatedAddresses.Count);
84+
}
4685

4786
[Fact]
4887
public async Task TestGetAddressInfo()
@@ -179,6 +218,83 @@ public async Task TestGetSubaddrs()
179218
TestSubaddrsEntry(entry);
180219
}
181220
}
221+
222+
[Fact]
223+
public async Task TestRescan()
224+
{
225+
var response = await Lws.Rescan(0, [Address]);
226+
Assert.NotEmpty(response.UpdatedAddresses);
227+
Assert.Single(response.UpdatedAddresses);
228+
Assert.Equal(Address, response.UpdatedAddresses.First());
229+
}
230+
231+
[Fact]
232+
public async Task TestValidate()
233+
{
234+
var response = await Lws.Validate(TestUtils.PublicViewKey, TestUtils.PublicSpendKey, TestUtils.PrivateViewKey);
235+
236+
if (response.Error != null)
237+
{
238+
Assert.Fail($"{response.Error.Field}: {response.Error.Details}");
239+
}
240+
241+
Assert.False(string.IsNullOrEmpty(response.Address));
242+
Assert.Equal(TestUtils.Address, response.Address);
243+
}
244+
245+
[Fact]
246+
public async Task TestListAccounts()
247+
{
248+
var response = await Lws.ListAccounts();
249+
TestAccounts(response.Active);
250+
TestAccounts(response.Inactive);
251+
TestAccounts(response.Hidden);
252+
}
253+
254+
[Fact]
255+
public async Task TestListRequests()
256+
{
257+
var response = await Lws.ListRequests();
258+
TestAccounts(response.Create, true);
259+
TestAccounts(response.Import, true);
260+
}
261+
262+
[Fact]
263+
public async Task TestAddAccount()
264+
{
265+
var address = "43a1cERdj8rT1513tmMUY5MBcWbt1hgSo2fgLhoRrkYTPXejjRjU9y2WCjYfdZMLfZ6LKVc7YRGJMdtxD3x9Dtjc6fFjH9q";
266+
var viewKey = "4f8d491198f5219b80a03ae2be337b37ace5a4626c67e80a68beb7d0e3eaaa08";
267+
268+
var accounts = await Lws.ListAccounts();
269+
var found = accounts.Active.Find(x => x.Address.Equals(address));
270+
if (found != null)
271+
{
272+
// account already added
273+
return;
274+
}
275+
276+
var response = await Lws.AddAccount(address, viewKey);
277+
Assert.NotEmpty(response.UpdatedAddresses);
278+
Assert.Single(response.UpdatedAddresses);
279+
Assert.Equal(address, response.UpdatedAddresses.First());
280+
}
281+
282+
[Fact]
283+
public async Task TestModifyAccountStatus()
284+
{
285+
// deactivate account
286+
var response = await Lws.ModifyAccountStatus("inactive", [TestUtils.Address]);
287+
Assert.NotEmpty(response.UpdatedAddresses);
288+
Assert.Single(response.UpdatedAddresses);
289+
Assert.Equal(TestUtils.Address, response.UpdatedAddresses.First());
290+
// wait for lws to catch up
291+
Thread.Sleep(5000);
292+
// reactivate account
293+
response = await Lws.ModifyAccountStatus("active", [TestUtils.Address]);
294+
Assert.NotEmpty(response.UpdatedAddresses);
295+
Assert.Single(response.UpdatedAddresses);
296+
Assert.Equal(TestUtils.Address, response.UpdatedAddresses.First());
297+
}
182298

183299
private static void TestTransaction(MoneroLwsTransaction? tx)
184300
{
@@ -355,4 +471,31 @@ private static void TestAddressMeta(MoneroLwsAddressMeta? addressMeta)
355471
Assert.True(addressMeta.MinIndex >= 0);
356472
}
357473

474+
private static void TestAccount(MoneroLwsAccount? account, bool request)
475+
{
476+
Assert.NotNull(account);
477+
Assert.False(string.IsNullOrEmpty(account.Address));
478+
if (request)
479+
{
480+
Assert.True(account.StartHeight >= 0);
481+
return;
482+
}
483+
484+
Assert.True(account.ScanHeight >= 0);
485+
Assert.True(account.AccessTime >= 0);
486+
}
487+
488+
private static void TestAccounts(List<MoneroLwsAccount>? accounts, bool request)
489+
{
490+
Assert.NotNull(accounts);
491+
foreach (var account in accounts)
492+
{
493+
TestAccount(account, request);
494+
}
495+
}
496+
497+
private static void TestAccounts(List<MoneroLwsAccount>? accounts)
498+
{
499+
TestAccounts(accounts, false);
500+
}
358501
}

Monero.Lws.IntegrationTests/Utils/TestUtils.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ internal static class TestUtils
77
public const string Username = "";
88
public const string Password = "";
99
public const string Address = "42EhKmBx6pAPYhX4QCHKBPRw8dgc3VVVdA7g2dxr5wz21crqvPUkwPTde64Xac5uawQeFbh6K7PD4YLqiX1VTP5jUH7gZez";
10-
public const string ViewKey = "41f55a92b942681e35bf7bb64f71142729039bd8e606a4f4218c543065c15c05";
10+
public const string PublicViewKey = "b244f89be70e16db0d8905628480708d590ffd4e820303bb61c96cf2395bfaf1";
11+
public const string PublicSpendKey = "1030f7c992ec9b86cc0055d2c44632951104e67b05d28c367ecd8382c0931303";
12+
public const string PrivateViewKey = "41f55a92b942681e35bf7bb64f71142729039bd8e606a4f4218c543065c15c05";
1113

1214
private static MoneroLwsService? _lwsService = null;
1315

1416
public static MoneroLwsService GetLwsService()
1517
{
1618
if (_lwsService == null)
1719
{
18-
_lwsService = new MoneroLwsService(LwsServiceUri, "lws", Username, Password);
20+
_lwsService = new MoneroLwsService(LwsServiceUri, "lws", "admin", Username, Password);
1921
}
2022

2123
return _lwsService;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Monero.Lws.Common;
4+
5+
public class MoneroLwsAccount
6+
{
7+
/// <summary>
8+
/// Account primary address.
9+
/// </summary>
10+
[JsonPropertyName("address")] public string Address { get; set; } = "";
11+
12+
/// <summary>
13+
/// Account scan height.
14+
/// </summary>
15+
[JsonPropertyName("scan_height")] public long ScanHeight { get; set; } = 0;
16+
17+
/// <summary>
18+
/// Account start height.
19+
/// </summary>
20+
[JsonPropertyName("start_height")] public long StartHeight { get; set; } = 0;
21+
22+
/// <summary>
23+
/// Account last access time.
24+
/// </summary>
25+
[JsonPropertyName("access_time")] public long AccessTime { get; set; } = 0;
26+
27+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Monero.Lws.Common;
4+
5+
public class MoneroLwsDaemonStatus
6+
{
7+
/// <summary>
8+
/// Outgoing connections from daemon.
9+
/// </summary>
10+
[JsonPropertyName("outgoing_connections_count")] public long OutgoingConnectionsCount { get; set; } = 0;
11+
12+
/// <summary>
13+
/// Incoming connections to daemon.
14+
/// </summary>
15+
[JsonPropertyName("incoming_connections_count")] public long IncomingConnectionsCount { get; set; } = 0;
16+
17+
/// <summary>
18+
/// Daemon height.
19+
/// </summary>
20+
[JsonPropertyName("height")] public long Height { get; set; } = 0;
21+
22+
/// <summary>
23+
/// Target height.
24+
/// </summary>
25+
[JsonPropertyName("target_height")] public long TargetHeight { get; set; } = 0;
26+
27+
/// <summary>
28+
/// Network type.
29+
/// </summary>
30+
[JsonPropertyName("network")] public string Network { get; set; } = "";
31+
32+
/// <summary>
33+
/// Daemon status.
34+
/// </summary>
35+
[JsonPropertyName("state")] public string State { get; set; } = "";
36+
}

0 commit comments

Comments
 (0)