1extern crate scopeguard;
2
3use core::cmp::{max, min};
4use core::fmt::{self, Debug, Formatter};
5
6use bitcoin::bip32::DerivationPath;
7use bitcoin::blockdata::block::Header as BlockHeader;
8use bitcoin::blockdata::script::ScriptBuf;
9use bitcoin::hash_types::FilterHeader;
10use bitcoin::hashes::sha256::Hash as Sha256;
11use bitcoin::hashes::Hash;
12use bitcoin::secp256k1::ecdsa::Signature;
13use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
14use bitcoin::sighash::{EcdsaSighashType, SegwitV0Sighash};
15use bitcoin::{BlockHash, Network, OutPoint, Transaction};
16use core::time::Duration;
17use lightning::ln::chan_utils::{ClosingTransaction, HTLCOutputInCommitment, TxCreationKeys};
18use lightning::sign::InMemorySigner;
19use lightning::types::payment::PaymentHash;
20use log::{debug, error};
21use serde_derive::{Deserialize, Serialize};
22use serde_with::{serde_as, Bytes, IfIsHumanReadable};
23use txoo::proof::{TxoProof, VerifyError};
24
25use crate::channel::{ChannelBalance, ChannelId, ChannelSetup, ChannelSlot};
26use crate::invoice::{Invoice, InvoiceAttributes};
27use crate::policy::{Policy, MAX_CLOCK_SKEW, MIN_INVOICE_EXPIRY};
28use crate::prelude::*;
29use crate::tx::tx::{CommitmentInfo, CommitmentInfo2, HTLCInfo2, PreimageMap};
30use crate::util::debug_utils::DebugBytes;
31use crate::wallet::Wallet;
32
33use super::error::ValidationError;
34
35pub trait Validator {
39 fn validate_setup_channel(
44 &self,
45 wallet: &dyn Wallet,
46 setup: &ChannelSetup,
47 holder_shutdown_key_path: &DerivationPath,
48 ) -> Result<(), ValidationError>;
49
50 fn validate_channel_value(&self, setup: &ChannelSetup) -> Result<(), ValidationError>;
52
53 fn validate_onchain_tx(
69 &self,
70 wallet: &dyn Wallet,
71 channels: Vec<Option<Arc<Mutex<ChannelSlot>>>>,
72 tx: &Transaction,
73 segwit_flags: &[bool],
74 values_sat: &[u64],
75 opaths: &[DerivationPath],
76 weight_lower_bound: usize,
77 ) -> Result<u64, ValidationError>;
78
79 fn decode_commitment_tx(
81 &self,
82 keys: &InMemorySigner,
83 setup: &ChannelSetup,
84 is_counterparty: bool,
85 tx: &Transaction,
86 output_witscripts: &[Vec<u8>],
87 ) -> Result<CommitmentInfo, ValidationError>;
88
89 fn validate_counterparty_commitment_tx(
91 &self,
92 estate: &EnforcementState,
93 commit_num: u64,
94 commitment_point: &PublicKey,
95 setup: &ChannelSetup,
96 cstate: &ChainState,
97 info2: &CommitmentInfo2,
98 ) -> Result<(), ValidationError>;
99
100 fn validate_holder_commitment_tx(
102 &self,
103 estate: &EnforcementState,
104 commit_num: u64,
105 commitment_point: &PublicKey,
106 setup: &ChannelSetup,
107 cstate: &ChainState,
108 info2: &CommitmentInfo2,
109 ) -> Result<(), ValidationError>;
110
111 fn validate_counterparty_revocation(
115 &self,
116 state: &EnforcementState,
117 revoke_num: u64,
118 commitment_secret: &SecretKey,
119 ) -> Result<(), ValidationError>;
120
121 fn decode_and_validate_htlc_tx(
123 &self,
124 is_counterparty: bool,
125 setup: &ChannelSetup,
126 txkeys: &TxCreationKeys,
127 tx: &Transaction,
128 redeemscript: &ScriptBuf,
129 htlc_amount_sat: u64,
130 output_witscript: &ScriptBuf,
131 ) -> Result<(u32, HTLCOutputInCommitment, SegwitV0Sighash, EcdsaSighashType), ValidationError>;
132
133 fn validate_htlc_tx(
135 &self,
136 setup: &ChannelSetup,
137 cstate: &ChainState,
138 is_counterparty: bool,
139 htlc: &HTLCOutputInCommitment,
140 feerate_per_kw: u32,
141 ) -> Result<(), ValidationError>;
142
143 fn decode_and_validate_mutual_close_tx(
145 &self,
146 wallet: &dyn Wallet,
147 setup: &ChannelSetup,
148 state: &EnforcementState,
149 tx: &Transaction,
150 opaths: &[DerivationPath],
151 ) -> Result<ClosingTransaction, ValidationError>;
152
153 fn validate_mutual_close_tx(
155 &self,
156 wallet: &dyn Wallet,
157 setup: &ChannelSetup,
158 state: &EnforcementState,
159 to_holder_value_sat: u64,
160 to_counterparty_value_sat: u64,
161 holder_shutdown_script: &Option<ScriptBuf>,
162 counterparty_shutdown_script: &Option<ScriptBuf>,
163 holder_wallet_path_hint: &DerivationPath,
164 ) -> Result<(), ValidationError>;
165
166 fn validate_delayed_sweep(
168 &self,
169 wallet: &dyn Wallet,
170 setup: &ChannelSetup,
171 cstate: &ChainState,
172 tx: &Transaction,
173 input: usize,
174 amount_sat: u64,
175 key_path: &DerivationPath,
176 ) -> Result<(), ValidationError>;
177
178 fn validate_counterparty_htlc_sweep(
181 &self,
182 wallet: &dyn Wallet,
183 setup: &ChannelSetup,
184 cstate: &ChainState,
185 tx: &Transaction,
186 redeemscript: &ScriptBuf,
187 input: usize,
188 amount_sat: u64,
189 key_path: &DerivationPath,
190 ) -> Result<(), ValidationError>;
191
192 fn validate_justice_sweep(
194 &self,
195 wallet: &dyn Wallet,
196 setup: &ChannelSetup,
197 cstate: &ChainState,
198 tx: &Transaction,
199 input: usize,
200 amount_sat: u64,
201 key_path: &DerivationPath,
202 ) -> Result<(), ValidationError>;
203
204 fn validate_payment_balance(
211 &self,
212 incoming_msat: u64,
213 outgoing_msat: u64,
214 invoiced_amount_msat: Option<u64>,
215 ) -> Result<(), ValidationError>;
216
217 fn enforce_balance(&self) -> bool {
220 false
221 }
222
223 fn minimum_initial_balance(&self, holder_value_msat: u64) -> u64;
227
228 fn is_ready(&self, cstate: &ChainState) -> bool;
230
231 fn policy(&self) -> Box<&dyn Policy>;
233
234 fn set_next_holder_commit_num(
236 &self,
237 estate: &mut EnforcementState,
238 num: u64,
239 current_commitment_info: CommitmentInfo2,
240 counterparty_signatures: CommitmentSignatures,
241 ) -> Result<(), ValidationError> {
242 let current = estate.next_holder_commit_num;
243 if num != current && num != current + 1 {
244 policy_err!(
246 self,
247 "policy-revoke-new-commitment-signed",
248 "invalid progression: {} to {}",
249 current,
250 num
251 );
252 }
253 estate.set_next_holder_commit_num(num, current_commitment_info, counterparty_signatures);
254 Ok(())
255 }
256
257 fn get_current_holder_commitment_info(
259 &self,
260 estate: &mut EnforcementState,
261 commitment_number: u64,
262 ) -> Result<CommitmentInfo2, ValidationError> {
263 if commitment_number + 1 != estate.next_holder_commit_num {
265 policy_err!(
266 self,
267 "policy-other",
268 "invalid next holder commitment number: {} != {}",
269 commitment_number + 1,
270 estate.next_holder_commit_num
271 );
272 }
273 let commitment_info = estate.current_holder_commit_info.as_ref().unwrap().clone();
275 Ok(commitment_info)
276 }
277
278 fn set_next_counterparty_commit_num(
281 &self,
282 estate: &mut EnforcementState,
283 num: u64,
284 current_point: PublicKey,
285 current_commitment_info: CommitmentInfo2,
286 ) -> Result<(), ValidationError> {
287 if num == 0 {
288 policy_err!(self, "policy-other", "can't set next to 0");
289 }
290
291 let delta = if num == 1 { 1 } else { 2 };
293
294 if num < estate.next_counterparty_revoke_num + delta {
296 policy_err!(
297 self,
298 "policy-commitment-previous-revoked",
299 "{} too small relative to next_counterparty_revoke_num {}",
300 num,
301 estate.next_counterparty_revoke_num
302 );
303 }
304
305 let current = estate.next_counterparty_commit_num;
306 if num != current && num != current + 1 {
307 policy_err!(
308 self,
309 "policy-commitment-previous-revoked",
310 "invalid progression: {} to {}",
311 current,
312 num
313 );
314 }
315
316 estate.set_next_counterparty_commit_num(num, current_point, current_commitment_info);
317 Ok(())
318 }
319
320 fn set_next_counterparty_revoke_num(
322 &self,
323 estate: &mut EnforcementState,
324 num: u64,
325 ) -> Result<(), ValidationError> {
326 if num == 0 {
327 policy_err!(self, "policy-other", "can't set next to 0");
328 }
329
330 if num + 2 < estate.next_counterparty_commit_num {
332 policy_err!(
333 self,
334 "policy-commitment-previous-revoked",
335 "{} too small relative to next_counterparty_commit_num {}",
336 num,
337 estate.next_counterparty_commit_num
338 );
339 }
340 if num + 1 > estate.next_counterparty_commit_num {
341 policy_err!(
342 self,
343 "policy-commitment-previous-revoked",
344 "{} too large relative to next_counterparty_commit_num {}",
345 num,
346 estate.next_counterparty_commit_num
347 );
348 }
349
350 let current = estate.next_counterparty_revoke_num;
351 if num != current && num != current + 1 {
352 policy_err!(
353 self,
354 "policy-commitment-previous-revoked",
355 "invalid progression: {} to {}",
356 current,
357 num
358 );
359 }
360
361 estate.set_next_counterparty_revoke_num(num);
362 debug!("next_counterparty_revoke_num {} -> {}", current, num);
363 Ok(())
364 }
365
366 fn validate_block(
368 &self,
369 proof: &TxoProof,
370 height: u32,
371 header: &BlockHeader,
372 external_block_hash: Option<&BlockHash>,
373 prev_filter_header: &FilterHeader,
374 outpoint_watches: &[OutPoint],
375 trusted_oracle_pubkeys: &Vec<PublicKey>,
376 ) -> Result<(), ValidationError> {
377 validate_block(
378 self,
379 proof,
380 height,
381 header,
382 external_block_hash,
383 prev_filter_header,
384 outpoint_watches,
385 trusted_oracle_pubkeys,
386 )
387 }
388
389 fn validate_invoice(&self, invoice: &Invoice, now: Duration) -> Result<(), ValidationError> {
391 #[cfg(not(feature = "timeless_workaround"))]
393 let (behind_tolerance, ahead_tolerance) = (Duration::from_secs(0), Duration::from_secs(0));
394 #[cfg(feature = "timeless_workaround")]
395 let (behind_tolerance, ahead_tolerance) =
396 (Duration::from_secs(1 * 60 * 60), Duration::from_secs(2 * 60 * 60));
397
398 if now + MAX_CLOCK_SKEW + behind_tolerance < invoice.duration_since_epoch() {
400 policy_err!(
401 self,
402 "policy-invoice-not-expired",
403 "invoice is not yet valid ({} + {} (skew) + {} (tolerance) < {})",
404 now.as_secs(),
405 MAX_CLOCK_SKEW.as_secs(),
406 behind_tolerance.as_secs(),
407 invoice.duration_since_epoch().as_secs()
408 );
409 }
410
411 if now + MIN_INVOICE_EXPIRY
413 > (invoice.duration_since_epoch() + invoice.expiry_duration())
414 + MAX_CLOCK_SKEW
415 + ahead_tolerance
416 {
417 policy_err!(
418 self,
419 "policy-invoice-not-expired",
420 "invoice is expired ({} + {} (buffer) > {} + {} (skew) + {} (tolerance))",
421 now.as_secs(),
422 MIN_INVOICE_EXPIRY.as_secs(),
423 (invoice.duration_since_epoch() + invoice.expiry_duration()).as_secs(),
424 MAX_CLOCK_SKEW.as_secs(),
425 ahead_tolerance.as_secs()
426 );
427 }
428
429 Ok(())
430 }
431}
432
433#[inline]
435pub fn validate_block<T: Validator + ?Sized>(
436 self_: &T,
437 proof: &TxoProof,
438 height: u32,
439 header: &BlockHeader,
440 external_block_hash: Option<&BlockHash>,
441 prev_filter_header: &FilterHeader,
442 outpoint_watches: &[OutPoint],
443 trusted_oracle_pubkeys: &Vec<PublicKey>,
444) -> Result<(), ValidationError> {
445 let secp = Secp256k1::new();
446 let result = proof.verify(
447 height,
448 header,
449 external_block_hash,
450 prev_filter_header,
451 outpoint_watches,
452 &secp,
453 );
454 match result {
455 Ok(()) => {}
456 Err(VerifyError::InvalidAttestation) => {
457 for (pubkey, attestation) in &proof.attestations {
458 error!(
459 "invalid attestation for oracle {} at height {} block hash {} - {:?}",
460 pubkey,
461 height,
462 header.block_hash(),
463 &attestation.attestation
464 );
465 }
466 policy_err!(self_, "policy-chain-validated", "invalid attestation");
467 }
468 Err(_) => {
469 policy_err!(self_, "policy-chain-validated", "invalid proof {:?}", result);
470 }
471 }
472
473 let required_majority = (trusted_oracle_pubkeys.len() + 1) / 2;
474 let key_matches = trusted_oracle_pubkeys
475 .iter()
476 .filter(|&trusted_key| {
477 proof.attestations.iter().find(|(a, _)| *a == *trusted_key).is_some()
478 })
479 .count();
480 if key_matches < required_majority {
481 policy_err!(self_, "policy-chain-validated", "attestation from trusted oracles not found");
482 }
483
484 Ok(())
485}
486
487#[derive(Debug)]
489pub struct ChainState {
490 pub current_height: u32,
492 pub funding_depth: u32,
494 pub funding_double_spent_depth: u32,
496 pub closing_depth: u32,
498}
499
500pub trait ValidatorFactory: Send + Sync {
502 fn make_validator(
504 &self,
505 network: Network,
506 node_id: PublicKey,
507 channel_id: Option<ChannelId>,
508 ) -> Arc<dyn Validator>;
509
510 fn policy(&self, network: Network) -> Box<dyn Policy>;
512}
513
514#[derive(Clone, Debug, Serialize, Deserialize)]
516pub struct CommitmentSignatures(pub Signature, pub Vec<Signature>);
517
518#[serde_as]
520#[derive(Clone, Serialize, Deserialize)]
521pub struct CounterpartyCommitmentSecrets {
522 #[serde_as(as = "IfIsHumanReadable<_, Vec<(Bytes, _)>>")]
523 old_secrets: Vec<([u8; 32], u64)>,
524}
525
526impl Debug for CounterpartyCommitmentSecrets {
527 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
528 f.debug_struct("CounterpartyCommitmentSecrets")
529 .field("old_secrets", &DebugOldSecrets(&self.old_secrets))
530 .finish()
531 }
532}
533
534struct DebugOldSecrets<'a>(pub &'a Vec<([u8; 32], u64)>);
535impl<'a> core::fmt::Debug for DebugOldSecrets<'a> {
536 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
537 f.debug_list().entries(self.0.iter().map(|os| DebugOldSecret(os))).finish()
538 }
539}
540
541struct DebugOldSecret<'a>(pub &'a ([u8; 32], u64));
542impl<'a> core::fmt::Debug for DebugOldSecret<'a> {
543 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
544 f.debug_tuple("OldSecret").field(&DebugBytes(&self.0 .0)).field(&self.0 .1).finish()
545 }
546}
547
548impl CounterpartyCommitmentSecrets {
549 pub fn new() -> Self {
551 let old_secrets = Vec::new();
552 Self { old_secrets }
553 }
554
555 #[inline]
556 fn place_secret(idx: u64) -> u8 {
557 for i in 0..48 {
558 if idx & (1 << i) == (1 << i) {
559 return i;
560 }
561 }
562 48
563 }
564
565 pub fn get_min_seen_secret(&self) -> u64 {
568 let mut min = 1 << 48;
569 for &(_, idx) in self.old_secrets.iter() {
570 if idx < min {
571 min = idx;
572 }
573 }
574 min
575 }
576
577 #[inline]
578 fn derive_secret(secret: [u8; 32], bits: u8, idx: u64) -> [u8; 32] {
579 let mut res: [u8; 32] = secret;
580 for i in 0..bits {
581 let bitpos = bits - 1 - i;
582 if idx & (1 << bitpos) == (1 << bitpos) {
583 res[(bitpos / 8) as usize] ^= 1 << (bitpos & 7);
584 res = Sha256::hash(&res).to_byte_array();
585 }
586 }
587 res
588 }
589
590 pub fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), ()> {
593 let pos = Self::place_secret(idx);
594 if pos as usize > self.old_secrets.len() {
595 return Err(());
596 }
597 for i in 0..pos {
598 let (old_secret, old_idx) = self.old_secrets[i as usize];
599 if Self::derive_secret(secret, pos, old_idx) != old_secret {
600 return Err(());
601 }
602 }
603 if self.get_min_seen_secret() <= idx {
604 return Ok(());
605 }
606 if (pos as usize) < self.old_secrets.len() {
607 self.old_secrets[pos as usize] = (secret, idx);
608 } else {
609 self.old_secrets.push((secret, idx));
610 }
611 Ok(())
612 }
613
614 pub fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
617 for i in 0..self.old_secrets.len() {
618 if (idx & (!((1 << i) - 1))) == self.old_secrets[i].1 {
619 return Some(Self::derive_secret(self.old_secrets[i].0, i as u8, idx));
620 }
621 }
622 assert!(idx < self.get_min_seen_secret());
623 None
624 }
625}
626
627#[allow(missing_docs)]
632#[derive(Clone, Debug, Serialize, Deserialize)]
633pub struct EnforcementState {
634 pub next_holder_commit_num: u64,
637 pub next_counterparty_commit_num: u64,
640 pub next_counterparty_revoke_num: u64,
643
644 pub current_counterparty_point: Option<PublicKey>, pub previous_counterparty_point: Option<PublicKey>, pub current_holder_commit_info: Option<CommitmentInfo2>,
651 pub current_counterparty_signatures: Option<CommitmentSignatures>,
653
654 pub next_holder_commit_info: Option<(CommitmentInfo2, CommitmentSignatures)>,
656
657 pub current_counterparty_commit_info: Option<CommitmentInfo2>,
659 pub previous_counterparty_commit_info: Option<CommitmentInfo2>,
661
662 pub channel_closed: bool,
663 pub initial_holder_value: u64,
664
665 pub counterparty_secrets: Option<CounterpartyCommitmentSecrets>,
668}
669
670impl EnforcementState {
671 pub fn new(initial_holder_value: u64) -> EnforcementState {
676 EnforcementState {
677 next_holder_commit_num: 0,
678 next_counterparty_commit_num: 0,
679 next_counterparty_revoke_num: 0,
680 current_counterparty_point: None,
681 previous_counterparty_point: None,
682 current_holder_commit_info: None,
683 current_counterparty_signatures: None,
684 next_holder_commit_info: None,
685 current_counterparty_commit_info: None,
686 previous_counterparty_commit_info: None,
687 channel_closed: false,
688 initial_holder_value,
689 counterparty_secrets: Some(CounterpartyCommitmentSecrets::new()),
690 }
691 }
692
693 pub fn minimum_to_holder_value(&self, epsilon_sat: u64) -> Option<u64> {
696 if let Some(hinfo) = &self.current_holder_commit_info {
697 if let Some(cinfo) = &self.current_counterparty_commit_info {
698 let hval = hinfo.to_broadcaster_value_sat;
699 let cval = cinfo.to_countersigner_value_sat;
700 debug!("min to_holder: hval={}, cval={}", hval, cval);
701 if hval > cval {
702 if hval - cval <= epsilon_sat {
703 return Some(cval);
704 }
705 } else
706 {
708 if cval - hval <= epsilon_sat {
709 return Some(hval);
710 }
711 }
712 }
713 }
714 None
715 }
716
717 pub fn minimum_to_counterparty_value(&self, epsilon_sat: u64) -> Option<u64> {
720 if let Some(hinfo) = &self.current_holder_commit_info {
721 if let Some(cinfo) = &self.current_counterparty_commit_info {
722 let hval = hinfo.to_countersigner_value_sat;
723 let cval = cinfo.to_broadcaster_value_sat;
724 debug!("min to_cparty: hval={}, cval={}", hval, cval);
725 if hval > cval {
726 if hval - cval <= epsilon_sat {
727 return Some(cval);
728 }
729 } else
730 {
732 if cval - hval <= epsilon_sat {
733 return Some(hval);
734 }
735 }
736 }
737 }
738 None
739 }
740
741 pub fn set_next_holder_commit_num(
744 &mut self,
745 num: u64,
746 current_commitment_info: CommitmentInfo2,
747 counterparty_signatures: CommitmentSignatures,
748 ) {
749 let current = self.next_holder_commit_num;
750 assert_eq!(num, current + 1);
751 debug!("next_holder_commit_num {} -> {}", current, num);
753 self.next_holder_commit_num = num;
754 self.current_holder_commit_info = Some(current_commitment_info);
755 self.current_counterparty_signatures = Some(counterparty_signatures);
756 }
757
758 pub fn set_next_counterparty_commit_num(
760 &mut self,
761 num: u64,
762 current_point: PublicKey,
763 current_commitment_info: CommitmentInfo2,
764 ) {
765 assert!(num > 0);
766 let current = self.next_counterparty_commit_num;
767
768 if num == current + 1 {
769 self.previous_counterparty_point = self.current_counterparty_point;
771 self.previous_counterparty_commit_info = self.current_counterparty_commit_info.take();
772 } else if num > current + 1 || num < current {
773 self.previous_counterparty_point = None;
775 self.previous_counterparty_commit_info = None;
776 }
777
778 if num >= current + 1 {
779 self.current_counterparty_point = Some(current_point);
781 self.current_counterparty_commit_info = Some(current_commitment_info);
782 }
783
784 self.next_counterparty_commit_num = num;
785 debug!("next_counterparty_commit_num {} -> {} current {}", current, num, current_point);
786 }
787
788 pub fn get_previous_counterparty_point(&self, num: u64) -> Option<PublicKey> {
790 if num + 1 == self.next_counterparty_commit_num {
791 self.current_counterparty_point
792 } else if num + 2 == self.next_counterparty_commit_num {
793 self.previous_counterparty_point
794 } else {
795 None
796 }
797 }
798
799 pub fn get_previous_counterparty_commit_info(&self, num: u64) -> Option<CommitmentInfo2> {
801 if num + 1 == self.next_counterparty_commit_num {
802 self.current_counterparty_commit_info.clone()
803 } else if num + 2 == self.next_counterparty_commit_num {
804 self.previous_counterparty_commit_info.clone()
805 } else {
806 None
807 }
808 }
809
810 pub fn set_next_counterparty_revoke_num(&mut self, num: u64) {
812 assert_ne!(num, 0);
813 let current = self.next_counterparty_revoke_num;
814
815 if num + 1 >= self.next_counterparty_commit_num {
817 self.previous_counterparty_commit_info = None;
819 }
820
821 self.next_counterparty_revoke_num = num;
822 debug!("next_counterparty_revoke_num {} -> {}", current, num);
823 }
824
825 #[allow(missing_docs)]
826 #[cfg(any(test, feature = "test_utils"))]
827 pub fn set_next_holder_commit_num_for_testing(&mut self, num: u64) {
828 debug!(
829 "set_next_holder_commit_num_for_testing: {} -> {}",
830 self.next_holder_commit_num, num
831 );
832 self.next_holder_commit_num = num;
833 }
834
835 #[allow(missing_docs)]
836 #[cfg(any(test, feature = "test_utils"))]
837 pub fn set_next_counterparty_commit_num_for_testing(
838 &mut self,
839 num: u64,
840 current_point: PublicKey,
841 ) {
842 debug!(
843 "set_next_counterparty_commit_num_for_testing: {} -> {}",
844 self.next_counterparty_commit_num, num
845 );
846 self.previous_counterparty_point = self.current_counterparty_point;
847 self.current_counterparty_point = Some(current_point);
848 self.next_counterparty_commit_num = num;
849 }
850
851 #[allow(missing_docs)]
852 #[cfg(any(test, feature = "test_utils"))]
853 pub fn set_next_counterparty_revoke_num_for_testing(&mut self, num: u64) {
854 debug!(
855 "set_next_counterparty_revoke_num_for_testing: {} -> {}",
856 self.next_counterparty_revoke_num, num
857 );
858 self.next_counterparty_revoke_num = num;
859 }
860
861 pub fn payments_summary(
868 &self,
869 new_holder_tx: Option<&CommitmentInfo2>,
870 new_counterparty_tx: Option<&CommitmentInfo2>,
871 ) -> Map<PaymentHash, u64> {
872 let holder_offered =
873 new_holder_tx.or(self.current_holder_commit_info.as_ref()).map(|h| &h.offered_htlcs);
874 let counterparty_received = new_counterparty_tx
875 .or(self.current_counterparty_commit_info.as_ref())
876 .map(|c| &c.received_htlcs);
877 let holder_summary =
878 holder_offered.map(|h| Self::summarize_payments(h)).unwrap_or_else(|| Map::new());
879 let counterparty_summary = counterparty_received
880 .map(|h| Self::summarize_payments(h))
881 .unwrap_or_else(|| Map::new());
882 let mut summary = holder_summary;
884 for (k, v) in counterparty_summary {
885 summary.entry(k).and_modify(|e| *e = max(*e, v)).or_insert(v);
887 }
888
889 if let Some(holder_tx) = self.current_holder_commit_info.as_ref() {
890 for h in holder_tx.offered_htlcs.iter() {
891 summary.entry(h.payment_hash).or_insert(0);
892 }
893 }
894
895 if let Some(counterparty_tx) = self.current_counterparty_commit_info.as_ref() {
896 for h in counterparty_tx.received_htlcs.iter() {
897 summary.entry(h.payment_hash).or_insert(0);
898 }
899 }
900 summary
901 }
902
903 pub fn incoming_payments_summary(
913 &self,
914 new_holder_tx: Option<&CommitmentInfo2>,
915 new_counterparty_tx: Option<&CommitmentInfo2>,
916 ) -> Map<PaymentHash, u64> {
917 let holder_received =
918 new_holder_tx.or(self.current_holder_commit_info.as_ref()).map(|h| &h.received_htlcs);
919 let counterparty_offered = new_counterparty_tx
920 .or(self.current_counterparty_commit_info.as_ref())
921 .map(|c| &c.offered_htlcs);
922 let holder_summary =
923 holder_received.map(|h| Self::summarize_payments(h)).unwrap_or_else(|| Map::new());
924 let counterparty_summary =
925 counterparty_offered.map(|h| Self::summarize_payments(h)).unwrap_or_else(|| Map::new());
926 let mut summary = holder_summary;
929 summary.retain(|k, _| counterparty_summary.contains_key(k));
930 for (k, v) in counterparty_summary {
931 summary.entry(k).and_modify(|e| *e = min(*e, v));
933 }
934
935 if let Some(holder_tx) = self.current_holder_commit_info.as_ref() {
936 for h in holder_tx.received_htlcs.iter() {
937 summary.entry(h.payment_hash).or_insert(0);
938 }
939 }
940
941 if let Some(counterparty_tx) = self.current_counterparty_commit_info.as_ref() {
942 for h in counterparty_tx.offered_htlcs.iter() {
943 summary.entry(h.payment_hash).or_insert(0);
944 }
945 }
946 summary
947 }
948
949 fn summarize_payments(htlcs: &[HTLCInfo2]) -> Map<PaymentHash, u64> {
950 let mut summary = Map::new();
951 for h in htlcs {
952 summary.entry(h.payment_hash).and_modify(|e| *e += h.value_sat).or_insert(h.value_sat);
954 }
955 summary
956 }
957
958 pub fn claimable_balances<T: PreimageMap>(
962 &self,
963 preimage_map: &T,
964 new_holder_tx: Option<&CommitmentInfo2>,
965 new_counterparty_tx: Option<&CommitmentInfo2>,
966 channel_setup: &ChannelSetup,
967 ) -> BalanceDelta {
968 assert!(
969 new_holder_tx.is_some() || new_counterparty_tx.is_some(),
970 "must have at least one new tx"
971 );
972 assert!(
973 new_holder_tx.is_none() || new_counterparty_tx.is_none(),
974 "must have at most one new tx"
975 );
976 let cur_holder_bal = self.current_holder_commit_info.as_ref().map(|tx| {
978 tx.claimable_balance(
979 preimage_map,
980 channel_setup.is_outbound,
981 channel_setup.channel_value_sat,
982 )
983 });
984 let cur_cp_bal = self.current_counterparty_commit_info.as_ref().map(|tx| {
986 tx.claimable_balance(
987 preimage_map,
988 channel_setup.is_outbound,
989 channel_setup.channel_value_sat,
990 )
991 });
992 let cur_bal_opt = min_opt(cur_holder_bal, cur_cp_bal);
994
995 let new_holder_bal = new_holder_tx.or(self.current_holder_commit_info.as_ref()).map(|tx| {
997 tx.claimable_balance(
998 preimage_map,
999 channel_setup.is_outbound,
1000 channel_setup.channel_value_sat,
1001 )
1002 });
1003 let new_cp_bal =
1004 new_counterparty_tx.or(self.current_counterparty_commit_info.as_ref()).map(|tx| {
1005 tx.claimable_balance(
1006 preimage_map,
1007 channel_setup.is_outbound,
1008 channel_setup.channel_value_sat,
1009 )
1010 });
1011 let new_bal =
1012 min_opt(new_holder_bal, new_cp_bal).expect("already checked that we have a new tx");
1013
1014 let cur_bal = cur_bal_opt.unwrap_or_else(|| self.initial_holder_value);
1017
1018 debug!(
1019 "balance {} -> {} --- cur h {} c {} new h {} c {}",
1020 cur_bal,
1021 new_bal,
1022 self.current_holder_commit_info.is_some(),
1023 self.current_counterparty_commit_info.is_some(),
1024 new_holder_tx.is_some(),
1025 new_counterparty_tx.is_some()
1026 );
1027
1028 BalanceDelta(cur_bal, new_bal)
1029 }
1030
1031 pub fn balance<T: PreimageMap + core::fmt::Debug>(
1033 &self,
1034 preimage_map: &T,
1035 channel_setup: &ChannelSetup,
1036 is_ready: bool,
1037 ) -> ChannelBalance {
1038 #[cfg(not(feature = "log_pretty_print"))]
1039 debug!("{:?}", preimage_map);
1040 #[cfg(feature = "log_pretty_print")]
1041 debug!("{:#?}", preimage_map);
1042
1043 if self.current_holder_commit_info.is_none()
1045 || self.current_counterparty_commit_info.is_none()
1046 {
1047 return ChannelBalance::zero();
1048 }
1049
1050 let holder_info = self.current_holder_commit_info.as_ref().unwrap();
1051 let counterparty_info = self.current_counterparty_commit_info.as_ref().unwrap();
1052
1053 let cur_holder_bal = holder_info.claimable_balance(
1055 preimage_map,
1056 channel_setup.is_outbound,
1057 channel_setup.channel_value_sat,
1058 );
1059 let cur_cp_bal = counterparty_info.claimable_balance(
1061 preimage_map,
1062 channel_setup.is_outbound,
1063 channel_setup.channel_value_sat,
1064 );
1065 let (cur_bal, received_htlc, offered_htlc, received_htlc_count, offered_htlc_count) =
1071 if cur_holder_bal < cur_cp_bal {
1072 let (received_htlc, offered_htlc, received_count, offered_count) =
1073 holder_info.htlc_balance();
1074 (cur_holder_bal, received_htlc, offered_htlc, received_count, offered_count)
1075 } else {
1076 let (received_htlc, offered_htlc, received_count, offered_count) =
1077 counterparty_info.htlc_balance();
1078 (cur_cp_bal, received_htlc, offered_htlc, received_count, offered_count)
1079 };
1080
1081 let (claimable, sweeping) = if self.channel_closed { (0, cur_bal) } else { (cur_bal, 0) };
1082 let (stub_count, unconfirmed_count, channel_count, closing_count) = if self.channel_closed {
1083 (0, 0, 0, 1)
1084 } else if is_ready {
1085 (0, 0, 1, 0)
1086 } else {
1087 (0, 1, 0, 0)
1088 };
1089 let balance = ChannelBalance {
1090 claimable,
1091 received_htlc,
1092 offered_htlc,
1093 sweeping,
1094 stub_count,
1095 unconfirmed_count,
1096 channel_count,
1097 closing_count,
1098 received_htlc_count,
1099 offered_htlc_count,
1100 };
1101 balance
1102 }
1103}
1104
1105pub struct BalanceDelta(pub u64, pub u64);
1107
1108impl Default for BalanceDelta {
1109 fn default() -> Self {
1110 BalanceDelta(0, 0)
1111 }
1112}
1113
1114fn min_opt(a_opt: Option<u64>, b_opt: Option<u64>) -> Option<u64> {
1116 if let Some(a) = a_opt {
1117 if let Some(b) = b_opt {
1118 Some(a.min(b))
1119 } else {
1120 a_opt
1121 }
1122 } else {
1123 b_opt
1124 }
1125}
1126
1127#[cfg(test)]
1128mod tests {
1129 use super::*;
1130 use crate::tx::tx::{CommitmentInfo2, HTLCInfo2};
1131 use lightning::types::payment::PaymentHash;
1132
1133 #[test]
1134 fn test_per_commitment_storage() {
1135 let mut monitor = CounterpartyCommitmentSecrets::new();
1137 let secret: [u8; 32] =
1138 hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc")
1139 .unwrap()
1140 .try_into()
1141 .unwrap();
1142 assert!(monitor.provide_secret(281474976710654, secret).is_err());
1143
1144 let mut secrets: Vec<[u8; 32]> = Vec::new();
1146 let mut monitor;
1147
1148 macro_rules! test_secrets {
1149 () => {
1150 let mut idx = 281474976710655;
1151 for secret in secrets.iter() {
1152 assert_eq!(monitor.get_secret(idx).unwrap(), *secret);
1153 idx -= 1;
1154 }
1155 assert_eq!(monitor.get_min_seen_secret(), idx + 1);
1156 assert!(monitor.get_secret(idx).is_none());
1157 };
1158 }
1159
1160 {
1161 monitor = CounterpartyCommitmentSecrets::new();
1163 secrets.clear();
1164
1165 secrets.push([0; 32]);
1166 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1167 &hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc")
1168 .unwrap(),
1169 );
1170 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1171 test_secrets!();
1172
1173 secrets.push([0; 32]);
1174 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1175 &hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964")
1176 .unwrap(),
1177 );
1178 monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
1179 test_secrets!();
1180
1181 secrets.push([0; 32]);
1182 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1183 &hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8")
1184 .unwrap(),
1185 );
1186 monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
1187 test_secrets!();
1188
1189 secrets.push([0; 32]);
1190 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1191 &hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116")
1192 .unwrap(),
1193 );
1194 monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
1195 test_secrets!();
1196
1197 secrets.push([0; 32]);
1198 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1199 &hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd")
1200 .unwrap(),
1201 );
1202 monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
1203 test_secrets!();
1204
1205 secrets.push([0; 32]);
1206 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1207 &hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2")
1208 .unwrap(),
1209 );
1210 monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
1211 test_secrets!();
1212
1213 secrets.push([0; 32]);
1214 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1215 &hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32")
1216 .unwrap(),
1217 );
1218 monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
1219 test_secrets!();
1220
1221 secrets.push([0; 32]);
1222 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1223 &hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17")
1224 .unwrap(),
1225 );
1226 monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap();
1227 test_secrets!();
1228 }
1229
1230 {
1231 monitor = CounterpartyCommitmentSecrets::new();
1233 secrets.clear();
1234
1235 secrets.push([0; 32]);
1236 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1237 &hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148")
1238 .unwrap(),
1239 );
1240 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1241 test_secrets!();
1242
1243 secrets.push([0; 32]);
1244 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1245 &hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964")
1246 .unwrap(),
1247 );
1248 assert!(monitor
1249 .provide_secret(281474976710654, secrets.last().unwrap().clone())
1250 .is_err());
1251 }
1252
1253 {
1254 monitor = CounterpartyCommitmentSecrets::new();
1256 secrets.clear();
1257
1258 secrets.push([0; 32]);
1259 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1260 &hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148")
1261 .unwrap(),
1262 );
1263 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1264 test_secrets!();
1265
1266 secrets.push([0; 32]);
1267 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1268 &hex::decode("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3")
1269 .unwrap(),
1270 );
1271 monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
1272 test_secrets!();
1273
1274 secrets.push([0; 32]);
1275 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1276 &hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8")
1277 .unwrap(),
1278 );
1279 monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
1280 test_secrets!();
1281
1282 secrets.push([0; 32]);
1283 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1284 &hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116")
1285 .unwrap(),
1286 );
1287 assert!(monitor
1288 .provide_secret(281474976710652, secrets.last().unwrap().clone())
1289 .is_err());
1290 }
1291
1292 {
1293 monitor = CounterpartyCommitmentSecrets::new();
1295 secrets.clear();
1296
1297 secrets.push([0; 32]);
1298 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1299 &hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc")
1300 .unwrap(),
1301 );
1302 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1303 test_secrets!();
1304
1305 secrets.push([0; 32]);
1306 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1307 &hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964")
1308 .unwrap(),
1309 );
1310 monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
1311 test_secrets!();
1312
1313 secrets.push([0; 32]);
1314 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1315 &hex::decode("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a")
1316 .unwrap(),
1317 );
1318 monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
1319 test_secrets!();
1320
1321 secrets.push([0; 32]);
1322 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1323 &hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116")
1324 .unwrap(),
1325 );
1326 assert!(monitor
1327 .provide_secret(281474976710652, secrets.last().unwrap().clone())
1328 .is_err());
1329 }
1330
1331 {
1332 monitor = CounterpartyCommitmentSecrets::new();
1334 secrets.clear();
1335
1336 secrets.push([0; 32]);
1337 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1338 &hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148")
1339 .unwrap(),
1340 );
1341 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1342 test_secrets!();
1343
1344 secrets.push([0; 32]);
1345 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1346 &hex::decode("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3")
1347 .unwrap(),
1348 );
1349 monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
1350 test_secrets!();
1351
1352 secrets.push([0; 32]);
1353 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1354 &hex::decode("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a")
1355 .unwrap(),
1356 );
1357 monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
1358 test_secrets!();
1359
1360 secrets.push([0; 32]);
1361 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1362 &hex::decode("ba65d7b0ef55a3ba300d4e87af29868f394f8f138d78a7011669c79b37b936f4")
1363 .unwrap(),
1364 );
1365 monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
1366 test_secrets!();
1367
1368 secrets.push([0; 32]);
1369 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1370 &hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd")
1371 .unwrap(),
1372 );
1373 monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
1374 test_secrets!();
1375
1376 secrets.push([0; 32]);
1377 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1378 &hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2")
1379 .unwrap(),
1380 );
1381 monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
1382 test_secrets!();
1383
1384 secrets.push([0; 32]);
1385 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1386 &hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32")
1387 .unwrap(),
1388 );
1389 monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
1390 test_secrets!();
1391
1392 secrets.push([0; 32]);
1393 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1394 &hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17")
1395 .unwrap(),
1396 );
1397 assert!(monitor
1398 .provide_secret(281474976710648, secrets.last().unwrap().clone())
1399 .is_err());
1400 }
1401
1402 {
1403 monitor = CounterpartyCommitmentSecrets::new();
1405 secrets.clear();
1406
1407 secrets.push([0; 32]);
1408 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1409 &hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc")
1410 .unwrap(),
1411 );
1412 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1413 test_secrets!();
1414
1415 secrets.push([0; 32]);
1416 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1417 &hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964")
1418 .unwrap(),
1419 );
1420 monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
1421 test_secrets!();
1422
1423 secrets.push([0; 32]);
1424 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1425 &hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8")
1426 .unwrap(),
1427 );
1428 monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
1429 test_secrets!();
1430
1431 secrets.push([0; 32]);
1432 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1433 &hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116")
1434 .unwrap(),
1435 );
1436 monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
1437 test_secrets!();
1438
1439 secrets.push([0; 32]);
1440 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1441 &hex::decode("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6")
1442 .unwrap(),
1443 );
1444 monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
1445 test_secrets!();
1446
1447 secrets.push([0; 32]);
1448 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1449 &hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2")
1450 .unwrap(),
1451 );
1452 assert!(monitor
1453 .provide_secret(281474976710650, secrets.last().unwrap().clone())
1454 .is_err());
1455 }
1456
1457 {
1458 monitor = CounterpartyCommitmentSecrets::new();
1460 secrets.clear();
1461
1462 secrets.push([0; 32]);
1463 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1464 &hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc")
1465 .unwrap(),
1466 );
1467 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1468 test_secrets!();
1469
1470 secrets.push([0; 32]);
1471 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1472 &hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964")
1473 .unwrap(),
1474 );
1475 monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
1476 test_secrets!();
1477
1478 secrets.push([0; 32]);
1479 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1480 &hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8")
1481 .unwrap(),
1482 );
1483 monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
1484 test_secrets!();
1485
1486 secrets.push([0; 32]);
1487 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1488 &hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116")
1489 .unwrap(),
1490 );
1491 monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
1492 test_secrets!();
1493
1494 secrets.push([0; 32]);
1495 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1496 &hex::decode("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6")
1497 .unwrap(),
1498 );
1499 monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
1500 test_secrets!();
1501
1502 secrets.push([0; 32]);
1503 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1504 &hex::decode("b7e76a83668bde38b373970155c868a653304308f9896692f904a23731224bb1")
1505 .unwrap(),
1506 );
1507 monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
1508 test_secrets!();
1509
1510 secrets.push([0; 32]);
1511 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1512 &hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32")
1513 .unwrap(),
1514 );
1515 monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
1516 test_secrets!();
1517
1518 secrets.push([0; 32]);
1519 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1520 &hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17")
1521 .unwrap(),
1522 );
1523 assert!(monitor
1524 .provide_secret(281474976710648, secrets.last().unwrap().clone())
1525 .is_err());
1526 }
1527
1528 {
1529 monitor = CounterpartyCommitmentSecrets::new();
1531 secrets.clear();
1532
1533 secrets.push([0; 32]);
1534 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1535 &hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc")
1536 .unwrap(),
1537 );
1538 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1539 test_secrets!();
1540
1541 secrets.push([0; 32]);
1542 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1543 &hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964")
1544 .unwrap(),
1545 );
1546 monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
1547 test_secrets!();
1548
1549 secrets.push([0; 32]);
1550 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1551 &hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8")
1552 .unwrap(),
1553 );
1554 monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
1555 test_secrets!();
1556
1557 secrets.push([0; 32]);
1558 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1559 &hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116")
1560 .unwrap(),
1561 );
1562 monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
1563 test_secrets!();
1564
1565 secrets.push([0; 32]);
1566 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1567 &hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd")
1568 .unwrap(),
1569 );
1570 monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
1571 test_secrets!();
1572
1573 secrets.push([0; 32]);
1574 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1575 &hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2")
1576 .unwrap(),
1577 );
1578 monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
1579 test_secrets!();
1580
1581 secrets.push([0; 32]);
1582 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1583 &hex::decode("e7971de736e01da8ed58b94c2fc216cb1dca9e326f3a96e7194fe8ea8af6c0a3")
1584 .unwrap(),
1585 );
1586 monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
1587 test_secrets!();
1588
1589 secrets.push([0; 32]);
1590 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1591 &hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17")
1592 .unwrap(),
1593 );
1594 assert!(monitor
1595 .provide_secret(281474976710648, secrets.last().unwrap().clone())
1596 .is_err());
1597 }
1598
1599 {
1600 monitor = CounterpartyCommitmentSecrets::new();
1602 secrets.clear();
1603
1604 secrets.push([0; 32]);
1605 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1606 &hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc")
1607 .unwrap(),
1608 );
1609 monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
1610 test_secrets!();
1611
1612 secrets.push([0; 32]);
1613 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1614 &hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964")
1615 .unwrap(),
1616 );
1617 monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
1618 test_secrets!();
1619
1620 secrets.push([0; 32]);
1621 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1622 &hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8")
1623 .unwrap(),
1624 );
1625 monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
1626 test_secrets!();
1627
1628 secrets.push([0; 32]);
1629 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1630 &hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116")
1631 .unwrap(),
1632 );
1633 monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
1634 test_secrets!();
1635
1636 secrets.push([0; 32]);
1637 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1638 &hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd")
1639 .unwrap(),
1640 );
1641 monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
1642 test_secrets!();
1643
1644 secrets.push([0; 32]);
1645 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1646 &hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2")
1647 .unwrap(),
1648 );
1649 monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
1650 test_secrets!();
1651
1652 secrets.push([0; 32]);
1653 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1654 &hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32")
1655 .unwrap(),
1656 );
1657 monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
1658 test_secrets!();
1659
1660 secrets.push([0; 32]);
1661 secrets.last_mut().unwrap()[0..32].clone_from_slice(
1662 &hex::decode("a7efbc61aac46d34f77778bac22c8a20c6a46ca460addc49009bda875ec88fa4")
1663 .unwrap(),
1664 );
1665 assert!(monitor
1666 .provide_secret(281474976710648, secrets.last().unwrap().clone())
1667 .is_err());
1668 }
1669 }
1670
1671 #[test]
1672 fn payments_summary_test() {
1673 let mut state = EnforcementState::new(1000000);
1674
1675 let payment_hash = PaymentHash([3; 32]);
1677 let htlcs = vec![HTLCInfo2 { value_sat: 1000, payment_hash, cltv_expiry: 100 }];
1678
1679 let cp_tx = make_tx(true, htlcs);
1680
1681 assert!(state.payments_summary(None, None).is_empty());
1683
1684 let sum = state.payments_summary(None, Some(&cp_tx));
1686 assert_eq!(sum.get(&payment_hash), Some(&1000));
1687
1688 state.current_counterparty_commit_info = Some(cp_tx);
1690 let sum = state.payments_summary(None, None);
1691 assert_eq!(sum.get(&payment_hash), Some(&1000));
1692
1693 let cp_tx2 = make_tx(true, vec![]);
1695 let sum = state.payments_summary(None, Some(&cp_tx2));
1696 assert_eq!(sum.get(&payment_hash), Some(&0));
1697
1698 state.current_counterparty_commit_info = Some(cp_tx2);
1699 let sum = state.payments_summary(None, None);
1700 assert_eq!(sum.get(&payment_hash), None);
1701
1702 let payment_hash = PaymentHash([4; 32]);
1704 let htlcs = vec![HTLCInfo2 { value_sat: 1000, payment_hash, cltv_expiry: 100 }];
1705 let holder_tx = make_tx(false, htlcs);
1706
1707 assert!(state.payments_summary(None, None).is_empty());
1709
1710 let sum = state.payments_summary(Some(&holder_tx), None);
1712 assert_eq!(sum.get(&payment_hash), Some(&1000));
1713
1714 state.current_holder_commit_info = Some(holder_tx);
1716 let sum = state.payments_summary(None, None);
1717 assert_eq!(sum.get(&payment_hash), Some(&1000));
1718
1719 let holder_tx2 = make_tx(false, vec![]);
1721 let sum = state.payments_summary(Some(&holder_tx2), None);
1722 assert_eq!(sum.get(&payment_hash), Some(&0));
1723
1724 state.current_holder_commit_info = Some(holder_tx2);
1725 let sum = state.payments_summary(None, None);
1726 assert_eq!(sum.get(&payment_hash), None);
1727 }
1728
1729 #[test]
1730 fn incoming_payments_summary_test() {
1731 let mut state = EnforcementState::new(1000000);
1732
1733 let payment_hash = PaymentHash([3; 32]);
1734 let htlcs = vec![HTLCInfo2 { value_sat: 1000, payment_hash, cltv_expiry: 100 }];
1735
1736 let cp_tx = make_tx(false, htlcs.clone());
1737 let holder_tx = make_tx(true, htlcs.clone());
1738
1739 assert!(state.incoming_payments_summary(None, None).is_empty());
1741
1742 assert!(state.incoming_payments_summary(Some(&holder_tx), None).is_empty());
1744 assert!(state.incoming_payments_summary(None, Some(&cp_tx)).is_empty());
1745
1746 let sum = state.incoming_payments_summary(Some(&holder_tx), Some(&cp_tx));
1748 assert_eq!(sum.get(&payment_hash), Some(&1000));
1749
1750 state.current_counterparty_commit_info = Some(cp_tx);
1752 state.current_holder_commit_info = Some(holder_tx);
1753 let sum = state.incoming_payments_summary(None, None);
1754 assert_eq!(sum.get(&payment_hash), Some(&1000));
1755
1756 let holder_tx2 = make_tx(true, vec![]);
1758 let cp_tx2 = make_tx(false, vec![]);
1759
1760 let sum = state.incoming_payments_summary(None, Some(&cp_tx2));
1761 assert_eq!(sum.get(&payment_hash), Some(&0));
1762
1763 let sum = state.incoming_payments_summary(Some(&holder_tx2), None);
1764 assert_eq!(sum.get(&payment_hash), Some(&0));
1765 }
1766
1767 fn make_tx(is_received: bool, htlcs: Vec<HTLCInfo2>) -> CommitmentInfo2 {
1768 CommitmentInfo2::new(
1769 is_received,
1770 9000,
1771 10000,
1772 if is_received { vec![] } else { htlcs.clone() },
1773 if is_received { htlcs.clone() } else { vec![] },
1774 1000,
1775 )
1776 }
1777}