1use std::fmt::Debug;
15use std::ops::Range;
16
17#[cfg(feature = "serde")]
18use amplify::ToYamlString;
19use lnp2p::bolt::{AcceptChannel, ChannelType, OpenChannel};
20
21pub const BOLT3_MAX_ACCEPTED_HTLC_LIMIT: u16 = 483;
23
24pub const BOLT3_DUST_LIMIT: u64 = 354;
26
27#[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 ToSelfDelayUnreasonablyLarge { proposed: u16, allowed_maximum: u16 },
49
50 MaxAcceptedHtlcLimitExceeded(u16),
53
54 FeeRateUnreasonable {
58 proposed: u32,
59 lowest_accepted: u32,
60 highest_accepted: u32,
61 },
62
63 ChannelReserveLessDust { reserve: u64, dust_limit: u64 },
66
67 DustLimitTooSmall(u64),
70
71 ChannelFundingTooSmall {
75 proposed: u64,
76 required_minimum: u64,
77 },
78
79 HtlcMinimumTooLarge { proposed: u64, allowed_maximum: u64 },
83
84 HtlcInFlightMaximumTooSmall {
88 proposed: u64,
89 required_minimum: u64,
90 },
91
92 ChannelReserveTooLarge { proposed: u64, allowed_maximum: u64 },
96
97 MaxAcceptedHtlcsTooSmall {
101 proposed: u16,
102 required_minimum: u16,
103 },
104
105 DustLimitTooLarge { proposed: u64, allowed_maximum: u64 },
108
109 UnreasonableMinDepth { proposed: u32, allowed_maximum: u32 },
113
114 LocalDustExceedsRemoteReserve {
118 channel_reserve: u64,
119 dust_limit: u64,
120 },
121
122 RemoteDustExceedsLocalReserve {
126 channel_reserve: u64,
127 dust_limit: u64,
128 },
129}
130
131#[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 pub to_self_delay_max: u16,
147
148 pub feerate_per_kw_range: Range<u32>,
150
151 pub minimum_depth: u32,
154
155 pub maximum_depth: Option<u32>,
160
161 pub funding_satoshis_min: Option<u64>,
163
164 pub htlc_minimum_msat_max: Option<u64>,
166
167 pub max_htlc_value_in_flight_msat_min: Option<u64>,
169
170 pub channel_reserve_satoshis_max_abs: Option<u64>,
173
174 pub channel_reserve_satoshis_max_percent: Option<u8>,
177
178 pub max_accepted_htlcs_min: Option<u16>,
180
181 pub dust_limit_satoshis_max: Option<u64>,
183}
184
185#[cfg(feature = "serde")]
186impl ToYamlString for Policy {}
187
188impl Default for Policy {
189 fn default() -> Policy {
191 Policy {
192 to_self_delay_max: 250,
193 feerate_per_kw_range: 1..100,
196 minimum_depth: 3,
198 maximum_depth: Some(6),
200 funding_satoshis_min: Some(10000),
202 htlc_minimum_msat_max: None,
204 max_htlc_value_in_flight_msat_min: Some(10000),
207 max_accepted_htlcs_min: Some(10),
208 channel_reserve_satoshis_max_abs: None,
212 channel_reserve_satoshis_max_percent: Some(10),
213 dust_limit_satoshis_max: Some(1000),
216 }
217 }
218}
219
220impl Policy {
221 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 channel_reserve_satoshis_max_percent: Some(10),
235 dust_limit_satoshis_max: Some(546),
236 }
237 }
238
239 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 channel_reserve_satoshis_max_percent: Some(1),
253 dust_limit_satoshis_max: Some(546),
258 }
259 }
260
261 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 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 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 params.max_accepted_htlcs > BOLT3_MAX_ACCEPTED_HTLC_LIMIT {
293 return Err(PolicyError::MaxAcceptedHtlcLimitExceeded(
294 params.max_accepted_htlcs,
295 ));
296 }
297
298 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 params.dust_limit_satoshis < BOLT3_DUST_LIMIT {
308 return Err(PolicyError::DustLimitTooSmall(
309 params.dust_limit_satoshis,
310 ));
311 }
312
313 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 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 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 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 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 pub fn validate_inbound(
378 &self,
379 open_channel: &OpenChannel,
380 ) -> Result<PeerParams, PolicyError> {
381 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 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 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 pub fn confirm_outbound(
436 &self,
437 our_params: PeerParams,
438 accept_channel: &AcceptChannel,
439 ) -> Result<PeerParams, PolicyError> {
440 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 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 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#[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 pub minimum_depth: u32,
502
503 pub feerate_per_kw: u32,
508
509 pub announce_channel: bool,
513
514 pub channel_type: ChannelType,
519}
520
521#[cfg(feature = "serde")]
522impl ToYamlString for CommonParams {}
523
524impl Default for CommonParams {
525 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 #[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#[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 pub dust_limit_satoshis: u64,
590
591 pub to_self_delay: u16,
594
595 pub htlc_minimum_msat: u64,
597
598 pub max_htlc_value_in_flight_msat: u64,
601
602 pub channel_reserve_satoshis: u64,
605
606 pub max_accepted_htlcs: u16,
608}
609
610#[cfg(feature = "serde")]
611impl ToYamlString for PeerParams {}
612
613impl Default for PeerParams {
614 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 #[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 #[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 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 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}