< Summary - Combined Code Coverage

Information
Class: NLightning.Application.Channels.Handlers.FundingCreatedMessageHandler
Assembly: NLightning.Application
File(s): /home/runner/work/NLightning/NLightning/src/NLightning.Application/Channels/Handlers/FundingCreatedMessageHandler.cs
Tag: 57_24045730253
Line coverage
0%
Covered lines: 0
Uncovered lines: 66
Coverable lines: 66
Total lines: 150
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
HandleAsync()0%7280%
PersistChannelAsync()0%620%

File(s)

/home/runner/work/NLightning/NLightning/src/NLightning.Application/Channels/Handlers/FundingCreatedMessageHandler.cs

#LineLine coverage
 1using Microsoft.Extensions.Logging;
 2
 3namespace NLightning.Application.Channels.Handlers;
 4
 5using Domain.Bitcoin.Interfaces;
 6using Domain.Bitcoin.Transactions.Enums;
 7using Domain.Bitcoin.Transactions.Interfaces;
 8using Domain.Channels.Enums;
 9using Domain.Channels.Interfaces;
 10using Domain.Channels.Models;
 11using Domain.Crypto.ValueObjects;
 12using Domain.Exceptions;
 13using Domain.Node.Options;
 14using Domain.Persistence.Interfaces;
 15using Domain.Protocol.Interfaces;
 16using Domain.Protocol.Messages;
 17using Infrastructure.Bitcoin.Builders.Interfaces;
 18using Infrastructure.Bitcoin.Wallet.Interfaces;
 19using Interfaces;
 20
 21public class FundingCreatedMessageHandler : IChannelMessageHandler<FundingCreatedMessage>
 22{
 23    private readonly IBlockchainMonitor _blockchainMonitor;
 24    private readonly IChannelIdFactory _channelIdFactory;
 25    private readonly IChannelMemoryRepository _channelMemoryRepository;
 26    private readonly ICommitmentTransactionBuilder _commitmentTransactionBuilder;
 27    private readonly ICommitmentTransactionModelFactory _commitmentTransactionModelFactory;
 28    private readonly ILightningSigner _lightningSigner;
 29    private readonly ILogger<FundingCreatedMessageHandler> _logger;
 30    private readonly IMessageFactory _messageFactory;
 31    private readonly IUnitOfWork _unitOfWork;
 32
 033    public FundingCreatedMessageHandler(IBlockchainMonitor blockchainMonitor, IChannelIdFactory channelIdFactory,
 034                                        IChannelMemoryRepository channelMemoryRepository,
 035                                        ICommitmentTransactionBuilder commitmentTransactionBuilder,
 036                                        ICommitmentTransactionModelFactory commitmentTransactionModelFactory,
 037                                        ILightningSigner lightningSigner, ILogger<FundingCreatedMessageHandler> logger,
 038                                        IMessageFactory messageFactory, IUnitOfWork unitOfWork)
 39    {
 040        _blockchainMonitor = blockchainMonitor;
 041        _channelIdFactory = channelIdFactory;
 042        _channelMemoryRepository = channelMemoryRepository;
 043        _commitmentTransactionBuilder = commitmentTransactionBuilder;
 044        _commitmentTransactionModelFactory = commitmentTransactionModelFactory;
 045        _lightningSigner = lightningSigner;
 046        _logger = logger;
 047        _messageFactory = messageFactory;
 048        _unitOfWork = unitOfWork;
 049    }
 50
 51    public async Task<IChannelMessage?> HandleAsync(FundingCreatedMessage message, ChannelState currentState,
 52                                                    FeatureOptions negotiatedFeatures, CompactPubKey peerPubKey)
 53    {
 054        _logger.LogTrace("Processing FundingCreatedMessage with ChannelId: {ChannelId} from Peer: {PeerPubKey}",
 055                         message.Payload.ChannelId, peerPubKey);
 56
 057        var payload = message.Payload;
 58
 059        if (currentState != ChannelState.None)
 060            throw new ChannelErrorException("A channel with this id already exists", payload.ChannelId);
 61
 62        // Check if there's a temporary channel for this peer
 063        if (!_channelMemoryRepository.TryGetTemporaryChannelState(peerPubKey, payload.ChannelId, out currentState))
 064            throw new ChannelErrorException("This channel has never been negotiated", payload.ChannelId);
 65
 066        if (currentState != ChannelState.V1Opening)
 067            throw new ChannelErrorException("Channel had the wrong state", payload.ChannelId,
 068                                            "This channel is already being negotiated with peer");
 69
 70        // Get the channel and set missing props
 071        if (!_channelMemoryRepository.TryGetTemporaryChannel(peerPubKey, payload.ChannelId, out var channel))
 072            throw new ChannelErrorException("Temporary channel not found", payload.ChannelId);
 73
 074        channel.FundingOutput.TransactionId = payload.FundingTxId;
 075        channel.FundingOutput.Index = payload.FundingOutputIndex;
 76
 77        // Create a new channelId
 078        var oldChannelId = channel.ChannelId;
 079        channel.UpdateChannelId(_channelIdFactory.CreateV1(payload.FundingTxId, payload.FundingOutputIndex));
 80
 81        // Register the channel with the signer
 082        _lightningSigner.RegisterChannel(channel.ChannelId, channel.GetSigningInfo());
 83
 84        // Generate the base commitment transactions
 085        var localCommitmentTransaction =
 086            _commitmentTransactionModelFactory.CreateCommitmentTransactionModel(channel, CommitmentSide.Local);
 087        var remoteCommitmentTransaction =
 088            _commitmentTransactionModelFactory.CreateCommitmentTransactionModel(channel, CommitmentSide.Remote);
 89
 90        // Build the output and the transactions
 091        var localUnsignedCommitmentTransaction = _commitmentTransactionBuilder.Build(localCommitmentTransaction);
 092        var remoteUnsignedCommitmentTransaction = _commitmentTransactionBuilder.Build(remoteCommitmentTransaction);
 93
 94        // Validate remote signature for our local commitment transaction
 095        _lightningSigner.ValidateSignature(channel.ChannelId, payload.Signature, localUnsignedCommitmentTransaction);
 96
 97        // Sign our remote commitment transaction
 098        var ourSignature =
 099            _lightningSigner.SignChannelTransaction(channel.ChannelId, remoteUnsignedCommitmentTransaction);
 100
 101        // Update the channel with the new signatures and the new state
 0102        channel.UpdateLastReceivedSignature(payload.Signature);
 0103        channel.UpdateLastSentSignature(ourSignature);
 0104        channel.UpdateState(ChannelState.V1FundingSigned);
 105
 106        // Save to the database
 0107        await PersistChannelAsync(channel);
 108
 109        // Create the funding signed message
 0110        var fundingSignedMessage =
 0111            _messageFactory.CreateFundingSignedMessage(channel.ChannelId, ourSignature);
 112
 113        // Add the channel to the dictionary
 0114        _channelMemoryRepository.AddChannel(channel);
 115
 116        // Remove the temporary channel
 0117        _channelMemoryRepository.TryRemoveTemporaryChannel(peerPubKey, oldChannelId);
 118
 0119        await _blockchainMonitor.WatchTransactionAsync(channel.ChannelId, payload.FundingTxId,
 0120                                                       channel.ChannelConfig.MinimumDepth);
 121
 0122        return fundingSignedMessage;
 0123    }
 124
 125    /// <summary>
 126    /// Persists a channel to the database using the scoped Unit of Work
 127    /// </summary>
 128    private async Task PersistChannelAsync(ChannelModel channel)
 129    {
 130        try
 131        {
 132            // TODO: REVIEW FULL FLOW
 133            // Check if the channel already exists
 0134            var existingChannel = await _unitOfWork.ChannelDbRepository.GetByIdAsync(channel.ChannelId);
 0135            if (existingChannel is not null)
 0136                throw new ChannelWarningException("Channel already exists", channel.ChannelId,
 0137                                                  "This channel is already in our database");
 138
 0139            await _unitOfWork.ChannelDbRepository.AddAsync(channel);
 0140            await _unitOfWork.SaveChangesAsync();
 141
 0142            _logger.LogDebug("Successfully persisted channel {ChannelId} to database", channel.ChannelId);
 0143        }
 0144        catch (Exception ex)
 145        {
 0146            _logger.LogError(ex, "Failed to persist channel {ChannelId} to database", channel.ChannelId);
 0147            throw;
 148        }
 0149    }
 150}