@@ -643,6 +643,21 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
643643 } ,
644644) ;
645645
646+ /// Information about an HTLC forward that was claimed via preimage on the outbound edge, included
647+ /// in [`ChannelMonitorUpdateStep`] so the monitor can generate events with the full claim context.
648+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
649+ pub ( crate ) struct OutboundHTLCClaim {
650+ pub htlc_id : SentHTLCId ,
651+ pub preimage : PaymentPreimage ,
652+ pub skimmed_fee_msat : Option < u64 > ,
653+ }
654+
655+ impl_writeable_tlv_based ! ( OutboundHTLCClaim , {
656+ ( 1 , htlc_id, required) ,
657+ ( 3 , preimage, required) ,
658+ ( 5 , skimmed_fee_msat, option) ,
659+ } ) ;
660+
646661#[ derive( Clone , Debug , PartialEq , Eq ) ]
647662pub ( crate ) enum ChannelMonitorUpdateStep {
648663 LatestHolderCommitmentTXInfo {
@@ -654,13 +669,13 @@ pub(crate) enum ChannelMonitorUpdateStep {
654669 /// `htlc_outputs` will only include dust HTLCs. We still have to track the
655670 /// `Option<Signature>` for backwards compatibility.
656671 htlc_outputs : Vec < ( HTLCOutputInCommitment , Option < Signature > , Option < HTLCSource > ) > ,
657- claimed_htlcs : Vec < ( SentHTLCId , PaymentPreimage ) > ,
672+ claimed_htlcs : Vec < OutboundHTLCClaim > ,
658673 nondust_htlc_sources : Vec < HTLCSource > ,
659674 } ,
660675 LatestHolderCommitment {
661676 commitment_txs : Vec < HolderCommitmentTransaction > ,
662677 htlc_data : CommitmentHTLCData ,
663- claimed_htlcs : Vec < ( SentHTLCId , PaymentPreimage ) > ,
678+ claimed_htlcs : Vec < OutboundHTLCClaim > ,
664679 } ,
665680 LatestCounterpartyCommitmentTXInfo {
666681 commitment_txid : Txid ,
@@ -742,9 +757,29 @@ impl ChannelMonitorUpdateStep {
742757impl_writeable_tlv_based_enum_upgradable ! ( ChannelMonitorUpdateStep ,
743758 ( 0 , LatestHolderCommitmentTXInfo ) => {
744759 ( 0 , commitment_tx, required) ,
745- ( 1 , claimed_htlcs, optional_vec) ,
760+ ( 1 , _legacy_claimed_htlcs, ( legacy, Vec <( SentHTLCId , PaymentPreimage ) >,
761+ |v: Option <& Vec <( SentHTLCId , PaymentPreimage ) >>| {
762+ // Only populate from legacy if the new-format tag 5 wasn't read.
763+ if let Some ( legacy) = v {
764+ if claimed_htlcs. as_ref( ) . map_or( true , |v| v. is_empty( ) ) {
765+ claimed_htlcs = Some ( legacy. iter( ) . map( |( htlc_id, preimage) | OutboundHTLCClaim {
766+ htlc_id: * htlc_id, preimage: * preimage, skimmed_fee_msat: None ,
767+ } ) . collect( ) ) ;
768+ }
769+ }
770+ Ok ( ( ) )
771+ } ,
772+ |us: & ChannelMonitorUpdateStep | match us {
773+ ChannelMonitorUpdateStep :: LatestHolderCommitmentTXInfo { claimed_htlcs, .. } => {
774+ let claims: Vec <( SentHTLCId , PaymentPreimage ) > =
775+ claimed_htlcs. iter( ) . map( |claim| ( claim. htlc_id, claim. preimage) ) . collect( ) ;
776+ Some ( claims)
777+ }
778+ _ => None
779+ } ) ) ,
746780 ( 2 , htlc_outputs, required_vec) ,
747781 ( 4 , nondust_htlc_sources, optional_vec) ,
782+ ( 5 , claimed_htlcs, optional_vec) , // Added in 0.4
748783 } ,
749784 ( 1 , LatestCounterpartyCommitmentTXInfo ) => {
750785 ( 0 , commitment_txid, required) ,
@@ -779,7 +814,27 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
779814 ( 8 , LatestHolderCommitment ) => {
780815 ( 1 , commitment_txs, required_vec) ,
781816 ( 3 , htlc_data, required) ,
782- ( 5 , claimed_htlcs, required_vec) ,
817+ ( 5 , _legacy_claimed_htlcs, ( legacy, Vec <( SentHTLCId , PaymentPreimage ) >,
818+ |v: Option <& Vec <( SentHTLCId , PaymentPreimage ) >>| {
819+ // Only populate from legacy if the new-format tag 7 wasn't read.
820+ if let Some ( legacy) = v {
821+ if claimed_htlcs. as_ref( ) . map_or( true , |v| v. is_empty( ) ) {
822+ claimed_htlcs = Some ( legacy. iter( ) . map( |( htlc_id, preimage) | OutboundHTLCClaim {
823+ htlc_id: * htlc_id, preimage: * preimage, skimmed_fee_msat: None ,
824+ } ) . collect( ) ) ;
825+ }
826+ }
827+ Ok ( ( ) )
828+ } ,
829+ |us: & ChannelMonitorUpdateStep | match us {
830+ ChannelMonitorUpdateStep :: LatestHolderCommitment { claimed_htlcs, .. } => {
831+ let claims: Vec <( SentHTLCId , PaymentPreimage ) > =
832+ claimed_htlcs. iter( ) . map( |claim| ( claim. htlc_id, claim. preimage) ) . collect( ) ;
833+ Some ( claims)
834+ }
835+ _ => None
836+ } ) ) ,
837+ ( 7 , claimed_htlcs, optional_vec) , // Added in 0.4
783838 } ,
784839 ( 10 , RenegotiatedFunding ) => {
785840 ( 1 , channel_parameters, ( required: ReadableArgs , None ) ) ,
@@ -3719,7 +3774,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
37193774 fn provide_latest_holder_commitment_tx (
37203775 & mut self , holder_commitment_tx : HolderCommitmentTransaction ,
37213776 htlc_outputs : & [ ( HTLCOutputInCommitment , Option < Signature > , Option < HTLCSource > ) ] ,
3722- claimed_htlcs : & [ ( SentHTLCId , PaymentPreimage ) ] , mut nondust_htlc_sources : Vec < HTLCSource > ,
3777+ claimed_htlcs : & [ OutboundHTLCClaim ] , mut nondust_htlc_sources : Vec < HTLCSource > ,
37233778 ) -> Result < ( ) , & ' static str > {
37243779 let dust_htlcs = if htlc_outputs. iter ( ) . any ( |( _, s, _) | s. is_some ( ) ) {
37253780 // If we have non-dust HTLCs in htlc_outputs, ensure they match the HTLCs in the
@@ -3840,7 +3895,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38403895
38413896 fn update_holder_commitment_data (
38423897 & mut self , commitment_txs : Vec < HolderCommitmentTransaction > ,
3843- mut htlc_data : CommitmentHTLCData , claimed_htlcs : & [ ( SentHTLCId , PaymentPreimage ) ] ,
3898+ mut htlc_data : CommitmentHTLCData , claimed_htlcs : & [ OutboundHTLCClaim ] ,
38443899 ) -> Result < ( ) , & ' static str > {
38453900 self . verify_matching_commitment_transactions (
38463901 commitment_txs. iter ( ) . map ( |holder_commitment_tx| holder_commitment_tx. deref ( ) ) ,
@@ -3860,7 +3915,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38603915 mem:: swap ( & mut htlc_data, & mut self . current_holder_htlc_data ) ;
38613916 self . prev_holder_htlc_data = Some ( htlc_data) ;
38623917
3863- for ( claimed_htlc_id , claimed_preimage ) in claimed_htlcs {
3918+ for claim in claimed_htlcs {
38643919 let htlc_opt = self
38653920 . funding
38663921 . counterparty_claimable_outpoints
@@ -3869,7 +3924,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38693924 . iter ( )
38703925 . find_map ( |( htlc, source_opt) | {
38713926 if let Some ( source) = source_opt {
3872- if SentHTLCId :: from_source ( source) == * claimed_htlc_id {
3927+ if SentHTLCId :: from_source ( source) == claim . htlc_id {
38733928 return Some ( ( htlc, source) ) ;
38743929 }
38753930 }
@@ -3883,14 +3938,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38833938 // startup until it is explicitly acked.
38843939 self . push_monitor_event ( MonitorEvent :: HTLCEvent ( HTLCUpdate {
38853940 payment_hash : htlc. payment_hash ,
3886- payment_preimage : Some ( * claimed_preimage ) ,
3941+ payment_preimage : Some ( claim . preimage ) ,
38873942 source : * source. clone ( ) ,
38883943 htlc_value_msat : Some ( htlc. amount_msat ) ,
38893944 user_channel_id : self . user_channel_id ,
38903945 } ) ) ;
38913946 }
38923947 }
3893- self . counterparty_fulfilled_htlcs . insert ( * claimed_htlc_id , * claimed_preimage ) ;
3948+ self . counterparty_fulfilled_htlcs . insert ( claim . htlc_id , claim . preimage ) ;
38943949 }
38953950
38963951 Ok ( ( ) )
0 commit comments