public static void ConfigureNRustLightningAuth(this IServiceCollection services, IConfiguration Configuration) { // configure lsat/macaroon authentication services.AddSingleton <IMacaroonSecretRepository, InMemoryMacaroonSecretRepository>(); // services.AddSingleton<ILSATInvoiceProvider, InMemoryRepository>(); string?ourServiceName = null; int ourServiceTier = 0; var lsatConfig = Configuration.GetSection("LSAT"); services.AddAuthentication(options => { options.DefaultScheme = LSATDefaults.Scheme; options.DefaultChallengeScheme = LSATDefaults.Scheme; }).AddLSATAuthentication(options => { options.ServiceName = "nrustlightning"; options.ServiceTier = ourServiceTier; lsatConfig.Bind(options); ourServiceName = options.ServiceName; ourServiceTier = options.ServiceTier; // we want to give users only read capability when they have payed for it. not write. options.MacaroonCaveats.Add($"{ourServiceName}{DotNetLightning.Payment.LSAT.Constants.CAPABILITIES_CONDITION_PREFIX}=read"); int amount = lsatConfig.GetOrDefault("amount", 1); options.InvoiceAmount = LNMoney.MilliSatoshis((long)amount); }); services.AddAuthorization(options => { options.AddPolicy("Readonly", policy => { policy.RequireClaim("service", $"{ourServiceName}:{ourServiceTier}"); policy.RequireClaim($"{ourServiceName}{DotNetLightning.Payment.LSAT.Constants.CAPABILITIES_CONDITION_PREFIX}", "read", "admin"); }); options.AddPolicy("Admin", policy => { policy.RequireClaim("service", $"{ourServiceName}:{ourServiceTier}"); policy.RequireClaim($"{ourServiceName}{DotNetLightning.Payment.LSAT.Constants.CAPABILITIES_CONDITION_PREFIX}", "admin"); }); }); }
public void CanCreateAndCloseChannel() { using var channelManager = PeerManagerTests.getTestPeerManager().ChannelManager; var pk = _pubKeys[0]; channelManager.CreateChannel(pk, Money.Satoshis(100000), LNMoney.MilliSatoshis(1000L), UInt64.MaxValue); var c = channelManager.ListChannels(_pool); Assert.Single(c); Assert.Equal(c[0].RemoteNetworkId, pk); Assert.Equal(100000U, c[0].ChannelValueSatoshis); Assert.Equal(1000U, c[0].InboundCapacityMSat); Assert.Equal(100000UL * 1000UL - 1000UL, c[0].OutboundCapacityMSat); Assert.False(c[0].IsLive); channelManager.CloseChannel(c[0].ChannelId); var events = channelManager.GetAndClearPendingEvents(_pool); Assert.Empty(events); channelManager.Dispose(); }
public void CanCallSendPayment() { var peerMan = getTestPeerManager(); var paymentHash = Primitives.PaymentHash.NewPaymentHash(uint256.Parse("4141414141414141414141414141414141414141414141414141414141414142")); var lastHops = new List <RouteHint>(); var e = Assert.Throws <FFIException>(() => peerMan.SendPayment(_keys[0].PubKey, paymentHash, lastHops, LNMoney.MilliSatoshis(100L), TEST_FINAL_CTLV)); Assert.Contains("Cannot route when there are no outbound routes away from us", e.Message); var secret = uint256.Parse("4141414141414141414141414141414141414141414141414141414141414143"); e = Assert.Throws <FFIException>(() => peerMan.SendPayment(_keys[0].PubKey, paymentHash, lastHops, LNMoney.MilliSatoshis(100L), TEST_FINAL_CTLV, secret)); Assert.Contains("Cannot route when there are no outbound routes away from us", e.Message); }
public async Task PayInvoice(PaymentRequest invoice, long?amountMSat = null, CancellationToken ct = default) { var amount = invoice.AmountValue?.Value.MilliSatoshi ?? amountMSat; if (amount is null) { throw new NRustLightningException($"You must specify payment amount if it is not included in invoice"); } var n = _networkProvider.TryGetByInvoice(invoice); if (n is null) { throw new NRustLightningException($"Unknown invoice prefix {invoice.PrefixValue}"); } var peerMan = _peerManagerProvider.GetPeerManager(n); var failureTcs = new TaskCompletionSource <Event>(); var successTcs = new TaskCompletionSource <Event>(); _eventAggregator.Subscribe <Event>(e => { if (e is Event.PaymentFailed paymentFailed && paymentFailed.Item.PaymentHash.Equals(invoice.PaymentHash)) { _logger.LogError($"Payment for invoice ({invoice}) failed"); failureTcs.SetResult(paymentFailed); } if (e is Event.PaymentSent paymentSent && paymentSent.Item.Hash.Equals(invoice.PaymentHash)) { _logger.LogInformation($"Payment for invoice ({invoice}) succeed"); successTcs.SetResult(paymentSent); } }); peerMan.SendPayment(invoice.NodeIdValue.Item, invoice.PaymentHash, new List <RouteHint>(), LNMoney.MilliSatoshis(amount.Value), invoice.MinFinalCLTVExpiryDelta); peerMan.ProcessEvents(); var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); cts.CancelAfter(TimeSpan.FromSeconds(_config.Value.PaymentTimeoutSec)); var delay = Task.Delay(TimeSpan.FromMilliseconds(-1), cts.Token); var task = Task.WhenAny(failureTcs.Task, successTcs.Task); await Task.WhenAny(task, delay); if (cts.IsCancellationRequested) { throw new NRustLightningException($"Payment for {invoice} did not finish in {_config.Value.PaymentTimeoutSec} seconds"); } var resultEvent = await await task; if (resultEvent is Event.PaymentFailed paymentFailed) { if (paymentFailed.Item.RejectedByDest) { throw new NRustLightningException($"Failed to pay! rejected by destination"); } throw new NRustLightningException($"Failed to pay!"); } if (resultEvent is Event.PaymentSent paymentSent) { await _invoiceRepository.SetPreimage(paymentSent.Item); } }
public async Task PayInvoice(PaymentRequest invoice, long?amountMSat = null, CancellationToken ct = default) { var amount = invoice.AmountValue?.Value.MilliSatoshi ?? amountMSat; if (amount is null) { throw new NRustLightningException($"You must specify payment amount if it is not included in invoice"); } var n = _networkProvider.TryGetByInvoice(invoice); if (n is null) { throw new NRustLightningException($"Unknown invoice prefix {invoice.PrefixValue}"); } var peerMan = _peerManagerProvider.GetPeerManager(n); var failureTcs = new TaskCompletionSource <Event>(TaskCreationOptions.RunContinuationsAsynchronously); var successTcs = new TaskCompletionSource <Event>(TaskCreationOptions.RunContinuationsAsynchronously); _eventAggregator.Subscribe <Event>(e => { if (e is Event.PaymentFailed paymentF && paymentF.Item.PaymentHash.Equals(invoice.PaymentHash)) { _logger.LogError($"Payment for invoice ({invoice}) failed"); failureTcs.SetResult(paymentF); } if (e is Event.PaymentSent paymentS && paymentS.Item.Hash.Equals(invoice.PaymentHash)) { _logger.LogInformation($"Payment for invoice ({invoice}) succeed"); successTcs.SetResult(paymentS); } }); peerMan.SendPayment(invoice.NodeIdValue.Item, invoice.PaymentHash, new List <RouteHint>(), LNMoney.MilliSatoshis(amount.Value), invoice.MinFinalCLTVExpiryDelta, _pool, invoice.PaymentSecret.Value); peerMan.ProcessEvents(); // case 1: canceled by user. var cancelTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); await using var _ = (ct.Register(state => { ((TaskCompletionSource <object>)state).TrySetResult(null); }, cancelTcs)); var cancelTask = cancelTcs.Task; // case 2: timeout. using var cts = new CancellationTokenSource(); var timeoutTask = Task.Delay(TimeSpan.FromSeconds(_config.Value.PaymentTimeoutSec), cts.Token); // case 3: finishes var task = Task.WhenAny(failureTcs.Task, successTcs.Task); var resultTask = await Task.WhenAny(cancelTask, timeoutTask, task); if (resultTask == cancelTask) { throw new NRustLightningException($"Payment canceled."); } if (resultTask == timeoutTask) { throw new NRustLightningException($"Payment for {invoice} did not finish in {_config.Value.PaymentTimeoutSec} seconds"); } cts.Cancel(); // cancel the timer task so it does not fire. var resultEvent = await await task; if (resultEvent is Event.PaymentFailed paymentFailed) { if (paymentFailed.Item.RejectedByDest) { throw new NRustLightningException($"Failed to pay! rejected by destination"); } throw new NRustLightningException($"Failed to pay!"); } if (resultEvent is Event.PaymentSent paymentSent) { await _repository.SetPreimage(paymentSent.Item, ct); } }
public override LNMoney?Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return(LNMoney.MilliSatoshis(reader.GetInt64())); }
public async Task CanCallSendPayment() { var hostBuilder = new HostBuilder().ConfigureTestHost(); using var host = await hostBuilder.StartAsync(); var c = host.GetTestNRustLightningClient(); var e = await Assert.ThrowsAsync <HttpRequestException>(async() => await c.PayToInvoiceAsync("lnbcrt1p03zqaapp54vmm7lg9fjjnm6v998v8cafzqcnzecjnqlq8dk55rhgzlrgstzasdqqcqzpgsp58vt9tjxuvx8jmy4q0wtdakdu24k6zlx8np67w8pxmvcmwcacsa3q9qy9qsqx8h8dmt0fsqel426tu0ayrscaty0pt4t3tg2rz0jpl7p3xyx6hynwhhc86h7apmmf9043n250275cuuad6npdasqclk0ga9htyq0v0qqjs26z3")); Assert.Equal("You must specify payment amount if it is not included in invoice", e.Message); e = await Assert.ThrowsAsync <HttpRequestException>(async() => await c.PayToInvoiceAsync("lnbcrt1p03zqaapp54vmm7lg9fjjnm6v998v8cafzqcnzecjnqlq8dk55rhgzlrgstzasdqqcqzpgsp58vt9tjxuvx8jmy4q0wtdakdu24k6zlx8np67w8pxmvcmwcacsa3q9qy9qsqx8h8dmt0fsqel426tu0ayrscaty0pt4t3tg2rz0jpl7p3xyx6hynwhhc86h7apmmf9043n250275cuuad6npdasqclk0ga9htyq0v0qqjs26z3", LNMoney.MilliSatoshis(100L))); Assert.Contains("Cannot route when there are no outbound routes away from us", e.Message); }