private async Task HandleEvent(Event e, CancellationToken cancellationToken) { _logger.LogDebug($"Handling event {e}"); _eventAggregator.Publish(e); var peerManager = _peerManagerProvider.GetPeerManager(_network); var chanMan = peerManager.ChannelManager; if (e is Event.FundingGenerationReady f) { var witScriptId = PayToWitScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(f.Item.OutputScript) ?? Infrastructure.Utils.Utils.Fail <WitScriptId>($"Failed to extract wit script from {f.Item.OutputScript.ToHex()}! this should never happen."); var outputAddress = witScriptId.GetAddress(_network.NBitcoinNetwork); var tx = await _walletService.GetSendingTxAsync(outputAddress, f.Item.ChannelValueSatoshis, _network, cancellationToken); var nOut = tx.Outputs.Select((txo, i) => (txo, i)) .First(item => item.txo.ScriptPubKey == outputAddress.ScriptPubKey).i; var fundingTxo = new OutPoint(tx.GetHash(), nOut); Debug.Assert(_pendingFundingTx.TryAdd(tx.GetHash(), tx)); _logger.LogDebug($"Finished creating funding tx {tx.ToHex()}; id: {tx.GetHash()}"); chanMan.FundingTransactionGenerated(f.Item.TemporaryChannelId.Value, fundingTxo); peerManager.ProcessEvents(); } else if (e is Event.FundingBroadcastSafe fundingBroadcastSafe) { var h = fundingBroadcastSafe.Item.OutPoint.Item.Hash; if (!_pendingFundingTx.TryGetValue(h, out var fundingTx)) { _logger.LogCritical($"RL asked us to broadcast unknown funding tx for id: ({h})! this should never happen."); return; } await _walletService.BroadcastAsync(fundingTx, _network).ConfigureAwait(false); } else if (e is Event.PaymentReceived paymentReceived) { var a = paymentReceived.Item.Amount; var hash = paymentReceived.Item.PaymentHash; var secret = paymentReceived.Item.PaymentSecret.GetOrDefault(); var(result, intendedAmount) = await _invoiceService.PaymentReceived(hash, a, secret); _logger.LogDebug($"Received payment of type {result}. Payment hash {hash}. PaymentSecret: {secret}"); if (result == PaymentReceivedType.UnknownPaymentHash) { _logger.LogError($"Received payment for unknown payment_hash({hash}). ignoring."); return; } var preImage = await _repository.GetPreimage(hash); _logger.LogDebug($"preimage {preImage.ToHex()}"); if (result == PaymentReceivedType.Ok) { if (chanMan.ClaimFunds(preImage, secret, (ulong)intendedAmount.MilliSatoshi)) { peerManager.ProcessEvents(); } } else { if (chanMan.FailHTLCBackwards(hash, secret)) { peerManager.ProcessEvents(); } else { _logger.LogCritical($"RL told us that preimage ({preImage}) and/or its hash ({hash}) is unknown to us. This should never happen"); } } } else if (e is Event.PaymentSent paymentSent) { await _repository.SetPreimage(paymentSent.Item); } else if (e is Event.PaymentFailed paymentFailed) { _logger.LogInformation($"payment failed: {paymentFailed.Item.PaymentHash}" + (paymentFailed.Item.RejectedByDest ? "rejected by destination" : "")); } else if (e is Event.PendingHTLCsForwardable pendingHtlCsForwardable) { #if DEBUG var wait = TimeSpan.Zero; #else var wait = pendingHtlCsForwardable.Item.TimeToWait(_random); #endif await Task.Delay(wait, cancellationToken); peerManager.ChannelManager.ProcessPendingHTLCForwards(); peerManager.ProcessEvents(); } else if (e is Event.SpendableOutputs spendableOutputs) { var chan = _channelProvider.GetSpendableOutputDescriptorChannel(_network.CryptoCode); foreach (var o in spendableOutputs.Item) { _logger.LogInformation($"New spendable on-chain funds txid: {o.OutPoint.Item.Hash}. vout: {o.OutPoint.Item.N}"); await chan.Writer.WriteAsync(o, cancellationToken); } } else { throw new Exception("Unreachable!"); } }