lnp/channel/bolt/
policy.rs

1// LNP/BP Core Library implementing LNPBP specifications & standards
2// Written in 2020-2022 by
3//     Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the MIT License
11// along with this software.
12// If not, see <https://opensource.org/licenses/MIT>.
13
14use std::fmt::Debug;
15use std::ops::Range;
16
17#[cfg(feature = "serde")]
18use amplify::ToYamlString;
19use lnp2p::bolt::{AcceptChannel, ChannelType, OpenChannel};
20
21/// Limit for the maximum number of the accepted HTLCs towards some node
22pub const BOLT3_MAX_ACCEPTED_HTLC_LIMIT: u16 = 483;
23
24/// BOLT-3 dust limit
25pub const BOLT3_DUST_LIMIT: u64 = 354;
26
27/// Errors from [BOLT-2] policy validations for `open_channel` and
28/// `accept_channel` messages.
29///
30/// [BOLT-2]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md
31#[derive(
32    Clone,
33    Copy,
34    PartialEq,
35    Eq,
36    Hash,
37    Debug,
38    Display,
39    Error,
40    StrictEncode,
41    StrictDecode
42)]
43#[display(doc_comments)]
44pub enum PolicyError {
45    /// proposed `to_self_delay` value {proposed} is unreasonably large and
46    /// exceeds node policy limit of {allowed_maximum}; rejecting the channel
47    /// according to BOLT-2
48    ToSelfDelayUnreasonablyLarge { proposed: u16, allowed_maximum: u16 },
49
50    /// proposed limit for maximum accepted number of HTLCs {0} exceeds BOLT-3
51    /// requirement to be below 483; rejecting the channel according to BOLT-2
52    MaxAcceptedHtlcLimitExceeded(u16),
53
54    /// proposed fee rate {proposed} sat/kw is outside of the fee rate policy
55    /// of the local node ({lowest_accepted}..{highest_accepted} sat/kw);
56    /// rejecting the channel according to BOLT-2
57    FeeRateUnreasonable {
58        proposed: u32,
59        lowest_accepted: u32,
60        highest_accepted: u32,
61    },
62
63    /// proposed channel reserve limit {reserve} sat is less than dust limit
64    /// {dust_limit} sat; rejecting the channel according to BOLT-2
65    ChannelReserveLessDust { reserve: u64, dust_limit: u64 },
66
67    /// dust limit {0} sat is less than protocol minimum requirement of 354
68    /// sat; rejecting the channel according to BOLT-2
69    DustLimitTooSmall(u64),
70
71    /// offered channel funding of {proposed} sat is too small and less than
72    /// {required_minimum} required by the node policy; rejecting the channel
73    /// according to BOLT-2
74    ChannelFundingTooSmall {
75        proposed: u64,
76        required_minimum: u64,
77    },
78
79    /// HTLC minimum {proposed} is too large and exceeds node policy
80    /// requirements ({allowed_maximum}); rejecting the channel according to
81    /// BOLT-2
82    HtlcMinimumTooLarge { proposed: u64, allowed_maximum: u64 },
83
84    /// HTLC-in-flight maximum requirement of {proposed} is too small and
85    /// does not match the node policy; the smallest requirement is
86    /// {required_minimum}; rejecting the channel according to BOLT-2
87    HtlcInFlightMaximumTooSmall {
88        proposed: u64,
89        required_minimum: u64,
90    },
91
92    /// requested {proposed} channel reserve is too large and exceeds local
93    /// policy requirement of {allowed_maximum}; rejecting the channel
94    /// according to BOLT-2
95    ChannelReserveTooLarge { proposed: u64, allowed_maximum: u64 },
96
97    /// maximum number of HTLCs {proposed} that can be accepted by the remote
98    /// node is too small and does not match node policy requirement of
99    /// {required_minimum}; rejecting the channel according to BOLT-2
100    MaxAcceptedHtlcsTooSmall {
101        proposed: u16,
102        required_minimum: u16,
103    },
104
105    /// dust limit {proposed} sats exceeds node policy requirement of
106    /// {allowed_maximum}; rejecting the channel according to BOLT-2
107    DustLimitTooLarge { proposed: u64, allowed_maximum: u64 },
108
109    /// minimum depth of {proposed} requested by the remote peer is exceeds
110    /// local policy limit of {allowed_maximum}; rejecting the channel
111    /// according to BOLT-2
112    UnreasonableMinDepth { proposed: u32, allowed_maximum: u32 },
113
114    /// `channel_reserve_satoshis` ({channel_reserve}) is less than
115    /// `dust_limit_satoshis` ({dust_limit}) within the `open_channel`
116    /// message; rejecting the channel according to BOLT-2
117    LocalDustExceedsRemoteReserve {
118        channel_reserve: u64,
119        dust_limit: u64,
120    },
121
122    /// `channel_reserve_satoshis` from the open_channel message
123    /// ({channel_reserve}) is less than `dust_limit_satoshis`
124    /// ({dust_limit}; rejecting the channel according to BOLT-2
125    RemoteDustExceedsLocalReserve {
126        channel_reserve: u64,
127        dust_limit: u64,
128    },
129}
130
131/// Policy to validate channel parameters proposed by a remote peer.
132///
133/// By default, [`crate::Channel::new`] uses reasonable default policy created
134/// by [`Policy::default()`] method. Channel creator may provide a custom policy
135/// by using [`crate::Channel::with`] method.
136#[derive(Clone, Eq, PartialEq, Hash, Debug, StrictEncode, StrictDecode)]
137#[cfg_attr(
138    feature = "serde",
139    derive(Display, Serialize, Deserialize),
140    serde(crate = "serde_crate"),
141    display(Policy::to_yaml_string)
142)]
143pub struct Policy {
144    /// Reasonable limit to check value of `to_self_delay` required by a remote
145    /// node, in blocks.
146    pub to_self_delay_max: u16,
147
148    /// Range of acceptable channel fees.
149    pub feerate_per_kw_range: Range<u32>,
150
151    /// Minimum funding transaction mining depth required from the remote node
152    /// for a channel proposed by it.
153    pub minimum_depth: u32,
154
155    // The following are optional policies which may not be set by a local
156    // node:
157    /// Maximum funding transaction mining depth which may be required by a
158    /// remote node for a channel opened by a local node.
159    pub maximum_depth: Option<u32>,
160
161    /// Minimum funding for a channel by this node.
162    pub funding_satoshis_min: Option<u64>,
163
164    /// The maximum acceptable limit on the value stored in a single HTLC.
165    pub htlc_minimum_msat_max: Option<u64>,
166
167    /// Minimum boundary for the upper limit of in-flight HTLC funds.
168    pub max_htlc_value_in_flight_msat_min: Option<u64>,
169
170    /// Maximum reserve for a channel from a local node required by the remote
171    /// node in absolute value.
172    pub channel_reserve_satoshis_max_abs: Option<u64>,
173
174    /// Maximum reserve for a channel from a local node required by the remote
175    /// node in persents from the channel funding.
176    pub channel_reserve_satoshis_max_percent: Option<u8>,
177
178    /// Minimum boundary to the limit of HTLCs offered to a remote peer.
179    pub max_accepted_htlcs_min: Option<u16>,
180
181    /// Maximum value for the dust limit required by a remote node.
182    pub dust_limit_satoshis_max: Option<u64>,
183}
184
185#[cfg(feature = "serde")]
186impl ToYamlString for Policy {}
187
188impl Default for Policy {
189    /// Sets reasonable values for the local node policies
190    fn default() -> Policy {
191        Policy {
192            to_self_delay_max: 250,
193            // normal operational range for the fees in bitcoin network - it
194            // really never went above 100 to get tx mined within an hour or two
195            feerate_per_kw_range: 1..100,
196            // three blocks is enough to get sufficient security
197            minimum_depth: 3,
198            // 6 blocks is enough to provide the necessary security
199            maximum_depth: Some(6),
200            // no reason of spamming blockchain with channels < 10000 sats
201            funding_satoshis_min: Some(10000),
202            // HTLCs can be arbitrary small:
203            htlc_minimum_msat_max: None,
204            // we need to earn commissions on routing, so limiting HTLCs too
205            // much does not make sense
206            max_htlc_value_in_flight_msat_min: Some(10000),
207            max_accepted_htlcs_min: Some(10),
208            // we do not want to over-collateralize on our channels in regard to
209            // the size of the channel: it should not exceed 10% of funds in the
210            // channel.
211            channel_reserve_satoshis_max_abs: None,
212            channel_reserve_satoshis_max_percent: Some(10),
213            // we do not want to require too large `to_local` / `to_remote`
214            // outputs
215            dust_limit_satoshis_max: Some(1000),
216        }
217    }
218}
219
220impl Policy {
221    /// Sets policy to match default policy used in c-lightning
222    pub fn with_clightning_defaults() -> Policy {
223        Policy {
224            to_self_delay_max: 14 * 24 * 6,
225            feerate_per_kw_range: 1..1000,
226            minimum_depth: 3,
227            maximum_depth: Some(6),
228            funding_satoshis_min: Some(10000),
229            htlc_minimum_msat_max: None,
230            max_htlc_value_in_flight_msat_min: Some(10000),
231            max_accepted_htlcs_min: Some(10),
232            channel_reserve_satoshis_max_abs: None,
233            // c-lightning uses 10% of the channel funding as a reserve
234            channel_reserve_satoshis_max_percent: Some(10),
235            dust_limit_satoshis_max: Some(546),
236        }
237    }
238
239    /// Sets policy to match default policy used in LND
240    pub fn with_lnd_defaults() -> Policy {
241        Policy {
242            to_self_delay_max: 14 * 24 * 6,
243            feerate_per_kw_range: 1..1000,
244            minimum_depth: 3,
245            maximum_depth: Some(6),
246            funding_satoshis_min: Some(20000),
247            htlc_minimum_msat_max: None,
248            max_htlc_value_in_flight_msat_min: Some(10000),
249            max_accepted_htlcs_min: Some(10),
250            channel_reserve_satoshis_max_abs: None,
251            // LND uses 1% of the channel funding as a reserve
252            channel_reserve_satoshis_max_percent: Some(1),
253            // Since LND 0.13.3 there is no default value for dust limit
254            // DustLimitForSize retrieves the dust limit for a given pkscript
255            // size 546 is the biggest value for p2pkh
256            // https://github.com/lightningnetwork/lnd/pull/5781
257            dust_limit_satoshis_max: Some(546),
258        }
259    }
260
261    /// Sets policy to match default policy used in Eclair
262    pub fn with_eclair_defaults() -> Policy {
263        Policy {
264            to_self_delay_max: 14 * 24 * 6,
265            feerate_per_kw_range: 1..1000,
266            minimum_depth: 3,
267            maximum_depth: Some(6),
268            funding_satoshis_min: Some(100000),
269            htlc_minimum_msat_max: None,
270            max_htlc_value_in_flight_msat_min: Some(10000),
271            max_accepted_htlcs_min: Some(10),
272            channel_reserve_satoshis_max_abs: None,
273            // Eclair uses 5% of the channel funding as a reserve
274            channel_reserve_satoshis_max_percent: Some(5),
275            dust_limit_satoshis_max: Some(546),
276        }
277    }
278
279    fn validate_peer_params(
280        &self,
281        params: PeerParams,
282    ) -> Result<(), PolicyError> {
283        // if `to_self_delay` is unreasonably large.
284        if params.to_self_delay > self.to_self_delay_max {
285            return Err(PolicyError::ToSelfDelayUnreasonablyLarge {
286                proposed: params.to_self_delay,
287                allowed_maximum: self.to_self_delay_max,
288            });
289        }
290
291        // if `max_accepted_htlcs` is greater than 483.
292        if params.max_accepted_htlcs > BOLT3_MAX_ACCEPTED_HTLC_LIMIT {
293            return Err(PolicyError::MaxAcceptedHtlcLimitExceeded(
294                params.max_accepted_htlcs,
295            ));
296        }
297
298        // if `dust_limit_satoshis` is greater than `channel_reserve_satoshis`.
299        if params.dust_limit_satoshis > params.channel_reserve_satoshis {
300            return Err(PolicyError::ChannelReserveLessDust {
301                reserve: params.channel_reserve_satoshis,
302                dust_limit: params.dust_limit_satoshis,
303            });
304        }
305
306        // if `dust_limit_satoshis` is smaller than 354 satoshis
307        if params.dust_limit_satoshis < BOLT3_DUST_LIMIT {
308            return Err(PolicyError::DustLimitTooSmall(
309                params.dust_limit_satoshis,
310            ));
311        }
312
313        // if we consider `htlc_minimum_msat` too large
314        if let Some(limit) = self.htlc_minimum_msat_max {
315            if params.htlc_minimum_msat > limit {
316                return Err(PolicyError::HtlcMinimumTooLarge {
317                    proposed: params.htlc_minimum_msat,
318                    allowed_maximum: limit,
319                });
320            }
321        }
322
323        // if we consider `max_htlc_value_in_flight_msat` too small
324        if let Some(limit) = self.max_htlc_value_in_flight_msat_min {
325            if params.max_htlc_value_in_flight_msat < limit {
326                return Err(PolicyError::HtlcInFlightMaximumTooSmall {
327                    proposed: params.max_htlc_value_in_flight_msat,
328                    required_minimum: limit,
329                });
330            }
331        }
332
333        // if we consider `channel_reserve_satoshis` too large in absolute
334        // values
335        if let Some(limit) = self.channel_reserve_satoshis_max_abs {
336            if params.channel_reserve_satoshis > limit {
337                return Err(PolicyError::ChannelReserveTooLarge {
338                    proposed: params.channel_reserve_satoshis,
339                    allowed_maximum: limit,
340                });
341            }
342        }
343
344        // if we consider `max_accepted_htlcs` too small
345        if let Some(limit) = self.max_accepted_htlcs_min {
346            if params.max_accepted_htlcs < limit {
347                return Err(PolicyError::MaxAcceptedHtlcsTooSmall {
348                    proposed: params.max_accepted_htlcs,
349                    required_minimum: limit,
350                });
351            }
352        }
353
354        // if we consider `dust_limit_satoshis` too large
355        if let Some(limit) = self.dust_limit_satoshis_max {
356            if params.dust_limit_satoshis > limit {
357                return Err(PolicyError::DustLimitTooLarge {
358                    proposed: params.dust_limit_satoshis,
359                    allowed_maximum: limit,
360                });
361            }
362        }
363
364        Ok(())
365    }
366
367    /// Validates parameters proposed by remote peer in `open_channel` message
368    /// against the policy
369    ///
370    /// # Arguments
371    /// - `self`: local policy;
372    /// - `open_channel`: BOLT-2 message received by the peer.
373    ///
374    /// # Returns
375    /// [`PeerParams`] to use for constructing channel transactions which should
376    /// be signed by the local node.
377    pub fn validate_inbound(
378        &self,
379        open_channel: &OpenChannel,
380    ) -> Result<PeerParams, PolicyError> {
381        // if we consider `feerate_per_kw` too small for timely processing or
382        // unreasonably large.
383        if !self
384            .feerate_per_kw_range
385            .contains(&open_channel.feerate_per_kw)
386        {
387            return Err(PolicyError::FeeRateUnreasonable {
388                proposed: open_channel.feerate_per_kw,
389                lowest_accepted: self.feerate_per_kw_range.start,
390                highest_accepted: self.feerate_per_kw_range.end,
391            });
392        }
393
394        // if `funding_satoshis` is too small
395        if let Some(limit) = self.funding_satoshis_min {
396            if open_channel.funding_satoshis < limit {
397                return Err(PolicyError::ChannelFundingTooSmall {
398                    proposed: open_channel.funding_satoshis,
399                    required_minimum: limit,
400                });
401            }
402        }
403
404        // if we consider `channel_reserve_satoshis` too large in relative
405        // values
406        if let Some(percents) = self.channel_reserve_satoshis_max_percent {
407            let limit =
408                open_channel.funding_satoshis as f32 * (percents as f32 / 100.);
409            let limit = limit as u64;
410            if open_channel.channel_reserve_satoshis > limit {
411                return Err(PolicyError::ChannelReserveTooLarge {
412                    proposed: open_channel.channel_reserve_satoshis,
413                    allowed_maximum: limit,
414                });
415            }
416        }
417
418        let peer_params = PeerParams::from(open_channel);
419        self.validate_peer_params(peer_params)?;
420        Ok(peer_params)
421    }
422
423    /// Confirms that parameters which were asked by a remote node via
424    /// `accept_channel` message are confirming our policy.
425    ///
426    /// # Arguments
427    /// - `self`: local policy;
428    /// - `params`: parameters proposed by the local node in `open_channel`
429    ///   message;
430    /// - `accept_channel`: BOLT-2 message received by the peer.
431    ///
432    /// # Returns
433    /// [`PeerParams`] to use for constructing channel transactions which should
434    /// be signed by the local node.
435    pub fn confirm_outbound(
436        &self,
437        our_params: PeerParams,
438        accept_channel: &AcceptChannel,
439    ) -> Result<PeerParams, PolicyError> {
440        // if `minimum_depth` is unreasonably large:
441        //
442        //     MAY reject the channel.
443        if let Some(limit) = self.maximum_depth {
444            if accept_channel.minimum_depth > limit {
445                return Err(PolicyError::UnreasonableMinDepth {
446                    proposed: accept_channel.minimum_depth,
447                    allowed_maximum: limit,
448                });
449            }
450        }
451
452        // if `channel_reserve_satoshis` is less than `dust_limit_satoshis`
453        // within the open_channel message:
454        //
455        //     MUST reject the channel.
456        if accept_channel.channel_reserve_satoshis
457            < our_params.dust_limit_satoshis
458        {
459            return Err(PolicyError::LocalDustExceedsRemoteReserve {
460                channel_reserve: accept_channel.channel_reserve_satoshis,
461                dust_limit: our_params.dust_limit_satoshis,
462            });
463        }
464
465        // if `channel_reserve_satoshis` from the open_channel message is less
466        // than `dust_limit_satoshis`:
467        //
468        //     MUST reject the channel.
469        if our_params.channel_reserve_satoshis
470            < accept_channel.dust_limit_satoshis
471        {
472            return Err(PolicyError::RemoteDustExceedsLocalReserve {
473                channel_reserve: our_params.channel_reserve_satoshis,
474                dust_limit: accept_channel.dust_limit_satoshis,
475            });
476        }
477
478        let peer_params = PeerParams::from(accept_channel);
479        self.validate_peer_params(peer_params)?;
480        Ok(peer_params)
481    }
482}
483
484/// Structure containing part of the channel configuration (and state, as it
485/// contains adjustible fee) which must follow specific policies and be accepted
486/// or validated basing on those policies and additional protocol-level
487/// requirements.
488///
489/// This information applies for both channel peers and used in constructing
490/// both sides of asymmetric transactions.
491#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, StrictEncode, StrictDecode)]
492#[cfg_attr(
493    feature = "serde",
494    derive(Display, Serialize, Deserialize),
495    serde(crate = "serde_crate"),
496    display(CommonParams::to_yaml_string)
497)]
498pub struct CommonParams {
499    /// Minimum depth of the funding transaction before the channel is
500    /// considered open
501    pub minimum_depth: u32,
502
503    /// indicates the initial fee rate in satoshi per 1000-weight (i.e. 1/4 the
504    /// more normally-used 'satoshi per 1000 vbytes') that this side will pay
505    /// for commitment and HTLC transactions, as described in BOLT #3 (this can
506    /// be adjusted later with an update_fee message).
507    pub feerate_per_kw: u32,
508
509    /// The least-significant bit of `channel_flags`. Indicates whether the
510    /// initiator of the funding flow wishes to advertise this channel publicly
511    /// to the network, as detailed within BOLT #7.
512    pub announce_channel: bool,
513
514    /// Channel types are an explicit enumeration: for convenience of future
515    /// definitions they reuse even feature bits, but they are not an arbitrary
516    /// combination (they represent the persistent features which affect the
517    /// channel operation).
518    pub channel_type: ChannelType,
519}
520
521#[cfg(feature = "serde")]
522impl ToYamlString for CommonParams {}
523
524impl Default for CommonParams {
525    /// Sets reasonable values for the common channel parameters used in
526    /// constructing `open_channel` message.
527    ///
528    /// Usually this should not be used and instead [`crate::Channel::with`]
529    /// should be provided with custom channel parameters basing on the
530    /// current state of the bitcoin mempool and hash rate.
531    fn default() -> Self {
532        CommonParams {
533            minimum_depth: 3,
534            feerate_per_kw: 256,
535            announce_channel: true,
536            channel_type: ChannelType::default(),
537        }
538    }
539}
540
541impl CommonParams {
542    /// Extracts common parameters from the incoming `open_channel` message and
543    /// local default requirement for the minimum depth.
544    #[inline]
545    pub fn with(open_channel: &OpenChannel, minimum_depth: u32) -> Self {
546        CommonParams {
547            minimum_depth,
548            feerate_per_kw: open_channel.feerate_per_kw,
549            announce_channel: open_channel.should_announce_channel(),
550            channel_type: open_channel.channel_type.unwrap_or_default(),
551        }
552    }
553}
554
555/// Structure containing part of the channel state which must follow specific
556/// policies and be accepted or validated basing on those policies and
557/// additional protocol-level requirements.
558///
559/// This information applies for only to one of the peers and requested by the
560/// other peer. It is used in constructing transactions which should be signed
561/// by the node demanding this requirements.
562///
563/// Should be instantiated from the node
564/// configuration persistent storage and/or command line parameters and provided
565/// to the channel constructor via [`crate::Channel::with`].
566///
567/// Later, when creating new channels, it should be copied from the local
568/// channel defaults object and updated / checked against local policies upon
569/// receiving `accept_channel` reply by setting
570/// [`super::BoltChannel::remote_params`] to a value returned from
571/// [`super::BoltChannel::local_params`][`.confirm_outbound`](Policy::
572/// confirm_outbound) method.
573///
574/// Upon receiving `open_channel` message from the remote node must validate the
575/// proposed parameters against local policy with
576/// [`super::BoltChannel::policy`][`.validate_inbound`](Policy::
577/// validate_inbound) method and assign the return value to
578/// [`super::BoltChannel::remote_params`].
579#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, StrictEncode, StrictDecode)]
580#[cfg_attr(
581    feature = "serde",
582    derive(Display, Serialize, Deserialize),
583    serde(crate = "serde_crate"),
584    display(PeerParams::to_yaml_string)
585)]
586pub struct PeerParams {
587    /// The threshold below which outputs on transactions broadcast by sender
588    /// will be omitted
589    pub dust_limit_satoshis: u64,
590
591    /// The number of blocks which the counterparty will have to wait to claim
592    /// on-chain funds if they broadcast a commitment transaction
593    pub to_self_delay: u16,
594
595    /// Indicates the smallest value HTLC this node will accept.
596    pub htlc_minimum_msat: u64,
597
598    /// The maximum inbound HTLC value in flight towards sender, in
599    /// milli-satoshi
600    pub max_htlc_value_in_flight_msat: u64,
601
602    /// The minimum value unencumbered by HTLCs for the counterparty to keep in
603    /// the channel
604    pub channel_reserve_satoshis: u64,
605
606    /// The maximum number of inbound HTLCs towards sender
607    pub max_accepted_htlcs: u16,
608}
609
610#[cfg(feature = "serde")]
611impl ToYamlString for PeerParams {}
612
613impl Default for PeerParams {
614    /// Sets reasonable values for the channel parameters requested from the
615    /// other peer in sent `open_channel` or `accept_channel` messages.
616    ///
617    /// Usually this should not be used and instead [`crate::Channel::with`]
618    /// should be provided with custom channel parameters basing on the user
619    /// preferences.
620    fn default() -> Self {
621        PeerParams {
622            dust_limit_satoshis: BOLT3_DUST_LIMIT,
623            to_self_delay: 3,
624            htlc_minimum_msat: 1,
625            max_htlc_value_in_flight_msat: 1_000_000_000,
626            channel_reserve_satoshis: 10000,
627            max_accepted_htlcs: BOLT3_MAX_ACCEPTED_HTLC_LIMIT,
628        }
629    }
630}
631
632impl From<&OpenChannel> for PeerParams {
633    /// Extracts peer-specific parameters from the incoming `open_channel`
634    /// message. These parameters are applied to the local node.
635    #[inline]
636    fn from(open_channel: &OpenChannel) -> Self {
637        PeerParams {
638            dust_limit_satoshis: open_channel.dust_limit_satoshis,
639            to_self_delay: open_channel.to_self_delay,
640            htlc_minimum_msat: open_channel.htlc_minimum_msat,
641            max_htlc_value_in_flight_msat: open_channel
642                .max_htlc_value_in_flight_msat,
643            channel_reserve_satoshis: open_channel.channel_reserve_satoshis,
644            max_accepted_htlcs: open_channel.max_accepted_htlcs,
645        }
646    }
647}
648
649impl From<&AcceptChannel> for PeerParams {
650    /// Extracts peer-specific parameters from the incoming `accept_channel`
651    /// message. These parameters are applied to the local node.
652    #[inline]
653    fn from(accept_channel: &AcceptChannel) -> Self {
654        PeerParams {
655            dust_limit_satoshis: accept_channel.dust_limit_satoshis,
656            to_self_delay: accept_channel.to_self_delay,
657            htlc_minimum_msat: accept_channel.htlc_minimum_msat,
658            max_htlc_value_in_flight_msat: accept_channel
659                .max_htlc_value_in_flight_msat,
660            channel_reserve_satoshis: accept_channel.channel_reserve_satoshis,
661            max_accepted_htlcs: accept_channel.max_accepted_htlcs,
662        }
663    }
664}
665
666#[cfg(test)]
667mod test {
668    use amplify::DumbDefault;
669    use p2p::bolt::OpenChannel;
670
671    use super::*;
672
673    // Returns a default open channel message.
674    fn get_open_channel() -> OpenChannel {
675        let mut open_channel = OpenChannel::dumb_default();
676        open_channel.to_self_delay = 250;
677        open_channel.max_accepted_htlcs = BOLT3_MAX_ACCEPTED_HTLC_LIMIT;
678        open_channel.channel_reserve_satoshis = 10000;
679        open_channel.max_htlc_value_in_flight_msat = 10000;
680        open_channel.dust_limit_satoshis = BOLT3_DUST_LIMIT;
681        open_channel.htlc_minimum_msat = 10;
682        open_channel.feerate_per_kw = 1;
683
684        open_channel
685    }
686
687    // Returns a default accept channel message.
688    fn get_accept_channel() -> AcceptChannel {
689        let mut accept_channel = AcceptChannel::dumb_default();
690        accept_channel.to_self_delay = 250;
691        accept_channel.max_accepted_htlcs = BOLT3_MAX_ACCEPTED_HTLC_LIMIT;
692        accept_channel.channel_reserve_satoshis = 10000;
693        accept_channel.max_htlc_value_in_flight_msat = 10000;
694        accept_channel.dust_limit_satoshis = BOLT3_DUST_LIMIT;
695        accept_channel.htlc_minimum_msat = 10;
696
697        accept_channel
698    }
699
700    #[test]
701    fn test_to_self_delay_too_large() {
702        let policy = Policy::default();
703        let mut open_channel = get_open_channel();
704
705        open_channel.to_self_delay = policy.to_self_delay_max + 1;
706
707        let params = PeerParams::from(&open_channel);
708        let error = policy.validate_peer_params(params);
709
710        assert_eq!(
711            error,
712            Err(PolicyError::ToSelfDelayUnreasonablyLarge {
713                proposed: params.to_self_delay,
714                allowed_maximum: policy.to_self_delay_max,
715            })
716        );
717    }
718
719    #[test]
720    fn test_max_accepted_htlc_limit_exceeded() {
721        let policy = Policy::default();
722        let mut open_channel = get_open_channel();
723
724        open_channel.max_accepted_htlcs = BOLT3_MAX_ACCEPTED_HTLC_LIMIT + 1;
725
726        let params = PeerParams::from(&open_channel);
727        let error = policy.validate_peer_params(params);
728
729        assert_eq!(
730            error,
731            Err(PolicyError::MaxAcceptedHtlcLimitExceeded(
732                params.max_accepted_htlcs,
733            ))
734        );
735    }
736
737    #[test]
738    fn test_channel_reserve_less_than_dust_limit() {
739        let policy = Policy::default();
740        let mut open_channel = get_open_channel();
741
742        open_channel.channel_reserve_satoshis =
743            open_channel.dust_limit_satoshis - 1;
744
745        let params = PeerParams::from(&open_channel);
746        let error = policy.validate_peer_params(params);
747
748        assert_eq!(
749            error,
750            Err(PolicyError::ChannelReserveLessDust {
751                dust_limit: params.dust_limit_satoshis,
752                reserve: params.channel_reserve_satoshis,
753            })
754        );
755    }
756
757    #[test]
758    fn test_dust_limit_is_too_small() {
759        let policy = Policy::default();
760        let mut open_channel = get_open_channel();
761
762        open_channel.dust_limit_satoshis = BOLT3_DUST_LIMIT - 1;
763
764        let params = PeerParams::from(&open_channel);
765        let error = policy.validate_peer_params(params);
766
767        assert_eq!(
768            error,
769            Err(PolicyError::DustLimitTooSmall(params.dust_limit_satoshis,))
770        );
771    }
772
773    #[test]
774    fn test_htlc_min_too_large() {
775        let mut policy = Policy::default();
776        let open_channel = get_open_channel();
777        let htlc_minimum_msat_max = open_channel.htlc_minimum_msat - 1;
778        policy.htlc_minimum_msat_max = Some(htlc_minimum_msat_max);
779
780        let params = PeerParams::from(&open_channel);
781        let error = policy.validate_peer_params(params);
782        assert_eq!(
783            error,
784            Err(PolicyError::HtlcMinimumTooLarge {
785                proposed: params.htlc_minimum_msat,
786                allowed_maximum: htlc_minimum_msat_max,
787            })
788        );
789    }
790
791    #[test]
792    fn test_htlc_in_flight_max_too_small() {
793        let policy = Policy::default();
794        let mut open_channel = get_open_channel();
795        let max_htlc_value_in_flight_msat_min =
796            policy.max_htlc_value_in_flight_msat_min.unwrap();
797        open_channel.max_htlc_value_in_flight_msat =
798            max_htlc_value_in_flight_msat_min - 1;
799        let params = PeerParams::from(&open_channel);
800        let error = policy.validate_peer_params(params);
801        assert_eq!(
802            error,
803            Err(PolicyError::HtlcInFlightMaximumTooSmall {
804                proposed: params.max_htlc_value_in_flight_msat,
805                required_minimum: max_htlc_value_in_flight_msat_min,
806            })
807        );
808    }
809
810    #[test]
811    fn test_channel_reserve_too_large_abs() {
812        let mut policy = Policy::default();
813        let open_channel = get_open_channel();
814        let channel_reserve_satoshis_max =
815            open_channel.channel_reserve_satoshis - 1;
816        policy.channel_reserve_satoshis_max_abs =
817            Some(channel_reserve_satoshis_max);
818        let params = PeerParams::from(&open_channel);
819        let error = policy.validate_peer_params(params);
820        assert_eq!(
821            error,
822            Err(PolicyError::ChannelReserveTooLarge {
823                proposed: params.channel_reserve_satoshis,
824                allowed_maximum: channel_reserve_satoshis_max,
825            })
826        );
827    }
828
829    #[test]
830    fn test_max_accepted_htlc_too_small() {
831        let policy = Policy::default();
832        let mut open_channel = get_open_channel();
833        let max_accepted_htlcs_min = policy.max_accepted_htlcs_min.unwrap();
834        open_channel.max_accepted_htlcs = max_accepted_htlcs_min - 1;
835        let params = PeerParams::from(&open_channel);
836        let error = policy.validate_peer_params(params);
837        assert_eq!(
838            error,
839            Err(PolicyError::MaxAcceptedHtlcsTooSmall {
840                proposed: params.max_accepted_htlcs,
841                required_minimum: max_accepted_htlcs_min,
842            })
843        );
844    }
845
846    #[test]
847    fn test_dust_limit_too_large() {
848        let policy = Policy::default();
849        let mut open_channel = get_open_channel();
850        let dust_limit_satoshis_max = policy.dust_limit_satoshis_max.unwrap();
851        open_channel.dust_limit_satoshis = dust_limit_satoshis_max + 1;
852        let params = PeerParams::from(&open_channel);
853        let error = policy.validate_peer_params(params);
854        assert_eq!(
855            error,
856            Err(PolicyError::DustLimitTooLarge {
857                proposed: params.dust_limit_satoshis,
858                allowed_maximum: dust_limit_satoshis_max,
859            })
860        );
861    }
862
863    #[test]
864    fn test_unreasonable_feerate_range_on_inbound() {
865        let policy = Policy::default();
866        let mut open_channel = get_open_channel();
867        open_channel.feerate_per_kw = policy.feerate_per_kw_range.end + 1;
868        let error = policy.validate_inbound(&open_channel);
869        assert_eq!(
870            error,
871            Err(PolicyError::FeeRateUnreasonable {
872                proposed: open_channel.feerate_per_kw,
873                lowest_accepted: policy.feerate_per_kw_range.start,
874                highest_accepted: policy.feerate_per_kw_range.end,
875            })
876        );
877    }
878
879    #[test]
880    fn test_channel_funding_too_small() {
881        let policy = Policy::default();
882        let mut open_channel = get_open_channel();
883        let funding_satoshis_min = policy.funding_satoshis_min.unwrap();
884        open_channel.funding_satoshis = funding_satoshis_min - 1;
885        let error = policy.validate_inbound(&open_channel);
886        assert_eq!(
887            error,
888            Err(PolicyError::ChannelFundingTooSmall {
889                proposed: open_channel.funding_satoshis,
890                required_minimum: funding_satoshis_min,
891            })
892        );
893    }
894
895    #[test]
896    fn test_channel_reserve_too_large_percent() {
897        let policy = Policy::default();
898        let mut open_channel = get_open_channel();
899        open_channel.funding_satoshis = 20000;
900        let percents = policy.channel_reserve_satoshis_max_percent.unwrap();
901        let channel_reserve_satoshis_max =
902            open_channel.funding_satoshis as f32 * (percents as f32 / 100.);
903        let channel_reserve_satoshis_max = channel_reserve_satoshis_max as u64;
904        let error = policy.validate_inbound(&open_channel);
905        assert_eq!(
906            error,
907            Err(PolicyError::ChannelReserveTooLarge {
908                proposed: open_channel.channel_reserve_satoshis,
909                allowed_maximum: channel_reserve_satoshis_max,
910            })
911        );
912    }
913
914    #[test]
915    fn test_unreasonable_min_depth() {
916        let policy = Policy::default();
917        let open_channel = get_open_channel();
918        let mut accept_channel = get_accept_channel();
919        let maximum_depth = policy.maximum_depth.unwrap();
920        accept_channel.minimum_depth = maximum_depth + 1;
921        let params = PeerParams::from(&open_channel);
922        let error = policy.confirm_outbound(params, &accept_channel);
923        assert_eq!(
924            error,
925            Err(PolicyError::UnreasonableMinDepth {
926                proposed: accept_channel.minimum_depth,
927                allowed_maximum: maximum_depth,
928            })
929        );
930    }
931
932    #[test]
933    fn test_local_dust_limit_exeeds_remote_reserve() {
934        let policy = Policy::default();
935        let open_channel = get_open_channel();
936        let mut accept_channel = get_accept_channel();
937        accept_channel.channel_reserve_satoshis =
938            open_channel.dust_limit_satoshis - 1;
939        let params = PeerParams::from(&open_channel);
940        let error = policy.confirm_outbound(params, &accept_channel);
941        assert_eq!(
942            error,
943            Err(PolicyError::LocalDustExceedsRemoteReserve {
944                channel_reserve: accept_channel.channel_reserve_satoshis,
945                dust_limit: params.dust_limit_satoshis,
946            })
947        );
948    }
949
950    #[test]
951    fn test_remote_dust_limit_exceeds_local_reserve() {
952        let policy = Policy::default();
953        let mut open_channel = get_open_channel();
954        let accept_channel = get_accept_channel();
955        open_channel.channel_reserve_satoshis =
956            accept_channel.dust_limit_satoshis - 1;
957        let params = PeerParams::from(&open_channel);
958        let error = policy.confirm_outbound(params, &accept_channel);
959        assert_eq!(
960            error,
961            Err(PolicyError::RemoteDustExceedsLocalReserve {
962                channel_reserve: params.channel_reserve_satoshis,
963                dust_limit: accept_channel.dust_limit_satoshis,
964            })
965        );
966    }
967}