< Summary - Combined Code Coverage

Information
Class: NLightning.Domain.Channels.Validators.ChannelOpenValidator
Assembly: NLightning.Domain
File(s): /home/runner/work/NLightning/NLightning/src/NLightning.Domain/Channels/Validators/ChannelOpenValidator.cs
Tag: 57_24045730253
Line coverage
0%
Covered lines: 0
Uncovered lines: 77
Coverable lines: 77
Total lines: 154
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 76
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%
PerformOptionalChecks(...)0%506220%
PerformMandatoryChecks(...)0%2970540%

File(s)

/home/runner/work/NLightning/NLightning/src/NLightning.Domain/Channels/Validators/ChannelOpenValidator.cs

#LineLine coverage
 1namespace NLightning.Domain.Channels.Validators;
 2
 3using Bitcoin.Transactions.Constants;
 4using Constants;
 5using Domain.Enums;
 6using Exceptions;
 7using Interfaces;
 8using Money;
 9using Node.Options;
 10using Parameters;
 11
 12public class ChannelOpenValidator : IChannelOpenValidator
 13{
 14    private readonly NodeOptions _nodeOptions;
 15
 016    public ChannelOpenValidator(NodeOptions nodeOptions)
 17    {
 018        _nodeOptions = nodeOptions;
 019    }
 20
 21    /// <inheritdoc/>
 22    public void PerformOptionalChecks(ChannelOpenOptionalValidationParameters parameters)
 23    {
 24        // Check if Funding Satoshis is too small
 025        if (parameters.FundingAmount is not null && parameters.FundingAmount < _nodeOptions.MinimumChannelSize)
 026            throw new ChannelErrorException($"Funding amount is too small: {parameters.FundingAmount}");
 27
 28        // Check if we consider htlc_minimum_msat too large. IE. 20% bigger than our htlc minimum amount
 029        if (parameters.HtlcMinimumAmount is not null
 030         && parameters.HtlcMinimumAmount > _nodeOptions.HtlcMinimumAmount * 1.2M)
 031            throw new ChannelErrorException($"Htlc minimum amount is too large: {parameters.HtlcMinimumAmount}");
 32
 33        // Check if we consider max_htlc_value_in_flight_msat too small. IE. 20% smaller than our maximum htlc value
 034        if (parameters.FundingAmount is not null && parameters.MaxHtlcValueInFlight is not null)
 35        {
 036            var ourMaxHtlcValueInFlight =
 037                LightningMoney.Satoshis(_nodeOptions.AllowUpToPercentageOfChannelFundsInFlight *
 038                                        parameters.FundingAmount.Satoshi / 100M);
 039            if (parameters.MaxHtlcValueInFlight < ourMaxHtlcValueInFlight * 0.8M)
 040                throw new ChannelErrorException(
 041                    $"Max htlc value in flight is too small: {parameters.MaxHtlcValueInFlight}");
 42        }
 43
 44        // If the channel amount is too small, we can have the channelReserve smaller than our dust
 045        var ourChannelReserveAmount = parameters.OurChannelReserveAmount;
 046        if (ourChannelReserveAmount < parameters.DustLimitAmount)
 047            ourChannelReserveAmount = parameters.DustLimitAmount;
 48
 49        // Check if we consider channel_reserve_satoshis too large. IE. 20% bigger than our 1% channel reserve
 050        if (parameters.ChannelReserveAmount > ourChannelReserveAmount * 1.2M)
 051            throw new ChannelErrorException($"Channel reserve amount is too large: {parameters.ChannelReserveAmount}");
 52
 53        // Check if we consider max_accepted_htlcs too small. IE. 20% smaller than our max-accepted htlcs
 054        if (parameters.MaxAcceptedHtlcs < (ushort)(_nodeOptions.MaxAcceptedHtlcs * 0.8M))
 055            throw new ChannelErrorException($"Max accepted htlcs is too small: {parameters.MaxAcceptedHtlcs}");
 56
 57        // Check if we consider dust_limit_satoshis too large. IE. 75% bigger than our dust limit
 058        if (parameters.DustLimitAmount > _nodeOptions.DustLimitAmount * 1.75M)
 059            throw new ChannelErrorException($"Dust limit amount is too large: {parameters.DustLimitAmount}");
 060    }
 61
 62    /// <inheritdoc/>
 63    public void PerformMandatoryChecks(ChannelOpenMandatoryValidationParameters parameters,
 64                                       out uint minimumDepth)
 65    {
 66        // Check if ChainHash is compatible
 067        if (parameters.ChainHash is not null && parameters.ChainHash != _nodeOptions.BitcoinNetwork.ChainHash)
 068            throw new ChannelErrorException("ChainHash is not compatible");
 69
 70        // Check if we consider to_self_delay unreasonably large. IE. 50% bigger than our to_self_delay
 071        if (parameters.ToSelfDelay > _nodeOptions.ToSelfDelay * 1.5M)
 072            throw new ChannelErrorException($"To self delay is too large: {parameters.ToSelfDelay}");
 73
 74        // Check max_accepted_htlcs is too large
 075        if (parameters.MaxAcceptedHtlcs > ChannelConstants.MaxAcceptedHtlcs)
 076            throw new ChannelErrorException($"Max accepted htlcs is too small: {parameters.MaxAcceptedHtlcs}");
 77
 078        if (parameters.FeeRatePerKw is not null)
 79        {
 80            // Check if we consider fee_rate_per_kw too large
 081            if (parameters.FeeRatePerKw > ChannelConstants.MaxFeePerKw)
 082                throw new ChannelErrorException($"Fee rate per kw is too large: {parameters.FeeRatePerKw}");
 83
 84            // Check if we consider fee_rate_per_kw too small. IE. 20% smaller than our fee rate
 085            if (parameters.FeeRatePerKw < ChannelConstants.MinFeePerKw ||
 086                parameters.FeeRatePerKw < parameters.CurrentFeeRatePerKw * 0.8M)
 087                throw new ChannelErrorException(
 088                    $"Fee rate per kw is too small: {parameters.FeeRatePerKw}, currentFee{parameters.CurrentFeeRatePerKw
 89        }
 90
 91        // Check if the dust limit is greater than the channel reserve amount
 092        if (parameters.DustLimitAmount > parameters.ChannelReserveAmount)
 093            throw new ChannelErrorException(
 094                $"Dust limit({parameters.DustLimitAmount}) is greater than channel reserve({parameters.ChannelReserveAmo
 95
 96        // Check if dust_limit_satoshis is too small
 097        if (parameters.DustLimitAmount < ChannelConstants.MinDustLimitAmount)
 098            throw new ChannelErrorException($"Dust limit amount is too small: {parameters.DustLimitAmount}");
 99
 0100        if (parameters.FundingAmount is not null)
 101        {
 102            // Check if the push amount is too large
 0103            if (parameters.PushAmount is not null
 0104             && parameters.PushAmount > 1_000 * parameters.FundingAmount)
 0105                throw new ChannelErrorException($"Push amount is too large: {parameters.PushAmount}");
 106
 107            // Check if there are enough funds to pay for fees
 0108            var expectedWeight = parameters.NegotiatedFeatures.OptionAnchors > FeatureSupport.No
 0109                                     ? TransactionConstants.InitialCommitmentTransactionWeightNoAnchor
 0110                                     : TransactionConstants.InitialCommitmentTransactionWeightWithAnchor;
 0111            var expectedFee = LightningMoney.Satoshis(expectedWeight * parameters.CurrentFeeRatePerKw.Satoshi / 1000);
 0112            if (parameters.FundingAmount < expectedFee + parameters.ChannelReserveAmount)
 0113                throw new ChannelErrorException(
 0114                    $"Funding amount is too small to cover fees: {parameters.FundingAmount}");
 115
 116            // Check if this is a large channel and if we support it
 0117            if (parameters.FundingAmount >= ChannelConstants.LargeChannelAmount &&
 0118                parameters.NegotiatedFeatures.LargeChannels == FeatureSupport.No)
 0119                throw new ChannelErrorException("We don't support large channels");
 120        }
 121
 122        // Check if ChannelType exists
 0123        minimumDepth = _nodeOptions.MinimumDepth;
 0124        if (parameters.ChannelTypeTlv is null)
 0125            throw new ChannelErrorException("ChannelTypeTlv is not present");
 126
 127        // Check if OptionStaticRemoteKey is Compulsory
 0128        if (!parameters.ChannelTypeTlv.Features.IsFeatureSet(Feature.OptionStaticRemoteKey, true))
 0129            throw new ChannelErrorException("Static remote key feature is compulsory but not set by peer",
 0130                                            "ChannelTypeTlv: Static remote key is compulsory");
 131
 0132        if (parameters.ChannelTypeTlv.Features.IsFeatureSet(Feature.OptionAnchors, true)
 0133         && parameters.NegotiatedFeatures.OptionAnchors == FeatureSupport.No)
 0134            throw new ChannelErrorException("Anchor outputs feature is not supported but requested by peer",
 0135                                            "ChannelTypeTlv: We don't support anchor outputs");
 136
 0137        if (parameters.ChannelTypeTlv.Features.IsFeatureSet(Feature.OptionScidAlias, true))
 138        {
 0139            if (parameters.ChannelFlags is not null && parameters.ChannelFlags.Value.AnnounceChannel)
 0140                throw new ChannelErrorException("Invalid channel flags for OPTION_SCID_ALIAS",
 0141                                                "ChannelTypeTlv: We want to announce this channel");
 142        }
 143
 144        // Check for ZeroConf feature
 0145        if (parameters.ChannelTypeTlv.Features.IsFeatureSet(Feature.OptionZeroconf, true))
 146        {
 0147            if (_nodeOptions.Features.ZeroConf == FeatureSupport.No)
 0148                throw new ChannelErrorException("ZeroConf feature not supported but requested by peer",
 0149                                                "ChannelTypeTlv: We don't support ZeroConf with you");
 150
 0151            minimumDepth = 0U;
 152        }
 0153    }
 154}