1use bitcoin::absolute::{Height, Time};
2use bitcoin::bip32::DerivationPath;
3use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
4use bitcoin::sighash::{EcdsaSighashType, SegwitV0Sighash, SighashCache};
5use bitcoin::transaction::Version;
6use bitcoin::{Address, Amount, Network, ScriptBuf, Transaction};
7use lightning::ln::chan_utils::{
8 build_htlc_transaction, htlc_success_tx_weight, htlc_timeout_tx_weight,
9 make_funding_redeemscript, ClosingTransaction, HTLCOutputInCommitment, TxCreationKeys,
10};
11use lightning::sign::{ChannelSigner, InMemorySigner};
12use lightning::types::payment::PaymentHash;
13use log::*;
14use serde::Deserialize;
15use vls_common::HexEncode;
16use vls_policy_derive::Optionized;
17
18use super::error::{
19 policy_error, transaction_format_error, unknown_destinations_error, ValidationError,
20};
21use super::filter::{FilterResult, PolicyFilter};
22use super::validator::EnforcementState;
23use super::validator::{ChainState, Validator, ValidatorFactory};
24use super::{
25 policy_error_with_filter, Policy, DEFAULT_FEE_VELOCITY_CONTROL, MAX_CHANNELS, MAX_INVOICES,
26 MAX_ONCHAIN_TX_SIZE,
27};
28use crate::channel::{ChannelId, ChannelSetup, ChannelSlot, CommitmentType};
29use crate::policy::temporary_policy_error_with_filter;
30use crate::prelude::*;
31use crate::tx::tx::{
32 parse_offered_htlc_script, parse_received_htlc_script, parse_revokeable_redeemscript,
33 CommitmentInfo, CommitmentInfo2,
34};
35use crate::util::debug_utils::{
36 script_debug, DebugHTLCOutputInCommitment, DebugInMemorySigner, DebugTxCreationKeys,
37 DebugVecVecU8,
38};
39use crate::util::transaction_utils::{
40 estimate_feerate_per_kw, expected_commitment_tx_weight, is_tx_non_malleable,
41 mutual_close_tx_weight, MIN_CHAN_DUST_LIMIT_SATOSHIS, MIN_DUST_LIMIT_SATOSHIS,
42};
43use crate::util::velocity::VelocityControlSpec;
44use crate::wallet::Wallet;
45
46extern crate scopeguard;
47
48const SAFE_COMMITMENT_TYPE: &[CommitmentType] =
49 &[CommitmentType::StaticRemoteKey, CommitmentType::AnchorsZeroFeeHtlc];
50
51const MAX_CHAIN_LAG: u32 = 2;
52
53pub struct SimpleValidatorFactory {
55 pub(crate) policy: Option<SimplePolicy>,
56}
57
58impl SimpleValidatorFactory {
59 pub fn new() -> Self {
61 SimpleValidatorFactory { policy: None }
62 }
63
64 pub fn new_with_policy(policy: SimplePolicy) -> Self {
66 SimpleValidatorFactory { policy: Some(policy) }
67 }
68}
69
70impl ValidatorFactory for SimpleValidatorFactory {
71 fn make_validator(
72 &self,
73 network: Network,
74 node_id: PublicKey,
75 channel_id: Option<ChannelId>,
76 ) -> Arc<dyn Validator> {
77 let validator = SimpleValidator {
78 policy: self.policy.clone().unwrap_or_else(|| make_default_simple_policy(network)),
79 node_id,
80 channel_id,
81 };
82
83 Arc::new(validator)
84 }
85
86 fn policy(&self, network: Network) -> Box<dyn Policy> {
87 Box::new(self.policy.clone().unwrap_or_else(|| make_default_simple_policy(network)))
88 }
89}
90
91#[derive(Clone, Debug, Optionized, Deserialize)]
93pub struct SimplePolicy {
94 pub min_delay: u16,
96 pub max_delay: u16,
98 pub max_channel_size_sat: u64,
100 pub epsilon_sat: u64,
102 pub max_htlcs: usize,
104 pub max_htlc_value_sat: u64,
106 pub use_chain_state: bool,
108 pub min_feerate_per_kw: u32,
110 pub max_feerate_per_kw: u32,
112 pub enforce_balance: bool,
114 pub max_routing_fee_msat: u64,
116 pub max_feerate_percentage: u8,
119 pub dev_flags: Option<PolicyDevFlags>,
121 pub filter: PolicyFilter,
123 pub global_velocity_control: VelocityControlSpec,
125 pub max_channels: usize,
127 pub max_invoices: usize,
129 pub fee_velocity_control: VelocityControlSpec,
131}
132
133impl Policy for SimplePolicy {
134 fn policy_error(&self, tag: String, msg: String) -> Result<(), ValidationError> {
135 policy_error_with_filter(tag, msg, &self.filter)
136 }
137
138 fn temporary_policy_error(&self, tag: String, msg: String) -> Result<(), ValidationError> {
139 temporary_policy_error_with_filter(tag, msg, &self.filter)
140 }
141
142 fn policy_log(&self, tag: String, msg: String) {
143 if self.filter.filter(&tag) == FilterResult::Error {
144 error!("{}", msg);
145 } else {
146 warn!("{}", msg);
147 }
148 }
149
150 fn global_velocity_control(&self) -> VelocityControlSpec {
151 self.global_velocity_control
152 }
153
154 fn max_channels(&self) -> usize {
155 self.max_channels
156 }
157
158 fn max_invoices(&self) -> usize {
159 self.max_invoices
160 }
161
162 fn fee_velocity_control(&self) -> VelocityControlSpec {
163 self.fee_velocity_control
164 }
165}
166
167#[derive(Clone, Debug, Deserialize)]
169pub struct PolicyDevFlags {
170 pub disable_beneficial_balance_checks: bool,
172}
173
174const DEFAULT_DEV_FLAGS: PolicyDevFlags =
175 PolicyDevFlags { disable_beneficial_balance_checks: false };
176
177impl Default for PolicyDevFlags {
178 fn default() -> Self {
179 DEFAULT_DEV_FLAGS
180 }
181}
182
183pub struct SimpleValidator {
186 policy: SimplePolicy,
187 node_id: PublicKey,
188 channel_id: Option<ChannelId>,
189}
190
191impl SimpleValidator {
192 const ANCHOR_SEQS: [u32; 1] = [0x_0000_0001];
193 const NON_ANCHOR_SEQS: [u32; 3] = [0x_0000_0000_u32, 0x_ffff_fffd_u32, 0x_ffff_ffff_u32];
194
195 fn log_prefix(&self) -> String {
196 let short_node_id = &self.node_id.to_string()[0..4];
197 let short_channel_id = self
198 .channel_id
199 .as_ref()
200 .map(|c| c.as_slice()[0..4].to_vec().to_hex())
201 .unwrap_or("".to_string());
202 format!("{}/{}", short_node_id, short_channel_id)
203 }
204
205 fn validate_delay(&self, name: &str, delay: u32) -> Result<(), ValidationError> {
206 let policy = &self.policy;
207
208 if delay < policy.min_delay as u32 {
209 let tag = format!("policy-channel-contest-delay-range-{}", name);
210 policy_err!(
211 self,
212 tag,
213 "{} contest-delay too small: {} < {}",
214 name,
215 delay,
216 policy.min_delay
217 );
218 }
219 if delay > policy.max_delay as u32 {
220 let tag = format!("policy-channel-contest-delay-range-{}", name);
221 policy_err!(
222 self,
223 tag,
224 "{} contest-delay too large: {} > {}",
225 name,
226 delay,
227 policy.max_delay
228 );
229 }
230
231 Ok(())
232 }
233
234 fn validate_expiry(
235 &self,
236 name: &str,
237 expiry: u32,
238 current_height: u32,
239 ) -> Result<(), ValidationError> {
240 let policy = &self.policy;
241
242 if policy.use_chain_state {
243 if expiry < current_height + policy.min_delay as u32 {
244 policy_err!(
245 self,
246 "policy-commitment-htlc-cltv-range",
247 "{} expiry too early: {} < {}",
248 name,
249 expiry,
250 current_height + policy.min_delay as u32
251 );
252 }
253 if expiry > current_height + policy.max_delay as u32 {
254 policy_err!(
255 self,
256 "policy-commitment-htlc-cltv-range",
257 "{} expiry too late: {} > {}",
258 name,
259 expiry,
260 current_height + policy.max_delay as u32
261 );
262 }
263 }
264
265 Ok(())
266 }
267
268 fn validate_fee(
269 &self,
270 tag: &str,
271 sum_inputs: u64,
272 sum_outputs: u64,
273 weight: usize,
274 ) -> Result<(), ValidationError> {
275 let fee = sum_inputs.checked_sub(sum_outputs).ok_or_else(|| {
276 policy_error(tag, format!("fee underflow: {} - {}", sum_inputs, sum_outputs))
277 })?;
278 let feerate_perkw = estimate_feerate_per_kw(fee, weight as u64);
279 debug!("validate_fee fee:{} / weight:{} = feerate_perkw:{}", fee, weight, feerate_perkw);
280 if feerate_perkw < self.policy.min_feerate_per_kw {
281 policy_err!(
282 self,
283 tag, "feerate below minimum: {} < {}",
285 feerate_perkw,
286 self.policy.min_feerate_per_kw
287 );
288 }
289 if feerate_perkw > self.policy.max_feerate_per_kw {
290 policy_err!(
291 self,
292 tag, "feerate above maximum: {} > {}",
294 feerate_perkw,
295 self.policy.max_feerate_per_kw
296 );
297 }
298 Ok(())
299 }
300
301 fn validate_beneficial_value(
302 &self,
303 sum_our_inputs: u64,
304 sum_our_outputs: u64,
305 weight: usize,
306 ) -> Result<u64, ValidationError> {
307 let non_beneficial = sum_our_inputs.checked_sub(sum_our_outputs).ok_or_else(|| {
308 policy_error(
309 "policy-onchain-format-standard",
310 format!(
311 "non-beneficial value underflow: sum of our inputs {} < sum of our outputs {}",
312 sum_our_inputs, sum_our_outputs
313 ),
314 )
315 })?;
316 let feerate_perkw = estimate_feerate_per_kw(non_beneficial, weight as u64);
317 if feerate_perkw > self.policy.max_feerate_per_kw {
318 let dev_flags = self.policy.dev_flags.as_ref().unwrap_or(&DEFAULT_DEV_FLAGS);
319 if dev_flags.disable_beneficial_balance_checks {
320 error!(
321 "DEV IGNORE \
322 non-beneficial value considered as fees is above maximum feerate: {} > {}",
323 feerate_perkw, self.policy.max_feerate_per_kw
324 );
325 } else {
326 policy_err!(
327 self,
328 "policy-onchain-fee-range",
329 "non-beneficial value considered as fees is above maximum feerate: {} > {}",
330 feerate_perkw,
331 self.policy.max_feerate_per_kw
332 );
333 }
334 }
335 Ok(non_beneficial)
336 }
337
338 fn outside_epsilon_range(&self, value0: u64, value1: u64) -> (bool, String) {
339 if value0 > value1 {
340 (value0 - value1 > self.policy.epsilon_sat, "larger".to_string())
341 } else {
342 (value1 - value0 > self.policy.epsilon_sat, "smaller".to_string())
343 }
344 }
345
346 fn validate_sweep(
348 &self,
349 wallet: &dyn Wallet,
350 tx: &Transaction,
351 _input: usize,
352 _amount_sat: u64,
353 wallet_path: &DerivationPath,
354 ) -> Result<(), ValidationError> {
355 if tx.version != Version::TWO {
356 transaction_format_err!(self, "policy-sweep-version", "bad version: {}", tx.version);
357 }
358
359 for out in tx.output.iter() {
367 let dest_script = &out.script_pubkey;
368 let spendable = wallet.can_spend(wallet_path, dest_script).map_err(|err| {
369 policy_error(
370 "policy-onchain-output-scriptpubkey",
371 format!("wallet can_spend error: {}", err),
372 )
373 })?;
374 if !spendable && !wallet.allowlist_contains(dest_script, wallet_path) {
375 info!(
376 "dest_script not matched: path={:?}, {}",
377 wallet_path,
378 script_debug(dest_script, wallet.network())
379 );
380 policy_err!(
381 self,
382 "policy-sweep-destination-allowlisted",
383 "destination is not in wallet or allowlist"
384 );
385 }
386 }
387
388 Ok(())
389 }
390}
391
392impl Validator for SimpleValidator {
393 fn validate_setup_channel(
394 &self,
395 wallet: &dyn Wallet,
396 setup: &ChannelSetup,
397 holder_shutdown_key_path: &DerivationPath,
398 ) -> Result<(), ValidationError> {
399 let mut debug_on_return = scoped_debug_return!(setup, holder_shutdown_key_path);
400
401 if !SAFE_COMMITMENT_TYPE.contains(&setup.commitment_type) {
405 if setup.commitment_type == CommitmentType::Anchors {
406 policy_err!(
409 self,
410 "policy-channel-safe-type-anchors",
411 "unsafe commitment type: plain anchors"
412 );
413 } else {
414 policy_err!(
415 self,
416 "policy-channel-safe-type",
417 "unsafe commitment type: {:?}",
418 setup.commitment_type
419 );
420 }
421 }
422
423 self.validate_delay("holder", setup.counterparty_selected_contest_delay as u32)?;
426
427 self.validate_delay("counterparty", setup.holder_selected_contest_delay as u32)?;
430
431 if let Some(holder_shutdown_script) = &setup.holder_shutdown_script {
432 let spendable = wallet
433 .can_spend(holder_shutdown_key_path, holder_shutdown_script)
434 .map_err(|err| {
435 policy_error(
436 "policy-onchain-output-scriptpubkey",
437 format!("wallet can_spend error: {}", err),
438 )
439 })?;
440 if !spendable
441 && !wallet.allowlist_contains(holder_shutdown_script, holder_shutdown_key_path)
442 {
443 info!(
444 "holder_shutdown_script not matched: path={:?}, {}",
445 holder_shutdown_key_path,
446 script_debug(holder_shutdown_script, wallet.network())
447 );
448 policy_err!(
449 self,
450 "policy-mutual-destination-allowlisted",
451 "holder_shutdown_script is not in wallet or allowlist"
452 );
453 }
454 }
455 *debug_on_return = false;
456 Ok(())
457 }
458
459 fn validate_channel_value(&self, setup: &ChannelSetup) -> Result<(), ValidationError> {
460 if setup.channel_value_sat > self.policy.max_channel_size_sat {
461 policy_err!(
462 self,
463 "policy-funding-max",
464 "channel value {} too large",
465 setup.channel_value_sat
466 );
467 }
468 Ok(())
469 }
470
471 fn validate_onchain_tx(
472 &self,
473 wallet: &dyn Wallet,
474 channels: Vec<Option<Arc<Mutex<ChannelSlot>>>>,
475 tx: &Transaction,
476 segwit_flags: &[bool],
477 values_sat: &[u64],
478 opaths: &[DerivationPath],
479 weight_lower_bound: usize,
480 ) -> Result<u64, ValidationError> {
481 let mut debug_on_return = scoped_debug_return!(tx, values_sat, opaths);
482
483 if tx.version != Version::TWO {
484 policy_err!(self, "policy-onchain-format-standard", "invalid version: {}", tx.version);
485 }
486
487 if tx.base_size() > MAX_ONCHAIN_TX_SIZE {
488 policy_err!(
489 self,
490 "policy-onchain-max-size",
491 "tx too large: {} > {}",
492 tx.base_size(),
493 MAX_ONCHAIN_TX_SIZE
494 );
495 }
496
497 if channels.iter().any(|c| c.is_some()) && !is_tx_non_malleable(tx, segwit_flags) {
498 policy_err!(
499 self,
500 "policy-onchain-funding-non-malleable",
501 "funding tx has non-segwit-native input"
502 );
503 }
504
505 let mut unknowns = Vec::new();
506
507 let mut beneficial_sum = 0u64;
508 for outndx in 0..tx.output.len() {
509 let output = &tx.output[outndx];
510 let opath = &opaths[outndx];
511 let channel_slot = channels[outndx].as_ref();
512
513 macro_rules! add_beneficial_output {
514 ($sum: expr, $val: expr, $which: expr) => {
515 $sum.checked_add($val).ok_or_else(|| {
516 policy_error(
517 "policy-onchain-fee-range",
518 format!(
519 "beneficial outputs overflow: sum {} + {} {}",
520 $sum, $which, $val
521 ),
522 )
523 })
524 };
525 }
526
527 if opath.len() > 0 {
528 let mut spendable =
530 wallet.can_spend(opath, &output.script_pubkey).map_err(|err| {
531 policy_error(
532 "policy-onchain-output-scriptpubkey",
533 format!("output[{}]: wallet_can_spend error: {}", outndx, err),
534 )
535 })?;
536 if spendable {
537 debug!("output {} ({}) is to our wallet", outndx, output.value.to_sat());
538 beneficial_sum =
539 add_beneficial_output!(beneficial_sum, output.value.to_sat(), "to wallet")?;
540 }
541 if !spendable {
542 spendable = wallet.allowlist_contains(&output.script_pubkey, opath);
544 if spendable {
545 debug!(
546 "output {} ({}) is to allowlisted xpub",
547 outndx,
548 output.value.to_sat()
549 );
550 beneficial_sum = add_beneficial_output!(
551 beneficial_sum,
552 output.value.to_sat(),
553 "to allowlisted xpub"
554 )?;
555 }
556 }
557 if !spendable {
558 policy_err!(
559 self,
560 "policy-onchain-no-unknown-outputs",
561 "output[{}] is unknown",
562 outndx
563 );
564 }
565 } else if wallet.allowlist_contains(&output.script_pubkey, &DerivationPath::master()) {
566 debug!("output {} ({}) is allowlisted", outndx, output.value.to_sat());
568 beneficial_sum =
569 add_beneficial_output!(beneficial_sum, output.value.to_sat(), "allowlisted")?;
570 } else if let Some(slot) = channel_slot {
571 match &*slot.lock().unwrap() {
573 ChannelSlot::Ready(chan) => {
574 debug!(
575 "output {} ({}) matches channel {}",
576 outndx,
577 output.value.to_sat(),
578 chan.id()
579 );
580 dbgvals!(chan.setup, chan.enforcement_state);
581
582 if output.value.to_sat() != chan.setup.channel_value_sat {
583 policy_err!(
584 self,
585 "policy-onchain-output-match-commitment",
586 "funding output amount mismatch w/ channel: {} != {}",
587 output.value.to_sat(),
588 chan.setup.channel_value_sat
589 );
590 }
591
592 let funding_redeemscript = make_funding_redeemscript(
593 &chan.keys.pubkeys().funding_pubkey,
594 &chan.counterparty_pubkeys().funding_pubkey,
595 );
596 let address = Address::p2wsh(&funding_redeemscript, wallet.network());
597 let script_pubkey = address.script_pubkey();
598 if output.script_pubkey != script_pubkey {
599 policy_err!(
600 self,
601 "policy-onchain-output-scriptpubkey",
602 "funding script_pubkey mismatch w/ channel: {} != {}",
603 output.script_pubkey,
604 script_pubkey
605 );
606 }
607
608 if chan.enforcement_state.next_holder_commit_num != 1 {
609 policy_err!(
610 self,
611 "policy-onchain-initial-commitment-countersigned",
612 "initial holder commitment not validated",
613 );
614 }
615 if !chan.setup.is_outbound {
616 policy_err!(
617 self,
618 "policy-onchain-no-fund-inbound",
619 "can't sign for inbound channel: dual-funding not supported yet",
620 );
621 }
622 let push_val_sat = chan.setup.push_value_msat / 1000;
623 if push_val_sat > 0 {
624 policy_err!(
625 self,
626 "policy-onchain-no-channel-push",
627 "channel push not allowed: dual-funding not supported yet",
628 );
629 }
630 let our_value =
631 chan.setup.channel_value_sat.checked_sub(push_val_sat).ok_or_else(
632 || {
633 policy_error(
634 "policy-onchain-fee-range",
635 format!(
636 "channel value underflow: {} - {}",
637 chan.setup.channel_value_sat, push_val_sat
638 ),
639 )
640 },
641 )?;
642 debug!(
643 "output {} ({}) funds channel {}",
644 outndx,
645 output.value.to_sat(),
646 chan.id()
647 );
648 beneficial_sum =
649 add_beneficial_output!(beneficial_sum, our_value, "channel value")?;
650 }
651 _ => panic!("this can't happen"),
652 };
653 } else {
654 debug!("output {} ({}) is unknown", outndx, output.value.to_sat());
655 unknowns.push(outndx);
657 }
658 }
659
660 if unknowns.len() > 0 {
661 return Err(unknown_destinations_error(unknowns));
662 }
663
664 let mut sum_inputs: u64 = 0;
666 for val in values_sat {
667 sum_inputs = sum_inputs.checked_add(*val).ok_or_else(|| {
668 policy_error("policy-onchain-fee-range", "funding sum inputs overflow")
669 })?;
670 }
671 let non_beneficial = self
672 .validate_beneficial_value(sum_inputs, beneficial_sum, weight_lower_bound)
673 .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
674
675 *debug_on_return = false;
676 Ok(non_beneficial)
677 }
678
679 fn decode_commitment_tx(
681 &self,
682 keys: &InMemorySigner,
683 setup: &ChannelSetup,
684 is_counterparty: bool,
685 tx: &bitcoin::Transaction,
686 output_witscripts: &[Vec<u8>],
687 ) -> Result<CommitmentInfo, ValidationError> {
688 let mut debug_on_return = scoped_debug_return!(
689 DebugInMemorySigner(keys),
690 setup,
691 is_counterparty,
692 tx,
693 DebugVecVecU8(output_witscripts)
694 );
695
696 if tx.version != Version::TWO {
697 policy_err!(
698 self,
699 "policy-commitment-version",
700 "bad commitment version: {}",
701 tx.version
702 );
703 }
704
705 let mut info = CommitmentInfo::new(is_counterparty);
706 for ind in 0..tx.output.len() {
707 info.handle_output(keys, setup, &tx.output[ind], output_witscripts[ind].as_slice())
708 .map_err(|ve| {
709 ve.prepend_msg(format!("{}: tx output[{}]: ", containing_function!(), ind))
710 })?;
711 }
712
713 *debug_on_return = false;
714 Ok(info)
715 }
716
717 fn validate_counterparty_commitment_tx(
718 &self,
719 estate: &EnforcementState,
720 commit_num: u64,
721 commitment_point: &PublicKey,
722 setup: &ChannelSetup,
723 cstate: &ChainState,
724 info2: &CommitmentInfo2,
725 ) -> Result<(), ValidationError> {
726 if let Some(current) = &estate.current_counterparty_commit_info {
727 let (added, removed) = current.delta_offered_htlcs(info2);
728 debug!(
729 "{} counterparty offered delta outbound={} +{:?} -{:?}",
730 self.log_prefix(),
731 setup.is_outbound,
732 added.collect::<Vec<_>>(),
733 removed.collect::<Vec<_>>()
734 );
735 let (added, removed) = current.delta_received_htlcs(info2);
736 debug!(
737 "{} counterparty received delta outbound={} +{:?} -{:?}",
738 self.log_prefix(),
739 setup.is_outbound,
740 added.collect::<Vec<_>>(),
741 removed.collect::<Vec<_>>()
742 );
743 }
744 self.validate_commitment_tx(estate, commit_num, commitment_point, setup, cstate, info2)
746 .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
747
748 let mut debug_on_return =
749 scoped_debug_return!(estate, commit_num, commitment_point, setup, cstate, info2);
750
751 if commit_num > estate.next_counterparty_revoke_num + 1 {
757 policy_err!(
758 self,
759 "policy-commitment-previous-revoked",
760 "invalid attempt to sign counterparty commit_num {} \
761 with next_counterparty_revoke_num {}",
762 commit_num,
763 estate.next_counterparty_revoke_num
764 );
765 }
766
767 if commit_num + 1 == estate.next_counterparty_commit_num {
771 match estate.current_counterparty_point {
773 None => {
774 policy_err!(
775 self,
776 "policy-commitment-retry-same",
777 "retry of sign_counterparty_commitment {} with no prev point: \
778 new {}",
779 commit_num,
780 commitment_point
781 );
782 }
783 Some(prev) =>
784 if *commitment_point != prev {
785 policy_err!(
786 self,
787 "policy-commitment-retry-same",
788 "retry of sign_counterparty_commitment {} with changed point: \
789 prev {} != new {}",
790 commit_num,
791 prev,
792 commitment_point
793 );
794 },
795 }
796
797 let prev_commit_info = estate.get_previous_counterparty_commit_info(commit_num);
799 if Some(info2) != prev_commit_info.as_ref() {
800 #[cfg(not(feature = "log_pretty_print"))]
801 policy_log!(
802 self,
803 "policy-commitment-retry-same",
804 "info2 != prev_commit_info\n{:?}\n{:?}",
805 info2,
806 prev_commit_info
807 );
808 #[cfg(feature = "log_pretty_print")]
809 policy_log!(
810 self,
811 "policy-commitment-retry-same",
812 "info2 != prev_commit_info\n{:#?}\n{:#?}",
813 info2,
814 prev_commit_info
815 );
816 policy_err!(
817 self,
818 "policy-commitment-retry-same",
819 "retry of sign_counterparty_commitment {} with changed info",
820 commit_num,
821 );
822 }
823 }
824
825 *debug_on_return = false;
826 Ok(())
827 }
828
829 fn validate_holder_commitment_tx(
830 &self,
831 estate: &EnforcementState,
832 commit_num: u64,
833 commitment_point: &PublicKey,
834 setup: &ChannelSetup,
835 cstate: &ChainState,
836 info2: &CommitmentInfo2,
837 ) -> Result<(), ValidationError> {
838 if let Some(current) = &estate.current_holder_commit_info {
839 let (added, removed) = current.delta_offered_htlcs(info2);
840 debug!(
841 "{} holder offered delta outbound={} +{:?} -{:?}",
842 self.log_prefix(),
843 setup.is_outbound,
844 added.collect::<Vec<_>>(),
845 removed.collect::<Vec<_>>()
846 );
847 let (added, removed) = current.delta_received_htlcs(info2);
848 debug!(
849 "{} holder received delta outbound={} +{:?} -{:?}",
850 self.log_prefix(),
851 setup.is_outbound,
852 added.collect::<Vec<_>>(),
853 removed.collect::<Vec<_>>()
854 );
855 }
856
857 self.validate_commitment_tx(estate, commit_num, commitment_point, setup, cstate, info2)
859 .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
860
861 let mut debug_on_return =
862 scoped_debug_return!(estate, commit_num, commitment_point, setup, cstate, info2);
863
864 if commit_num + 1 == estate.next_holder_commit_num {
866 let holder_commit_info =
869 &estate.current_holder_commit_info.as_ref().expect("current_holder_commit_info");
870 if info2 != *holder_commit_info {
871 dbgvals!(*info2, holder_commit_info);
872 policy_err!(
873 self,
874 "policy-commitment-retry-same",
875 "retry holder commitment {} with changed info",
876 commit_num
877 );
878 }
879 }
880
881 if commit_num + 2 <= estate.next_holder_commit_num {
884 dbgvals!(estate, commit_num);
885 policy_err!(
886 self,
887 "policy-commitment-holder-not-revoked",
888 "can't validate revoked commitment_number {}, \
889 next_holder_commit_num is {}",
890 commit_num,
891 estate.next_holder_commit_num
892 );
893 };
894
895 if commit_num == estate.next_holder_commit_num && estate.channel_closed {
898 dbgvals!(estate);
899 policy_err!(self, "policy-commitment-spends-active-utxo", "channel is closing");
900 }
901
902 *debug_on_return = false;
903 Ok(())
904 }
905
906 fn validate_counterparty_revocation(
907 &self,
908 state: &EnforcementState,
909 revoke_num: u64,
910 commitment_secret: &SecretKey,
911 ) -> Result<(), ValidationError> {
912 let secp_ctx = Secp256k1::signing_only();
913
914 if revoke_num != state.next_counterparty_revoke_num
916 && revoke_num + 1 != state.next_counterparty_revoke_num
917 {
918 dbgvals!(state, revoke_num, commitment_secret);
919 policy_err!(
920 self,
921 "policy-commitment-previous-revoked",
922 "invalid counterparty revoke_num {} with next_counterparty_revoke_num {}",
923 revoke_num,
924 state.next_counterparty_revoke_num
925 );
926 }
927
928 let supplied_commit_point = PublicKey::from_secret_key(&secp_ctx, &commitment_secret);
930 let prev_commit_point = state.get_previous_counterparty_point(revoke_num);
931 match prev_commit_point {
932 None => {
933 dbgvals!(state, revoke_num, commitment_secret);
934 policy_err!(
935 self,
936 "policy-commitment-previous-revoked",
937 "revocation commit point mismatch for commit_num {}: supplied {}, previous is None",
938 revoke_num,
939 supplied_commit_point
940 );
941 }
942 Some(prev) =>
943 if supplied_commit_point != prev {
944 dbgvals!(state, revoke_num, commitment_secret);
945 policy_err!(
946 self,
947 "policy-commitment-previous-revoked",
948 "revocation commit point mismatch for commit_num {}: supplied {}, previous {}",
949 revoke_num,
950 supplied_commit_point,
951 prev
952 );
953 },
954 }
955
956 Ok(())
957 }
958
959 fn decode_and_validate_htlc_tx(
962 &self,
963 is_counterparty: bool,
964 setup: &ChannelSetup,
965 txkeys: &TxCreationKeys,
966 tx: &Transaction,
967 redeemscript: &ScriptBuf,
968 htlc_amount_sat: u64,
969 output_witscript: &ScriptBuf,
970 ) -> Result<(u32, HTLCOutputInCommitment, SegwitV0Sighash, EcdsaSighashType), ValidationError>
971 {
972 let to_self_delay = if is_counterparty {
973 setup.holder_selected_contest_delay } else {
975 setup.counterparty_selected_contest_delay };
977 let sighash_type = if setup.is_anchors() {
978 EcdsaSighashType::SinglePlusAnyoneCanPay
979 } else {
980 EcdsaSighashType::All
981 };
982 let original_tx_sighash = SighashCache::new(tx)
983 .p2wsh_signature_hash(0, &redeemscript, Amount::from_sat(htlc_amount_sat), sighash_type)
984 .map_err(|_| {
985 policy_error(
986 "policy-commitment-other",
987 "could not compute sighash on provided HTLC tx",
988 )
989 })?;
990
991 let offered = if parse_offered_htlc_script(redeemscript, setup.is_anchors()).is_ok() {
992 true
993 } else if parse_received_htlc_script(redeemscript, setup.is_anchors()).is_ok() {
994 false
995 } else {
996 dbgvals!(
997 is_counterparty,
998 setup,
999 DebugTxCreationKeys(txkeys),
1000 tx,
1001 redeemscript,
1002 htlc_amount_sat,
1003 output_witscript
1004 );
1005 return Err(policy_error("policy-commitment-scripts", "invalid redeemscript"));
1006 };
1007
1008 let cltv_expiry = if offered { tx.lock_time.to_consensus_u32() } else { 0 };
1010 let transaction_output_index = tx.input[0].previous_output.vout;
1011 let commitment_txid = tx.input[0].previous_output.txid;
1012 let total_fee = htlc_amount_sat
1013 .checked_sub(tx.output[0].value.to_sat())
1014 .ok_or_else(|| policy_error("policy-commitment-fee-range", "fee underflow"))?;
1015
1016 let features = setup.features();
1017 let build_feerate = if setup.is_zero_fee_htlc() {
1018 0
1019 } else {
1020 let weight = if offered {
1021 htlc_timeout_tx_weight(&features)
1022 } else {
1023 htlc_success_tx_weight(&features)
1024 };
1025 estimate_feerate_per_kw(total_fee, weight)
1026 };
1027
1028 let htlc = HTLCOutputInCommitment {
1029 offered,
1030 amount_msat: htlc_amount_sat * 1000,
1031 cltv_expiry,
1032 payment_hash: PaymentHash([0; 32]), transaction_output_index: Some(transaction_output_index),
1034 };
1035
1036 let recomposed_tx = build_htlc_transaction(
1038 &commitment_txid,
1039 build_feerate,
1040 to_self_delay,
1041 &htlc,
1042 &setup.features(),
1043 &txkeys.broadcaster_delayed_payment_key,
1044 &txkeys.revocation_key,
1045 );
1046
1047 let recomposed_tx_sighash = SighashCache::new(&recomposed_tx)
1049 .p2wsh_signature_hash(0, &redeemscript, Amount::from_sat(htlc_amount_sat), sighash_type)
1050 .unwrap();
1051
1052 if recomposed_tx_sighash != original_tx_sighash {
1053 dbgvals!(
1054 is_counterparty,
1055 setup,
1056 DebugTxCreationKeys(txkeys),
1057 tx,
1058 redeemscript,
1059 htlc_amount_sat,
1060 output_witscript
1061 );
1062 let (revocation_key, contest_delay, delayed_pubkey) =
1063 parse_revokeable_redeemscript(output_witscript, setup.is_anchors())
1064 .unwrap_or_else(|_| (vec![], 0, vec![]));
1065 debug!(
1066 "ORIGINAL_TX={:#?}\n\
1067 output witscript params: [\n\
1068 \x20 revocation_pubkey: {},\n\
1069 \x20 to_self_delay: {},\n\
1070 \x20 delayed_pubkey: {},\n\
1071 ]",
1072 &tx,
1073 revocation_key.to_hex(),
1074 contest_delay,
1075 delayed_pubkey.to_hex()
1076 );
1077 debug!(
1078 "RECOMPOSED_TX={:#?}\n\
1079 output witscript params: [\n\
1080 \x20 revocation_pubkey: {},\n\
1081 \x20 to_self_delay: {},\n\
1082 \x20 delayed_pubkey: {},\n\
1083 ]",
1084 &recomposed_tx,
1085 &txkeys.revocation_key.0,
1086 to_self_delay,
1087 &txkeys.broadcaster_delayed_payment_key.0
1088 );
1089 return Err(policy_error("policy-htlc-other", "sighash mismatch".to_string()));
1090 }
1091
1092 Ok((build_feerate, htlc, recomposed_tx_sighash, sighash_type))
1102 }
1103
1104 fn validate_htlc_tx(
1105 &self,
1106 setup: &ChannelSetup,
1107 _cstate: &ChainState,
1108 _is_counterparty: bool,
1109 htlc: &HTLCOutputInCommitment,
1110 feerate_per_kw: u32,
1111 ) -> Result<(), ValidationError> {
1112 let mut debug_on_return =
1113 scoped_debug_return!(DebugHTLCOutputInCommitment(htlc), feerate_per_kw);
1114
1115 if htlc.offered && htlc.cltv_expiry == 0 {
1120 policy_err!(self, "policy-htlc-locktime", "offered lock_time must be non-zero");
1121 }
1122
1123 if !setup.is_zero_fee_htlc() {
1124 if feerate_per_kw < self.policy.min_feerate_per_kw {
1125 policy_err!(
1126 self,
1127 "policy-htlc-fee-range",
1128 "feerate_per_kw of {} is smaller than the minimum of {}",
1129 feerate_per_kw,
1130 self.policy.min_feerate_per_kw
1131 );
1132 }
1133 }
1134 if feerate_per_kw > self.policy.max_feerate_per_kw {
1135 policy_err!(
1136 self,
1137 "policy-htlc-fee-range",
1138 "feerate_per_kw of {} is larger than the maximum of {}",
1139 feerate_per_kw,
1140 self.policy.max_feerate_per_kw
1141 );
1142 }
1143
1144 *debug_on_return = false;
1145 Ok(())
1146 }
1147
1148 fn decode_and_validate_mutual_close_tx(
1149 &self,
1150 wallet: &dyn Wallet,
1151 setup: &ChannelSetup,
1152 estate: &EnforcementState,
1153 tx: &Transaction,
1154 wallet_paths: &[DerivationPath],
1155 ) -> Result<ClosingTransaction, ValidationError> {
1156 let should_debug = true;
1158 let mut debug_on_return = scopeguard::guard(should_debug, |should_debug| {
1159 if should_debug {
1160 if log::log_enabled!(log::Level::Debug) {
1161 debug!("{} failed:", containing_function!());
1162 dbgvals!(setup, estate, tx, wallet_paths);
1163
1164 let mut addrstrs = String::new();
1166 for ndx in 0..tx.output.len() {
1167 let script = &tx.output[ndx].script_pubkey;
1168 addrstrs.push_str(
1169 &format!(
1170 "\ntxout[{}]: {}",
1171 ndx,
1172 &script_debug(script, wallet.network())
1173 )[..],
1174 );
1175 }
1176 debug!("output addresses: {}", &addrstrs);
1177 }
1178 }
1179 });
1180
1181 if tx.output.len() > 2 {
1182 transaction_format_err!(
1183 self,
1184 "policy-mutual-other",
1185 "invalid number of outputs: {}",
1186 tx.output.len(),
1187 );
1188 }
1189
1190 assert_eq!(wallet_paths.len(), tx.output.len());
1192
1193 if estate.current_holder_commit_info.is_none() {
1194 policy_err!(self, "policy-mutual-other", "current_holder_commit_info missing");
1195 }
1196 if estate.current_counterparty_commit_info.is_none() {
1197 policy_err!(self, "policy-mutual-other", "current_counterparty_commit_info missing");
1198 }
1199
1200 #[derive(Debug)]
1207 struct ValidateArgs {
1208 to_holder_value_sat: u64,
1209 to_counterparty_value_sat: u64,
1210 holder_script: Option<ScriptBuf>,
1211 counterparty_script: Option<ScriptBuf>,
1212 wallet_path: DerivationPath,
1213 }
1214
1215 let holder_value = estate.minimum_to_holder_value(self.policy.epsilon_sat);
1220 let cparty_value = estate.minimum_to_counterparty_value(self.policy.epsilon_sat);
1221 #[cfg(not(feature = "log_pretty_print"))]
1222 debug!("holder_value={:?}, cparty_value={:?}", holder_value, cparty_value);
1223 #[cfg(feature = "log_pretty_print")]
1224 debug!("holder_value={:#?}, cparty_value={:#?}", holder_value, cparty_value);
1225 let holder_value_is_larger = holder_value > cparty_value;
1226 debug!("holder_value_is_larger={}", holder_value_is_larger);
1227
1228 let (likely_args, unlikely_args) = if tx.output.len() == 1 {
1229 let holders_output = ValidateArgs {
1230 to_holder_value_sat: tx.output[0].value.to_sat(),
1231 to_counterparty_value_sat: 0,
1232 holder_script: Some(tx.output[0].script_pubkey.clone()),
1233 counterparty_script: None,
1234 wallet_path: wallet_paths[0].clone(),
1235 };
1236 let cpartys_output = ValidateArgs {
1237 to_holder_value_sat: 0,
1238 to_counterparty_value_sat: tx.output[0].value.to_sat(),
1239 holder_script: None,
1240 counterparty_script: Some(tx.output[0].script_pubkey.clone()),
1241 wallet_path: DerivationPath::master(),
1242 };
1243 if holder_value_is_larger {
1244 debug!("{}: likely the holder's output", short_function!());
1245 (holders_output, cpartys_output)
1246 } else {
1247 debug!("{}: likely the counterparty's output", short_function!());
1248 (cpartys_output, holders_output)
1249 }
1250 } else {
1251 let holder_first = ValidateArgs {
1252 to_holder_value_sat: tx.output[0].value.to_sat(),
1253 to_counterparty_value_sat: tx.output[1].value.to_sat(),
1254 holder_script: Some(tx.output[0].script_pubkey.clone()),
1255 counterparty_script: Some(tx.output[1].script_pubkey.clone()),
1256 wallet_path: wallet_paths[0].clone(),
1257 };
1258 let cparty_first = ValidateArgs {
1259 to_holder_value_sat: tx.output[1].value.to_sat(),
1260 to_counterparty_value_sat: tx.output[0].value.to_sat(),
1261 holder_script: Some(tx.output[1].script_pubkey.clone()),
1262 counterparty_script: Some(tx.output[0].script_pubkey.clone()),
1263 wallet_path: wallet_paths[1].clone(),
1264 };
1265 if holder_value_is_larger {
1266 debug!(
1267 "{}: likely output[0] is counterparty, output[1] is holder",
1268 short_function!()
1269 );
1270 (cparty_first, holder_first)
1271 } else {
1272 debug!(
1273 "{}: likely output[0] is holder, output[1] is counterparty",
1274 short_function!()
1275 );
1276 (holder_first, cparty_first)
1277 }
1278 };
1279
1280 #[cfg(not(feature = "log_pretty_print"))]
1281 debug!("{}: trying likely args: {:?}", short_function!(), &likely_args);
1282 #[cfg(feature = "log_pretty_print")]
1283 debug!("{}: trying likely args: {:#?}", short_function!(), &likely_args);
1284 let likely_rv = self.validate_mutual_close_tx(
1285 wallet,
1286 setup,
1287 estate,
1288 likely_args.to_holder_value_sat,
1289 likely_args.to_counterparty_value_sat,
1290 &likely_args.holder_script,
1291 &likely_args.counterparty_script,
1292 &likely_args.wallet_path,
1293 );
1294
1295 let good_args = if likely_rv.is_ok() {
1296 likely_args
1297 } else {
1298 debug!("{}: trying unlikely args: {:#?}", short_function!(), &unlikely_args);
1300 let unlikely_rv = self.validate_mutual_close_tx(
1301 wallet,
1302 setup,
1303 estate,
1304 unlikely_args.to_holder_value_sat,
1305 unlikely_args.to_counterparty_value_sat,
1306 &unlikely_args.holder_script,
1307 &unlikely_args.counterparty_script,
1308 &unlikely_args.wallet_path,
1309 );
1310 if unlikely_rv.is_ok() {
1311 unlikely_args
1312 } else {
1313 return Err(likely_rv.unwrap_err());
1315 }
1316 };
1317
1318 let closing_tx = ClosingTransaction::new(
1319 good_args.to_holder_value_sat,
1320 good_args.to_counterparty_value_sat,
1321 good_args.holder_script.unwrap_or_else(|| ScriptBuf::new()),
1322 good_args.counterparty_script.unwrap_or_else(|| ScriptBuf::new()),
1323 setup.funding_outpoint,
1324 );
1325 let trusted = closing_tx.trust();
1326 let recomposed_tx = trusted.built_transaction();
1327
1328 if *recomposed_tx != *tx {
1329 debug!("ORIGINAL_TX={:#?}", &tx);
1330 debug!("RECOMPOSED_TX={:#?}", &recomposed_tx);
1331 policy_err!(self, "policy-onchain-format-standard", "recomposed tx mismatch");
1333 }
1334
1335 *debug_on_return = false; Ok(closing_tx)
1337 }
1338
1339 fn validate_mutual_close_tx(
1340 &self,
1341 wallet: &dyn Wallet,
1342 setup: &ChannelSetup,
1343 estate: &EnforcementState,
1344 to_holder_value_sat: u64,
1345 to_counterparty_value_sat: u64,
1346 holder_script: &Option<ScriptBuf>,
1347 counterparty_script: &Option<ScriptBuf>,
1348 holder_wallet_path_hint: &DerivationPath,
1349 ) -> Result<(), ValidationError> {
1350 let mut debug_on_return = scoped_debug_return!(
1351 setup,
1352 estate,
1353 to_holder_value_sat,
1354 to_counterparty_value_sat,
1355 holder_script,
1356 counterparty_script
1357 );
1358
1359 let holder_info = estate.current_holder_commit_info.as_ref().ok_or_else(|| {
1360 policy_error(
1361 "policy-mutual-value-matches-commitment",
1362 "current_holder_commit_info missing",
1363 )
1364 })?;
1365
1366 let counterparty_info =
1367 estate.current_counterparty_commit_info.as_ref().ok_or_else(|| {
1368 policy_error(
1369 "policy-mutual-value-matches-commitment",
1370 "current_counterparty_commit_info missing",
1371 )
1372 })?;
1373
1374 if to_holder_value_sat > 0 && holder_script.is_none() {
1375 policy_err!(
1376 self,
1377 "policy-mutual-destination-allowlisted",
1378 "missing holder_script with {} to_holder_value_sat",
1379 to_holder_value_sat
1380 );
1381 }
1382
1383 if to_counterparty_value_sat > 0 && counterparty_script.is_none() {
1384 policy_err!(
1385 self,
1386 "policy-mutual-destination-allowlisted",
1387 "missing counterparty_script with {} to_counterparty_value_sat",
1388 to_counterparty_value_sat
1389 );
1390 }
1391
1392 if setup.holder_shutdown_script.is_some() && to_holder_value_sat > 0 {
1395 if *holder_script != setup.holder_shutdown_script {
1396 policy_err!(
1397 self,
1398 "policy-mutual-destination-allowlisted",
1399 "holder_script doesn't match upfront holder_shutdown_script"
1400 );
1401 }
1402 }
1403
1404 if !holder_info.htlcs_is_empty() || !counterparty_info.htlcs_is_empty() {
1405 policy_err!(self, "policy-mutual-no-pending-htlcs", "cannot close with pending htlcs");
1406 }
1407
1408 let weight = mutual_close_tx_weight(
1409 &ClosingTransaction::new(
1410 to_holder_value_sat,
1411 to_counterparty_value_sat,
1412 holder_script.clone().unwrap_or_else(|| ScriptBuf::new()),
1413 counterparty_script.clone().unwrap_or_else(|| ScriptBuf::new()),
1414 setup.funding_outpoint,
1415 )
1416 .trust()
1417 .built_transaction(),
1418 );
1419
1420 let sum_outputs =
1422 to_holder_value_sat.checked_add(to_counterparty_value_sat).ok_or_else(|| {
1423 policy_error("policy-mutual-value-matches-commitment", "consumed overflow")
1424 })?;
1425 self.validate_fee("policy-mutual-fee-range", setup.channel_value_sat, sum_outputs, weight)
1426 .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
1427
1428 if setup.is_outbound {
1431 if let (true, descr) = self.outside_epsilon_range(
1434 to_counterparty_value_sat,
1435 counterparty_info.to_broadcaster_value_sat,
1436 ) {
1437 policy_err!(
1438 self,
1439 "policy-mutual-value-matches-commitment",
1440 "to_counterparty_value {} \
1441 is {} than counterparty_info.broadcaster_value_sat {}",
1442 to_counterparty_value_sat,
1443 descr,
1444 counterparty_info.to_broadcaster_value_sat
1445 );
1446 }
1447 if let (true, descr) = self.outside_epsilon_range(
1448 to_counterparty_value_sat,
1449 holder_info.to_countersigner_value_sat,
1450 ) {
1451 policy_err!(
1452 self,
1453 "policy-mutual-value-matches-commitment",
1454 "to_counterparty_value {} \
1455 is {} than holder_info.countersigner_value_sat {}",
1456 to_counterparty_value_sat,
1457 descr,
1458 holder_info.to_countersigner_value_sat
1459 );
1460 }
1461 } else {
1462 if let (true, descr) = self
1465 .outside_epsilon_range(to_holder_value_sat, holder_info.to_broadcaster_value_sat)
1466 {
1467 policy_err!(
1468 self,
1469 "policy-mutual-value-matches-commitment",
1470 "to_holder_value {} is {} than holder_info.broadcaster_value_sat {}",
1471 to_holder_value_sat,
1472 descr,
1473 holder_info.to_broadcaster_value_sat
1474 );
1475 }
1476 if let (true, descr) = self.outside_epsilon_range(
1477 to_holder_value_sat,
1478 counterparty_info.to_countersigner_value_sat,
1479 ) {
1480 policy_err!(
1481 self,
1482 "policy-mutual-value-matches-commitment",
1483 "to_holder_value {} is {} than counterparty_info.countersigner_value_sat {}",
1484 to_holder_value_sat,
1485 descr,
1486 counterparty_info.to_countersigner_value_sat
1487 );
1488 }
1489 }
1490
1491 if let Some(script) = &holder_script {
1492 if !wallet.can_spend(holder_wallet_path_hint, script).map_err(|err| {
1493 policy_error("policy-mutual-scripts", format!("wallet can_spend error: {}", err))
1494 })? && !wallet.allowlist_contains(script, holder_wallet_path_hint)
1495 {
1496 policy_err!(
1497 self,
1498 "policy-mutual-destination-allowlisted",
1499 "holder output not to wallet or in allowlist"
1500 );
1501 }
1502 }
1503
1504 *debug_on_return = false; Ok(())
1506 }
1507
1508 fn validate_delayed_sweep(
1509 &self,
1510 wallet: &dyn Wallet,
1511 setup: &ChannelSetup,
1512 cstate: &ChainState,
1513 tx: &Transaction,
1514 input: usize,
1515 amount_sat: u64,
1516 wallet_path: &DerivationPath,
1517 ) -> Result<(), ValidationError> {
1518 let mut debug_on_return =
1519 scoped_debug_return!(setup, cstate, tx, input, amount_sat, wallet_path);
1520
1521 self.validate_sweep(wallet, tx, input, amount_sat, wallet_path)
1523 .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
1524
1525 if !tx.lock_time.is_satisfied_by(
1527 Height::from_consensus(cstate.current_height + MAX_CHAIN_LAG)
1528 .expect("Height::from_consensus"),
1529 Time::MIN,
1531 ) {
1532 transaction_format_err!(
1533 self,
1534 "policy-sweep-locktime",
1535 "bad locktime: {} > {}",
1536 tx.lock_time,
1537 cstate.current_height + MAX_CHAIN_LAG
1538 );
1539 }
1540
1541 let seq = tx.input[0].sequence.0;
1542 if seq != setup.counterparty_selected_contest_delay as u32 {
1543 transaction_format_err!(
1544 self,
1545 "policy-sweep-sequence",
1546 "bad sequence: {} != {}",
1547 seq,
1548 setup.counterparty_selected_contest_delay
1549 );
1550 }
1551
1552 *debug_on_return = false;
1553 Ok(())
1554 }
1555
1556 fn validate_counterparty_htlc_sweep(
1557 &self,
1558 wallet: &dyn Wallet,
1559 setup: &ChannelSetup,
1560 cstate: &ChainState,
1561 tx: &Transaction,
1562 redeemscript: &ScriptBuf,
1563 input: usize,
1564 amount_sat: u64,
1565 wallet_path: &DerivationPath,
1566 ) -> Result<(), ValidationError> {
1567 let mut debug_on_return =
1568 scoped_debug_return!(setup, cstate, tx, input, amount_sat, wallet_path);
1569
1570 self.validate_sweep(wallet, tx, input, amount_sat, wallet_path)
1572 .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
1573
1574 if let Ok((
1576 _revocation_hash,
1577 _remote_htlc_pubkey,
1578 _payment_hash_vec,
1579 _local_htlc_pubkey,
1580 cltv_expiry,
1581 )) = parse_received_htlc_script(redeemscript, setup.is_anchors())
1582 {
1583 if cltv_expiry < 0 || cltv_expiry > u32::MAX as i64 {
1585 transaction_format_err!(
1586 self,
1587 "policy-sweep-other",
1588 "bad cltv_expiry: {}",
1589 cltv_expiry
1590 );
1591 }
1592
1593 if tx.lock_time.to_consensus_u32() > cltv_expiry as u32 {
1594 transaction_format_err!(
1595 self,
1596 "policy-sweep-locktime",
1597 "bad locktime: {} > {}",
1598 tx.lock_time,
1599 cltv_expiry as u32
1600 );
1601 }
1602 } else if let Ok((
1603 _revocation_hash,
1604 _remote_htlc_pubkey,
1605 _local_htlc_pubkey,
1606 _payment_hash_vec,
1607 )) = parse_offered_htlc_script(redeemscript, setup.is_anchors())
1608 {
1609 if !tx.lock_time.is_satisfied_by(
1611 Height::from_consensus(cstate.current_height + MAX_CHAIN_LAG)
1613 .expect("Height::from_consensus"),
1614 Time::MIN,
1616 ) {
1617 transaction_format_err!(
1618 self,
1619 "policy-sweep-locktime",
1620 "bad locktime: {} > {}",
1621 tx.lock_time,
1622 cstate.current_height + MAX_CHAIN_LAG
1623 );
1624 }
1625 } else {
1626 transaction_format_err!(
1628 self,
1629 "policy-sweep-other",
1630 "bad redeemscript: {}",
1631 &redeemscript
1632 );
1633 };
1634
1635 let seq = tx.input[0].sequence.0;
1636 let valid_seqs = if setup.is_anchors() {
1637 SimpleValidator::ANCHOR_SEQS.to_vec()
1638 } else {
1639 SimpleValidator::NON_ANCHOR_SEQS.to_vec()
1640 };
1641 if !valid_seqs.contains(&seq) {
1642 transaction_format_err!(
1643 self,
1644 "policy-sweep-sequence",
1645 "bad sequence: {} not in {:?}",
1646 seq,
1647 valid_seqs,
1648 );
1649 }
1650
1651 *debug_on_return = false;
1652 Ok(())
1653 }
1654
1655 fn validate_justice_sweep(
1656 &self,
1657 wallet: &dyn Wallet,
1658 _setup: &ChannelSetup,
1659 cstate: &ChainState,
1660 tx: &Transaction,
1661 input: usize,
1662 amount_sat: u64,
1663 wallet_path: &DerivationPath,
1664 ) -> Result<(), ValidationError> {
1665 let mut debug_on_return =
1666 scoped_debug_return!(_setup, cstate, tx, input, amount_sat, wallet_path);
1667
1668 self.validate_sweep(wallet, tx, input, amount_sat, wallet_path)
1670 .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
1671
1672 if !tx.lock_time.is_satisfied_by(
1673 Height::from_consensus(cstate.current_height + MAX_CHAIN_LAG)
1675 .expect("Height::from_consensus"),
1676 Time::MIN,
1678 ) {
1679 transaction_format_err!(
1680 self,
1681 "policy-sweep-locktime",
1682 "bad locktime: {} > {}",
1683 tx.lock_time,
1684 cstate.current_height + MAX_CHAIN_LAG
1685 );
1686 }
1687
1688 let seq = tx.input[0].sequence.0;
1689 let valid_seqs = SimpleValidator::NON_ANCHOR_SEQS.to_vec();
1690 if !valid_seqs.contains(&seq) {
1691 transaction_format_err!(
1692 self,
1693 "policy-sweep-sequence",
1694 "bad sequence: {} not in {:?}",
1695 seq,
1696 valid_seqs
1697 );
1698 }
1699
1700 *debug_on_return = false;
1701 Ok(())
1702 }
1703
1704 fn validate_payment_balance(
1714 &self,
1715 incoming_msat: u64,
1716 outgoing_msat: u64,
1717 invoiced_amount_msat: Option<u64>,
1718 ) -> Result<(), ValidationError> {
1719 let max_to_invoice_msat = if let Some(a) = invoiced_amount_msat {
1720 a + self.policy.max_routing_fee_msat
1721 } else {
1722 0
1723 };
1724
1725 if incoming_msat + max_to_invoice_msat < outgoing_msat {
1727 policy_err!(
1728 self,
1729 "policy-routing-balanced",
1730 "incoming_msat + max_to_invoice_msat < outgoing_msat: {} + {} < {}",
1731 incoming_msat,
1732 max_to_invoice_msat,
1733 outgoing_msat
1734 );
1735 }
1736
1737 if let Some(invoiced_amount_msat) = invoiced_amount_msat {
1738 if invoiced_amount_msat + incoming_msat > outgoing_msat {
1741 return Ok(());
1742 }
1743
1744 let fee = outgoing_msat - invoiced_amount_msat - incoming_msat;
1746 let actual_fee_percentage = fee.checked_mul(100).ok_or(policy_error(
1747 "policy-commitment-payment-velocity",
1748 "policy-generic-error: invoice amount too big",
1749 ))? / core::cmp::max(invoiced_amount_msat, 1);
1750 if actual_fee_percentage > self.policy.max_feerate_percentage.into() {
1751 policy_err!(
1752 self,
1753 "policy-htlc-fee-range",
1754 "fee_percentage > max_feerate_percentage: {actual_fee_percentage}% > {}%",
1755 self.policy.max_feerate_percentage
1756 );
1757 }
1758 }
1759
1760 Ok(())
1761 }
1762
1763 fn enforce_balance(&self) -> bool {
1764 self.policy.enforce_balance
1765 }
1766
1767 fn minimum_initial_balance(&self, holder_value_msat: u64) -> u64 {
1768 holder_value_msat / 1000
1769 }
1770
1771 fn is_ready(&self, cstate: &ChainState) -> bool {
1772 cstate.funding_depth > 0 && cstate.closing_depth == 0
1773 }
1774
1775 fn policy(&self) -> Box<&dyn Policy> {
1776 Box::new(&self.policy)
1777 }
1778}
1779
1780impl SimpleValidator {
1781 fn validate_commitment_tx(
1783 &self,
1784 estate: &EnforcementState,
1785 commit_num: u64,
1786 commitment_point: &PublicKey,
1787 setup: &ChannelSetup,
1788 cstate: &ChainState,
1789 info: &CommitmentInfo2,
1790 ) -> Result<(), ValidationError> {
1791 let mut debug_on_return =
1792 scoped_debug_return!(estate, commit_num, commitment_point, setup, cstate, info);
1793
1794 let policy = &self.policy;
1795
1796 if info.to_broadcaster_value_sat > 0
1797 && info.to_broadcaster_value_sat < MIN_CHAN_DUST_LIMIT_SATOSHIS
1798 {
1799 policy_err!(
1800 self,
1801 "policy-commitment-outputs-trimmed",
1802 "to_broadcaster_value_sat {} less than dust limit {}",
1803 info.to_broadcaster_value_sat,
1804 MIN_CHAN_DUST_LIMIT_SATOSHIS
1805 );
1806 }
1807 if info.to_countersigner_value_sat > 0
1808 && info.to_countersigner_value_sat < MIN_CHAN_DUST_LIMIT_SATOSHIS
1809 {
1810 policy_err!(
1811 self,
1812 "policy-commitment-outputs-trimmed",
1813 "to_countersigner_value_sat {} less than dust limit {}",
1814 info.to_countersigner_value_sat,
1815 MIN_CHAN_DUST_LIMIT_SATOSHIS
1816 );
1817 }
1818
1819 if info.offered_htlcs.len() + info.received_htlcs.len() > policy.max_htlcs {
1820 policy_err!(self, "policy-commitment-htlc-count-limit", "too many HTLCs");
1821 }
1822
1823 let mut htlc_value_sat: u64 = 0;
1824
1825 let offered_htlc_dust_limit = if setup.is_zero_fee_htlc() {
1826 MIN_CHAN_DUST_LIMIT_SATOSHIS
1827 } else {
1828 MIN_DUST_LIMIT_SATOSHIS
1829 + (info.feerate_per_kw as u64 * htlc_timeout_tx_weight(&setup.features()) / 1000)
1830 };
1831 for htlc in &info.offered_htlcs {
1832 self.validate_expiry("offered HTLC", htlc.cltv_expiry, cstate.current_height)?;
1837
1838 htlc_value_sat = htlc_value_sat.checked_add(htlc.value_sat).ok_or_else(|| {
1839 policy_error(
1840 "policy-commitment-payment-velocity",
1841 "offered HTLC value overflow".to_string(),
1842 )
1843 })?;
1844
1845 if htlc.value_sat < offered_htlc_dust_limit {
1846 policy_err!(
1847 self,
1848 "policy-commitment-outputs-trimmed",
1849 "offered htlc.value_sat {} less than dust limit {}",
1850 htlc.value_sat,
1851 offered_htlc_dust_limit
1852 );
1853 }
1854 }
1855
1856 let received_htlc_dust_limit = if setup.is_zero_fee_htlc() {
1857 MIN_CHAN_DUST_LIMIT_SATOSHIS
1858 } else {
1859 MIN_DUST_LIMIT_SATOSHIS
1860 + (info.feerate_per_kw as u64 * htlc_success_tx_weight(&setup.features()) / 1000)
1861 };
1862 for htlc in &info.received_htlcs {
1863 self.validate_expiry("received HTLC", htlc.cltv_expiry, cstate.current_height)?;
1868
1869 htlc_value_sat = htlc_value_sat.checked_add(htlc.value_sat).ok_or_else(|| {
1870 policy_error(
1871 "policy-commitment-payment-velocity",
1872 "received HTLC value overflow".to_string(),
1873 )
1874 })?;
1875
1876 if htlc.value_sat < received_htlc_dust_limit {
1877 policy_err!(
1878 self,
1879 "policy-commitment-outputs-trimmed",
1880 "received htlc.value_sat {} less than dust limit {}",
1881 htlc.value_sat,
1882 received_htlc_dust_limit
1883 );
1884 }
1885 }
1886
1887 if htlc_value_sat > policy.max_htlc_value_sat {
1888 policy_err!(
1889 self,
1890 "policy-commitment-htlc-inflight-limit",
1891 "sum of HTLC values {} too large",
1892 htlc_value_sat
1893 );
1894 }
1895
1896 let expected_weight = expected_commitment_tx_weight(
1897 setup.is_anchors(),
1898 info.offered_htlcs.len() + info.received_htlcs.len(),
1899 );
1900
1901 let sum_outputs = info
1903 .to_broadcaster_value_sat
1904 .checked_add(info.to_countersigner_value_sat)
1905 .ok_or_else(|| {
1906 policy_error(
1907 "policy-commitment-payment-velocity",
1908 "channel value overflow".to_string(),
1909 )
1910 })?
1911 .checked_add(htlc_value_sat)
1912 .ok_or_else(|| {
1913 policy_error(
1914 "policy-commitment-payment-velocity",
1915 "channel value overflow on HTLC".to_string(),
1916 )
1917 })?;
1918 self.validate_fee(
1919 "policy-commitment-fee-range",
1920 setup.channel_value_sat,
1921 sum_outputs,
1922 expected_weight,
1923 )
1924 .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
1925
1926 let (_holder_value_sat, counterparty_value_sat) = info.value_to_parties();
1927
1928 if commit_num == 0 {
1930 if info.offered_htlcs.len() + info.received_htlcs.len() > 0 {
1931 policy_err!(
1932 self,
1933 "policy-commitment-first-no-htlcs",
1934 "initial commitment may not have HTLCS"
1935 );
1936 }
1937
1938 if setup.is_outbound {
1942 if counterparty_value_sat > setup.push_value_msat / 1000 {
1948 policy_err!(
1949 self,
1950 "policy-commitment-initial-funding-value",
1951 "initial commitment may only send push_value_msat ({}) to fundee",
1952 setup.push_value_msat
1953 );
1954 }
1955 }
1956 }
1957
1958 *debug_on_return = false;
1959 Ok(())
1960 }
1961}
1962
1963pub fn make_simple_policy(network: Network, config: OptionizedSimplePolicy) -> SimplePolicy {
1965 config.resolve_defaults(make_default_simple_policy(network))
1966}
1967
1968pub fn make_default_simple_policy(network: Network) -> SimplePolicy {
1970 if network == Network::Bitcoin {
1971 SimplePolicy {
1972 min_delay: 144, max_delay: 2016, max_channel_size_sat: 1_000_000_001,
1975 epsilon_sat: 10_000,
1976 max_htlcs: 1000,
1977 max_htlc_value_sat: 16_777_216,
1978 use_chain_state: false,
1979 min_feerate_per_kw: 253, max_feerate_per_kw: 25_000, enforce_balance: false,
1982 max_routing_fee_msat: 10_000,
1983 max_feerate_percentage: 10,
1984 dev_flags: None,
1985 filter: PolicyFilter::default(),
1986 global_velocity_control: VelocityControlSpec::UNLIMITED,
1987 max_channels: MAX_CHANNELS,
1988 max_invoices: MAX_INVOICES,
1989 fee_velocity_control: DEFAULT_FEE_VELOCITY_CONTROL,
1990 }
1991 } else {
1992 SimplePolicy {
1993 min_delay: 4,
1994 max_delay: 2016, max_channel_size_sat: 1_000_000_001, epsilon_sat: 10_000, max_htlcs: 1000,
1999 max_htlc_value_sat: 16_777_216, use_chain_state: false,
2001 min_feerate_per_kw: 253, max_feerate_per_kw: 333_333, enforce_balance: false,
2004 max_routing_fee_msat: 222_000, max_feerate_percentage: 10,
2006 dev_flags: None,
2007 filter: PolicyFilter::default(),
2008 global_velocity_control: VelocityControlSpec::UNLIMITED,
2009 max_channels: MAX_CHANNELS,
2010 max_invoices: MAX_INVOICES,
2011 fee_velocity_control: DEFAULT_FEE_VELOCITY_CONTROL,
2012 }
2013 }
2014}
2015
2016#[cfg(test)]
2017mod tests {
2018 use lightning::types::payment::PaymentHash;
2019 use test_log::test;
2020
2021 use crate::tx::tx::HTLCInfo2;
2022 use crate::util::test_utils::key::*;
2023 use crate::util::test_utils::*;
2024
2025 use super::*;
2026
2027 fn make_test_validator() -> SimpleValidator {
2028 let policy = SimplePolicy {
2029 min_delay: 5,
2030 max_delay: 1440,
2031 max_channel_size_sat: 100_000_000,
2032 epsilon_sat: 100_000,
2033 max_htlcs: 1000,
2034 max_htlc_value_sat: 10_000_000,
2035 use_chain_state: true,
2036 min_feerate_per_kw: 1000,
2037 max_feerate_per_kw: 1000 * 1000,
2038 max_feerate_percentage: 10,
2039 enforce_balance: false,
2040 max_routing_fee_msat: 10000,
2041 dev_flags: None,
2042 filter: PolicyFilter::default(),
2043 global_velocity_control: VelocityControlSpec::UNLIMITED,
2044 max_channels: MAX_CHANNELS,
2045 max_invoices: MAX_INVOICES,
2046 fee_velocity_control: DEFAULT_FEE_VELOCITY_CONTROL,
2047 };
2048
2049 SimpleValidator {
2050 policy,
2051 node_id: PublicKey::from_slice(&[2u8; 33]).unwrap(),
2052 channel_id: None,
2053 }
2054 }
2055
2056 #[test]
2057 fn decode_commitment_test() {
2058 let validator = make_test_validator();
2059 let info = validator
2060 .decode_commitment_tx(
2061 &make_test_channel_keys(),
2062 &make_test_channel_setup(),
2063 true,
2064 &make_test_commitment_tx(),
2065 &vec![vec![]],
2066 )
2067 .unwrap();
2068 assert_eq!(info.is_counterparty_broadcaster, true);
2069 }
2070
2071 #[test]
2072 fn validate_policy_commitment_version() {
2073 let validator = make_test_validator();
2074 let mut tx = make_test_commitment_tx();
2075 tx.version = Version::ONE;
2076 let res = validator.decode_commitment_tx(
2077 &make_test_channel_keys(),
2078 &make_test_channel_setup(),
2079 true,
2080 &tx,
2081 &vec![vec![]],
2082 );
2083 assert_policy_err!(
2084 res,
2085 "policy-commitment-version",
2086 "decode_commitment_tx: bad commitment version: 1"
2087 );
2088 }
2089
2090 #[test]
2091 fn validate_channel_value_test() {
2092 let mut setup = make_test_channel_setup();
2093 let validator = make_test_validator();
2094 setup.channel_value_sat = 100_000_000;
2095 assert!(validator.validate_channel_value(&setup).is_ok());
2096 setup.channel_value_sat = 100_000_001;
2097 assert!(validator.validate_channel_value(&setup).is_err());
2098 }
2099
2100 fn make_counterparty_info(
2101 to_holder_value_sat: u64,
2102 to_counterparty_value_sat: u64,
2103 offered_htlcs: Vec<HTLCInfo2>,
2104 received_htlcs: Vec<HTLCInfo2>,
2105 ) -> CommitmentInfo2 {
2106 make_counterparty_info_with_feerate(
2107 to_holder_value_sat,
2108 to_counterparty_value_sat,
2109 offered_htlcs,
2110 received_htlcs,
2111 6500,
2112 )
2113 }
2114
2115 fn make_counterparty_info_with_feerate(
2116 to_holder_value_sat: u64,
2117 to_counterparty_value_sat: u64,
2118 offered_htlcs: Vec<HTLCInfo2>,
2119 received_htlcs: Vec<HTLCInfo2>,
2120 feerate_per_kw: u32,
2121 ) -> CommitmentInfo2 {
2122 CommitmentInfo2::new(
2123 true,
2124 to_holder_value_sat,
2125 to_counterparty_value_sat,
2126 offered_htlcs,
2127 received_htlcs,
2128 feerate_per_kw,
2129 )
2130 }
2131
2132 fn make_htlc_info2(expiry: u32) -> HTLCInfo2 {
2133 HTLCInfo2 { value_sat: 5010, payment_hash: PaymentHash([0; 32]), cltv_expiry: expiry }
2134 }
2135
2136 #[test]
2137 fn validate_commitment_tx_test() {
2138 let validator = make_test_validator();
2139 let mut enforcement_state = EnforcementState::new(0);
2140 let commit_num = 23;
2141 enforcement_state
2142 .set_next_counterparty_commit_num_for_testing(commit_num, make_test_pubkey(0x10));
2143 enforcement_state.set_next_counterparty_revoke_num_for_testing(commit_num - 1);
2144 let commit_point = make_test_pubkey(0x12);
2145 let cstate = make_test_chain_state();
2146 let setup = make_test_channel_setup();
2147 let info = make_counterparty_info(2_000_000, 999_000, vec![], vec![]);
2148 assert_status_ok!(validator.validate_commitment_tx(
2149 &enforcement_state,
2150 commit_num,
2151 &commit_point,
2152 &setup,
2153 &cstate,
2154 &info,
2155 ));
2156 }
2157
2158 #[test]
2161 fn validate_to_holder_min_delay_test() {
2162 let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
2163 let mut setup = make_test_channel_setup();
2164 let validator = make_test_validator();
2165 setup.holder_selected_contest_delay = 5;
2166 let derivation_path = DerivationPath::master();
2167 assert!(validator.validate_setup_channel(&*node, &setup, &derivation_path).is_ok());
2168 setup.holder_selected_contest_delay = 4;
2169 assert_policy_err!(
2170 validator.validate_setup_channel(&*node, &setup, &derivation_path),
2171 "policy-channel-contest-delay-range-counterparty",
2172 "validate_delay: counterparty contest-delay too small: 4 < 5"
2173 );
2174 }
2175
2176 #[test]
2178 fn validate_safe_modes_test() {
2179 let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
2180 let mut setup = make_test_channel_setup();
2181 let validator = make_test_validator();
2182
2183 let derivation_path = DerivationPath::master();
2184 assert!(validator.validate_setup_channel(&*node, &setup, &derivation_path).is_ok());
2185
2186 setup.commitment_type = CommitmentType::Anchors;
2187 assert!(validator.validate_setup_channel(&*node, &setup, &derivation_path).is_err());
2188
2189 setup.commitment_type = CommitmentType::Legacy;
2190 assert!(validator.validate_setup_channel(&*node, &setup, &derivation_path).is_err());
2191 }
2192
2193 #[test]
2196 fn validate_to_holder_max_delay_test() {
2197 let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
2198 let mut setup = make_test_channel_setup();
2199 let validator = make_test_validator();
2200 setup.holder_selected_contest_delay = 1440;
2201 let derivation_path = DerivationPath::master();
2202 assert!(validator.validate_setup_channel(&*node, &setup, &derivation_path).is_ok());
2203 setup.holder_selected_contest_delay = 1441;
2204 assert_policy_err!(
2205 validator.validate_setup_channel(&*node, &setup, &derivation_path),
2206 "policy-channel-contest-delay-range-counterparty",
2207 "validate_delay: counterparty contest-delay too large: 1441 > 1440"
2208 );
2209 }
2210
2211 #[test]
2214 fn validate_to_counterparty_min_delay_test() {
2215 let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
2216 let mut setup = make_test_channel_setup();
2217 let validator = make_test_validator();
2218 setup.counterparty_selected_contest_delay = 5;
2219 let derivation_path = DerivationPath::master();
2220 assert!(validator.validate_setup_channel(&*node, &setup, &derivation_path).is_ok());
2221
2222 setup.counterparty_selected_contest_delay = 4;
2223 assert_policy_err!(
2224 validator.validate_setup_channel(&*node, &setup, &derivation_path),
2225 "policy-channel-contest-delay-range-holder",
2226 "validate_delay: holder contest-delay too small: 4 < 5"
2227 );
2228 }
2229
2230 #[test]
2233 fn validate_to_counterparty_max_delay_test() {
2234 let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
2235 let mut setup = make_test_channel_setup();
2236 let validator = make_test_validator();
2237 setup.counterparty_selected_contest_delay = 1440;
2238 let derivation_path = DerivationPath::master();
2239 assert!(validator.validate_setup_channel(&*node, &setup, &derivation_path).is_ok());
2240
2241 setup.counterparty_selected_contest_delay = 1441;
2242 assert_policy_err!(
2243 validator.validate_setup_channel(&*node, &setup, &derivation_path),
2244 "policy-channel-contest-delay-range-holder",
2245 "validate_delay: holder contest-delay too large: 1441 > 1440"
2246 );
2247 }
2248
2249 #[test]
2251 fn validate_commitment_tx_shortage_test() {
2252 let validator = make_test_validator();
2253 let enforcement_state = EnforcementState::new(0);
2254 let commit_num = 0;
2255 let commit_point = make_test_pubkey(0x12);
2256 let cstate = make_test_chain_state();
2257 let setup = make_test_channel_setup();
2258 let info_bad = make_counterparty_info(2_000_000, 1_000_001, vec![], vec![]);
2259 assert_policy_err!(
2260 validator.validate_commitment_tx(
2261 &enforcement_state,
2262 commit_num,
2263 &commit_point,
2264 &setup,
2265 &cstate,
2266 &info_bad,
2267 ),
2268 "policy-commitment-fee-range",
2269 "validate_commitment_tx: fee underflow: 3000000 - 3000001"
2270 );
2271 }
2272
2273 #[test]
2275 fn validate_commitment_tx_htlc_shortage_test() {
2276 let validator = make_test_validator();
2277 let htlc =
2278 HTLCInfo2 { value_sat: 100_000, payment_hash: PaymentHash([0; 32]), cltv_expiry: 1005 };
2279 let mut enforcement_state = EnforcementState::new(0);
2280 let commit_num = 23;
2281 enforcement_state
2282 .set_next_counterparty_commit_num_for_testing(commit_num, make_test_pubkey(0x10));
2283 enforcement_state.set_next_counterparty_revoke_num_for_testing(commit_num - 1);
2284 let commit_point = make_test_pubkey(0x12);
2285 let cstate = make_test_chain_state();
2286 let setup = make_test_channel_setup();
2287 let info = make_counterparty_info(2_000_000, 899_000, vec![htlc.clone()], vec![]);
2288
2289 assert_status_ok!(validator.validate_commitment_tx(
2290 &enforcement_state,
2291 commit_num,
2292 &commit_point,
2293 &setup,
2294 &cstate,
2295 &info,
2296 ));
2297
2298 let info_bad = make_counterparty_info(2_000_000, 1_000_000, vec![htlc.clone()], vec![]);
2299 assert_policy_err!(
2300 validator.validate_commitment_tx(
2301 &enforcement_state,
2302 commit_num,
2303 &commit_point,
2304 &setup,
2305 &cstate,
2306 &info_bad,
2307 ),
2308 "policy-commitment-fee-range",
2309 "validate_commitment_tx: fee underflow: 3000000 - 3100000"
2310 );
2311 }
2312
2313 #[test]
2315 fn validate_commitment_tx_initial_with_htlcs() {
2316 let validator = make_test_validator();
2317 let htlc =
2318 HTLCInfo2 { value_sat: 199_000, payment_hash: PaymentHash([0; 32]), cltv_expiry: 1005 };
2319 let enforcement_state = EnforcementState::new(0);
2320 let commit_num = 0;
2321 let commit_point = make_test_pubkey(0x12);
2322 let cstate = make_test_chain_state();
2323 let setup = make_test_channel_setup();
2324 let info = make_counterparty_info(2_000_000, 800_000, vec![htlc.clone()], vec![]);
2325
2326 let status = validator.validate_commitment_tx(
2327 &enforcement_state,
2328 commit_num,
2329 &commit_point,
2330 &setup,
2331 &cstate,
2332 &info,
2333 );
2334 assert_policy_err!(
2335 status,
2336 "policy-commitment-first-no-htlcs",
2337 "validate_commitment_tx: initial commitment may not have HTLCS"
2338 );
2339 }
2340
2341 #[test]
2343 fn validate_commitment_tx_initial_with_bad_fundee_output() {
2344 let validator = make_test_validator();
2345 let enforcement_state = EnforcementState::new(0);
2346 let commit_num = 0;
2347 let commit_point = make_test_pubkey(0x12);
2348 let cstate = make_test_chain_state();
2349 let setup = make_test_channel_setup();
2350 let info = make_counterparty_info(2_000_000, 999_000, vec![], vec![]);
2351
2352 let status = validator.validate_commitment_tx(
2353 &enforcement_state,
2354 commit_num,
2355 &commit_point,
2356 &setup,
2357 &cstate,
2358 &info,
2359 );
2360 assert_policy_err!(
2361 status,
2362 "policy-commitment-initial-funding-value",
2363 "validate_commitment_tx: initial commitment may only send push_value_msat (0) to fundee"
2364 );
2365 }
2366
2367 #[test]
2369 fn validate_commitment_tx_htlc_count_test() {
2370 let validator = make_test_validator();
2371 let enforcement_state = EnforcementState::new(0);
2372 let commit_num = 0;
2373 let commit_point = make_test_pubkey(0x12);
2374 let cstate = make_test_chain_state();
2375 let setup = make_test_channel_setup();
2376 let htlcs = (0..1001).map(|_| make_htlc_info2(1100)).collect();
2377 let info_bad = make_counterparty_info(99_000_000, 900_000, vec![], htlcs);
2378 assert_policy_err!(
2379 validator.validate_commitment_tx(
2380 &enforcement_state,
2381 commit_num,
2382 &commit_point,
2383 &setup,
2384 &cstate,
2385 &info_bad,
2386 ),
2387 "policy-commitment-htlc-count-limit",
2388 "validate_commitment_tx: too many HTLCs"
2389 );
2390 }
2391
2392 #[test]
2394 fn validate_commitment_tx_htlc_value_test() {
2395 let validator = make_test_validator();
2396 let enforcement_state = EnforcementState::new(0);
2397 let commit_num = 0;
2398 let commit_point = make_test_pubkey(0x12);
2399 let cstate = make_test_chain_state();
2400 let setup = make_test_channel_setup();
2401 let htlcs = (0..1000)
2402 .map(|_| HTLCInfo2 {
2403 value_sat: 10001,
2404 payment_hash: PaymentHash([0; 32]),
2405 cltv_expiry: 1100,
2406 })
2407 .collect();
2408 let info_bad = make_counterparty_info(99_000_000, 900_000, vec![], htlcs);
2409 assert_policy_err!(
2410 validator.validate_commitment_tx(
2411 &enforcement_state,
2412 commit_num,
2413 &commit_point,
2414 &setup,
2415 &cstate,
2416 &info_bad,
2417 ),
2418 "policy-commitment-htlc-inflight-limit",
2419 "validate_commitment_tx: sum of HTLC values 10001000 too large"
2420 );
2421 }
2422
2423 #[test]
2424 fn validate_commitment_tx_htlc_delay_test() {
2425 let validator = make_test_validator();
2426 let mut enforcement_state = EnforcementState::new(0);
2427 let commit_num = 23;
2428 enforcement_state
2429 .set_next_counterparty_commit_num_for_testing(commit_num, make_test_pubkey(0x10));
2430 enforcement_state.set_next_counterparty_revoke_num_for_testing(commit_num - 1);
2431 let commit_point = make_test_pubkey(0x12);
2432 let cstate = make_test_chain_state();
2433 let setup = make_test_channel_setup();
2434 let info_good =
2435 make_counterparty_info(2_000_000, 990_000, vec![], vec![make_htlc_info2(1005)]);
2436 assert_validation_ok!(validator.validate_commitment_tx(
2437 &enforcement_state,
2438 commit_num,
2439 &commit_point,
2440 &setup,
2441 &cstate,
2442 &info_good,
2443 ));
2444 let info_good =
2445 make_counterparty_info(2_000_000, 990_000, vec![], vec![make_htlc_info2(2440)]);
2446 assert_validation_ok!(validator.validate_commitment_tx(
2447 &enforcement_state,
2448 commit_num,
2449 &commit_point,
2450 &setup,
2451 &cstate,
2452 &info_good,
2453 ));
2454 let info_bad =
2455 make_counterparty_info(2_000_000, 990_000, vec![], vec![make_htlc_info2(1004)]);
2456 assert_policy_err!(
2457 validator.validate_commitment_tx(
2458 &enforcement_state,
2459 commit_num,
2460 &commit_point,
2461 &setup,
2462 &cstate,
2463 &info_bad,
2464 ),
2465 "policy-commitment-htlc-cltv-range",
2466 "validate_expiry: received HTLC expiry too early: 1004 < 1005"
2467 );
2468 let info_bad =
2469 make_counterparty_info(2_000_000, 990_000, vec![], vec![make_htlc_info2(2441)]);
2470 assert_policy_err!(
2471 validator.validate_commitment_tx(
2472 &enforcement_state,
2473 commit_num,
2474 &commit_point,
2475 &setup,
2476 &cstate,
2477 &info_bad,
2478 ),
2479 "policy-commitment-htlc-cltv-range",
2480 "validate_expiry: received HTLC expiry too late: 2441 > 2440"
2481 );
2482 }
2483
2484 #[test]
2485 fn enforcement_state_previous_counterparty_point_test() {
2486 let mut state = EnforcementState::new(0);
2487 let validator = make_test_validator();
2488
2489 let point0 = make_test_pubkey(0x12);
2490 let commit_info = make_test_commitment_info();
2491
2492 assert_policy_err!(
2494 validator.set_next_counterparty_commit_num(
2495 &mut state,
2496 0,
2497 point0.clone(),
2498 commit_info.clone()
2499 ),
2500 "policy-other",
2501 "set_next_counterparty_commit_num: can\'t set next to 0"
2502 );
2503
2504 assert_eq!(state.get_previous_counterparty_point(0), None);
2506
2507 assert_eq!(state.get_previous_counterparty_point(1), None);
2509
2510 assert_policy_err!(
2512 validator.set_next_counterparty_commit_num(
2513 &mut state,
2514 2,
2515 point0.clone(),
2516 commit_info.clone()
2517 ),
2518 "policy-commitment-previous-revoked",
2519 "set_next_counterparty_commit_num: invalid progression: 0 to 2"
2520 );
2521
2522 assert!(validator
2524 .set_next_counterparty_commit_num(&mut state, 1, point0.clone(), commit_info.clone())
2525 .is_ok());
2526
2527 assert_eq!(state.get_previous_counterparty_point(0).unwrap(), point0.clone());
2529
2530 assert!(validator
2533 .set_next_counterparty_commit_num(&mut state, 1, point0.clone(), commit_info.clone())
2534 .is_ok());
2535 assert_eq!(state.next_counterparty_commit_num, 1);
2536
2537 assert_eq!(state.get_previous_counterparty_point(1), None);
2539
2540 let point1 = make_test_pubkey(0x16);
2542 assert_policy_err!(
2543 validator.set_next_counterparty_commit_num(
2544 &mut state,
2545 3,
2546 point1.clone(),
2547 commit_info.clone()
2548 ),
2549 "policy-commitment-previous-revoked",
2550 "set_next_counterparty_commit_num: \
2551 invalid progression: 1 to 3"
2552 );
2553 assert_eq!(state.next_counterparty_commit_num, 1);
2554
2555 assert!(validator
2557 .set_next_counterparty_commit_num(&mut state, 2, point1.clone(), commit_info.clone())
2558 .is_ok());
2559 assert_eq!(state.next_counterparty_commit_num, 2);
2560
2561 assert_eq!(state.get_previous_counterparty_point(0).unwrap(), point0.clone());
2563
2564 assert_eq!(state.get_previous_counterparty_point(1).unwrap(), point1.clone());
2566
2567 assert_eq!(state.get_previous_counterparty_point(2), None);
2569
2570 assert_policy_err!(
2572 validator.set_next_counterparty_commit_num(
2573 &mut state,
2574 4,
2575 point1.clone(),
2576 commit_info.clone()
2577 ),
2578 "policy-commitment-previous-revoked",
2579 "set_next_counterparty_commit_num: invalid progression: 2 to 4"
2580 );
2581 assert_eq!(state.next_counterparty_commit_num, 2);
2582
2583 assert!(validator.set_next_counterparty_revoke_num(&mut state, 1).is_ok());
2584
2585 let point2 = make_test_pubkey(0x20);
2587 assert!(validator
2588 .set_next_counterparty_commit_num(&mut state, 3, point2.clone(), commit_info.clone())
2589 .is_ok());
2590 assert_eq!(state.next_counterparty_commit_num, 3);
2591
2592 assert_eq!(state.get_previous_counterparty_point(0), None);
2594
2595 assert_eq!(state.get_previous_counterparty_point(1).unwrap(), point1.clone());
2597
2598 assert_eq!(state.get_previous_counterparty_point(2).unwrap(), point2.clone());
2600
2601 assert_eq!(state.get_previous_counterparty_point(3), None);
2603 }
2604
2605 #[test]
2606 fn validate_payment_balance_with_zero_invoiced_amount_test() {
2607 let validator = make_test_validator();
2608 let result = validator.validate_payment_balance(100, 100, Some(0));
2609 assert!(result.is_ok());
2610 }
2611}