lightning_signer/policy/
simple_validator.rs

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
53/// A factory for SimpleValidator
54pub struct SimpleValidatorFactory {
55    pub(crate) policy: Option<SimplePolicy>,
56}
57
58impl SimpleValidatorFactory {
59    /// Create a new simple validator factory with default policy settings
60    pub fn new() -> Self {
61        SimpleValidatorFactory { policy: None }
62    }
63
64    /// Create a new simple validator factory with a specified policy
65    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/// A simple policy to configure a SimpleValidator
92#[derive(Clone, Debug, Optionized, Deserialize)]
93pub struct SimplePolicy {
94    /// Minimum delay in blocks
95    pub min_delay: u16,
96    /// Maximum delay in blocks
97    pub max_delay: u16,
98    /// Maximum channel value in satoshi
99    pub max_channel_size_sat: u64,
100    /// amounts below this number of satoshi are not considered important
101    pub epsilon_sat: u64,
102    /// Maximum number of in-flight HTLCs
103    pub max_htlcs: usize,
104    /// Maximum value of in-flight HTLCs
105    pub max_htlc_value_sat: u64,
106    /// Whether to use knowledge of chain state (e.g. current_height)
107    pub use_chain_state: bool,
108    /// Minimum feerate
109    pub min_feerate_per_kw: u32,
110    /// Maximum feerate
111    pub max_feerate_per_kw: u32,
112    /// Enforce holder balance
113    pub enforce_balance: bool,
114    /// Maximum layer-2 fee
115    pub max_routing_fee_msat: u64,
116    /// Maximum layer-2 percentage fee, this is setting
117    /// up the max fee percentage to pay for a payment.
118    pub max_feerate_percentage: u8,
119    /// Developer flags - DO NOT USE IN PRODUCTION
120    pub dev_flags: Option<PolicyDevFlags>,
121    /// Policy filter
122    pub filter: PolicyFilter,
123    /// Global velocity control specification
124    pub global_velocity_control: VelocityControlSpec,
125    /// Maximum number of channels
126    pub max_channels: usize,
127    /// Maximum number of invoices
128    pub max_invoices: usize,
129    /// Fee velocity control specification
130    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/// Development flags included in SimplePolicy
168#[derive(Clone, Debug, Deserialize)]
169pub struct PolicyDevFlags {
170    /// Allow sending to unknown destinations
171    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
183/// A simple validator.
184/// See [`SimpleValidatorFactory`] for construction
185pub 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, // also policy-{commitment,mutual}-fee-range
284                "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, // also policy-{commitment,mutual}-fee-range
293                "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    // Common validation for validate_{delayed,counterparty_htlc,justice}_sweep
347    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        // LDK now provides multi-input txs, and we can't easily validate fees securely
360        // TODO(522) Since we see the tx on-chain, we should just get the input amount from there
361
362        // // policy-sweep-fee-range
363        // self.validate_fee(amount_sat, tx.output[0].value.to_sat())
364        //     .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
365
366        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        // NOTE - setup.channel_value_sat is not valid, set later on.
402
403        // policy-channel-safe-type
404        if !SAFE_COMMITMENT_TYPE.contains(&setup.commitment_type) {
405            if setup.commitment_type == CommitmentType::Anchors {
406                // special case for anchors, so that they can be enabled until all
407                // dependent projects update to zero-fee HTLCs
408                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        // policy-channel-contest-delay-range-counterparty
424        // policy-commitment-to-self-delay-range relies on this value
425        self.validate_delay("holder", setup.counterparty_selected_contest_delay as u32)?;
426
427        // policy-channel-contest-delay-range-holder
428        // policy-commitment-to-self-delay-range relies on this value
429        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                // Possible change output to our wallet
529                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                    // Possible output to allowlisted xpub
543                    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                // Possible output to allowlisted address
567                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                // Possible funded channel balance
572                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                // policy-onchain-no-unknown-outputs
656                unknowns.push(outndx);
657            }
658        }
659
660        if unknowns.len() > 0 {
661            return Err(unknown_destinations_error(unknowns));
662        }
663
664        // policy-onchain-fee-range
665        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    /// panics if `keys` doesn't have counterparty keys populated
680    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        // Validate common commitment constraints
745        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 next_counterparty_revoke_num is 20:
752        // - commit_num 19 has been revoked
753        // - commit_num 20 is current, previously signed, ok to resign
754        // - commit_num 21 is ok to sign, advances the state
755        // - commit_num 22 is not ok to sign
756        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        // Is this a retry?
768        // not a security problem, because it's OK to re-sign an old commitment
769        // that the *counterparty* revoked
770        if commit_num + 1 == estate.next_counterparty_commit_num {
771            // The commit_point must be the same as previous
772            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            // The CommitmentInfo2 must be the same as previously
798            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        // Validate common commitment constraints
858        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        // Is this a retry?
865        if commit_num + 1 == estate.next_holder_commit_num {
866            // The CommitmentInfo2 must be the same as previously
867            // unwrap is safe, because commitment number can't be > 0 without a holder commitment_info
868            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        // This test overlaps the check in set_next_holder_commit_num but gives
882        // better diagnostic.
883        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        // It's ok to validate the current state when closed, but not ok to validate
896        // a new state.
897        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        // Only allowed to revoke expected next or retry.
915        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        // policy-commitment-previous-revoked (partial: secret validated, but not stored here)
929        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    // Phase 1
960    // setup and txkeys must come from a trusted source
961    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 // the local side imposes this value
974        } else {
975            setup.counterparty_selected_contest_delay // the remote side imposes this value
976        };
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        // Extract some parameters from the submitted transaction.
1009        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]), // isn't used
1033            transaction_output_index: Some(transaction_output_index),
1034        };
1035
1036        // Recompose the transaction.
1037        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        // unwrap is safe because we know the tx is valid
1048        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        // The sighash comparison in the previous block will fail if any of the
1093        // following policies are violated:
1094        // - policy-htlc-version
1095        // - policy-htlc-locktime
1096        // - policy-htlc-sequence
1097        // - policy-htlc-to-self-delay
1098        // - policy-htlc-revocation-pubkey
1099        // - policy-htlc-delayed-pubkey
1100
1101        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        // This must be further checked with policy-htlc-cltv-range.
1116        // Note that we can't check cltv_expiry for non-offered 2nd level
1117        // HTLC txs in phase 1, because they don't mention the cltv_expiry
1118        // there, only in the commitment tx output.
1119        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        // Log state and inputs if we don't succeed.
1157        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                    // Log the addresses associated with the outputs
1165                    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        // The caller checked, this shouldn't happen
1191        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        // Establish which output belongs to the holder by trying all possibilities
1201
1202        // Guess which ordering is most likely based on commitment values.
1203        // - Makes it unlikely we'll have to call validate a second time.
1204        // - Allows us to return the "better" validation error.
1205
1206        #[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        // If the commitments are not in the expected state, or the values
1216        // are outside epsilon from each other the comparison won't be
1217        // meaningful and an arbitrary order will have to do ...
1218        //
1219        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            // Try the other case
1299            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 the error from the likely attempt, it's probably "better"
1314                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            // this actually covers a few policies, not just format
1332            policy_err!(self, "policy-onchain-format-standard", "recomposed tx mismatch");
1333        }
1334
1335        *debug_on_return = false; // don't debug when we succeed
1336        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 the upfront holder_shutdown_script was in effect, make sure the
1393        // holder script matches.
1394        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        // policy-mutual-fee-range
1421        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        // To make this test independent of variable fees we compare the side that
1429        // isn't paying the fees.
1430        if setup.is_outbound {
1431            // We are the funder and paying the fees, make sure the counterparty's output matches
1432            // the latest commitments.  Our value will then be enforced by the max-fee policy.
1433            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            // The counterparty is the funder, make sure the holder's
1463            // output matches the latest commitments.
1464            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; // don't debug when we succeed
1505        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        // Common sweep validation
1522        self.validate_sweep(wallet, tx, input, amount_sat, wallet_path)
1523            .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
1524
1525        // this is safe because we know that the current height is reasonable
1526        if !tx.lock_time.is_satisfied_by(
1527            Height::from_consensus(cstate.current_height + MAX_CHAIN_LAG)
1528                .expect("Height::from_consensus"),
1529            // We are only interested in checking the height, and not the time. So we can put here any value.
1530            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        // Common sweep validation
1571        self.validate_sweep(wallet, tx, input, amount_sat, wallet_path)
1572            .map_err(|ve| ve.prepend_msg(format!("{}: ", containing_function!())))?;
1573
1574        // Parse the redeemscript to determine the cltv_expiry
1575        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            // It's a received htlc (counterparty perspective)
1584            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            // It's an offered htlc (counterparty perspective)
1610            if !tx.lock_time.is_satisfied_by(
1611                // this is safe because we know that the current height is reasonable
1612                Height::from_consensus(cstate.current_height + MAX_CHAIN_LAG)
1613                    .expect("Height::from_consensus"),
1614                // We are only interested in checking the height, and not the time. So we can put here any value.
1615                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            // The redeemscript didn't parse as received or offered ...
1627            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        // Common sweep validation
1669        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            // this is safe because we know that the current height is reasonable
1674            Height::from_consensus(cstate.current_height + MAX_CHAIN_LAG)
1675                .expect("Height::from_consensus"),
1676            // We are only interested in checking the height, and not the time. So we can put here any value.
1677            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    /// When thinking about payment routing and balance, it is
1705    /// useful to consider three cases:
1706    ///
1707    /// 1. When `invoiced_amount_msat` is specified and the `incoming_msat` is 0;
1708    /// e.g. we are paying an invoice and there is no loop in the routing through us
1709    /// 2. When `invoiced_amount_msat` is specified and the `incoming_msat` is not 0;
1710    /// e.g. we are paying an invoice and there is a loop in the routing that includes us
1711    /// 3. When no `invoiced_amount_msat` is specified and the `incoming_msat` is not 0;
1712    /// e.g forwarding a payment.
1713    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        // this also implicitly implements policy-commitment-payment-invoiced
1726        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            // When we are underpaying the invoice or we are not paying fee,
1739            // there is no need to check the fee here.
1740            if invoiced_amount_msat + incoming_msat > outgoing_msat {
1741                return Ok(());
1742            }
1743
1744            // check if the payment is payment an percentage of the fee
1745            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    // Common commitment validation applicable to both holder and counterparty txs
1782    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            // TODO(512) - this check should be converted into two checks, one the first time
1833            // the HTLC is introduced and the other every time it is encountered.
1834            //
1835            // policy-commitment-htlc-cltv-range
1836            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            // TODO(512) - this check should be converted into two checks, one the first time
1864            // the HTLC is introduced and the other every time it is encountered.
1865            //
1866            // policy-commitment-htlc-cltv-range
1867            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        // policy-commitment-fee-range
1902        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        // Enforce additional requirements on initial commitments.
1929        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 we are the funder, the value to us of the initial
1939            // commitment transaction should be equal to our funding
1940            // value.
1941            if setup.is_outbound {
1942                // Ensure that no extra value is sent to fundee, the
1943                // no-initial-htlcs and fee checks above will ensure
1944                // that our share is valid.
1945
1946                // The fundee is only entitled to push_value
1947                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
1963/// Construct a simple policy
1964pub fn make_simple_policy(network: Network, config: OptionizedSimplePolicy) -> SimplePolicy {
1965    config.resolve_defaults(make_default_simple_policy(network))
1966}
1967
1968/// Construct a default simple policy
1969pub fn make_default_simple_policy(network: Network) -> SimplePolicy {
1970    if network == Network::Bitcoin {
1971        SimplePolicy {
1972            min_delay: 144,  // LDK min
1973            max_delay: 2016, // LDK max
1974            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,    // mainnet observed
1980            max_feerate_per_kw: 25_000, // equiv to 100 sat/vb
1981            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,                     // Match LDK maximum and default
1995            max_channel_size_sat: 1_000_000_001, // lnd itest: wumbu default + 1
1996            // lnd itest: async_bidirectional_payments (large amount of dust HTLCs) 1_600_000
1997            epsilon_sat: 10_000, // c-lightning
1998            max_htlcs: 1000,
1999            max_htlc_value_sat: 16_777_216, // lnd itest: multi-hop_htlc_error_propagation
2000            use_chain_state: false,
2001            min_feerate_per_kw: 253,     // testnet/regtest observed
2002            max_feerate_per_kw: 333_333, // 301_096 observed in testnet
2003            enforce_balance: false,
2004            max_routing_fee_msat: 222_000, // CLN test_pay_avoid_low_fee_chan_1: 200_000
2005            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    // policy-channel-contest-delay-range-holder
2159    // policy-commitment-to-self-delay-range
2160    #[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    // policy-channel-safe-type
2177    #[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    // policy-channel-contest-delay-range-holder
2194    // policy-commitment-to-self-delay-range
2195    #[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    // policy-channel-contest-delay-range-counterparty
2212    // policy-commitment-to-self-delay-range
2213    #[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    // policy-channel-contest-delay-range-counterparty
2231    // policy-commitment-to-self-delay-range
2232    #[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    // policy-commitment-fee-range
2250    #[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    // policy-commitment-fee-range
2274    #[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    // policy-commitment-first-no-htlcs
2314    #[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    // policy-commitment-initial-funding-value
2342    #[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    // policy-commitment-htlc-count-limit
2368    #[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    // policy-commitment-htlc-inflight-limit
2393    #[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        // you can never set next to 0
2493        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        // point for 0 is not set yet
2505        assert_eq!(state.get_previous_counterparty_point(0), None);
2506
2507        // can't look forward either
2508        assert_eq!(state.get_previous_counterparty_point(1), None);
2509
2510        // can't skip forward
2511        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        // set point 0
2523        assert!(validator
2524            .set_next_counterparty_commit_num(&mut state, 1, point0.clone(), commit_info.clone())
2525            .is_ok());
2526
2527        // and now you can get it.
2528        assert_eq!(state.get_previous_counterparty_point(0).unwrap(), point0.clone());
2529
2530        // you can set it again to the same thing (retry)
2531        // policy-v2-commitment-retry-same
2532        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        // can't get commit_num 1 yet
2538        assert_eq!(state.get_previous_counterparty_point(1), None);
2539
2540        // can't skip forward
2541        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        // set point 1
2556        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        // you can still get commit_num 0
2562        assert_eq!(state.get_previous_counterparty_point(0).unwrap(), point0.clone());
2563
2564        // Now you can get commit_num 1
2565        assert_eq!(state.get_previous_counterparty_point(1).unwrap(), point1.clone());
2566
2567        // can't look forward
2568        assert_eq!(state.get_previous_counterparty_point(2), None);
2569
2570        // can't skip forward
2571        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        // set point 2
2586        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        // You can't get commit_num 0 anymore
2593        assert_eq!(state.get_previous_counterparty_point(0), None);
2594
2595        // you can still get commit_num 1
2596        assert_eq!(state.get_previous_counterparty_point(1).unwrap(), point1.clone());
2597
2598        // now you can get commit_num 2
2599        assert_eq!(state.get_previous_counterparty_point(2).unwrap(), point2.clone());
2600
2601        // can't look forward
2602        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}