@@ -516,6 +516,9 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
516
516
on_holder_tx_csv : u16 ,
517
517
518
518
commitment_secrets : CounterpartyCommitmentSecrets ,
519
+ /// The set of outpoints in each counterparty commitment transaction. We always need at least
520
+ /// the payment hash from `HTLCOutputInCommitment` to claim even a revoked commitment
521
+ /// transaction broadcast as we need to be able to construct the witness script in all cases.
519
522
counterparty_claimable_outpoints : HashMap < Txid , Vec < ( HTLCOutputInCommitment , Option < Box < HTLCSource > > ) > > ,
520
523
/// We cannot identify HTLC-Success or HTLC-Timeout transactions by themselves on the chain.
521
524
/// Nor can we figure out their commitment numbers without the commitment transaction they are
@@ -1208,6 +1211,81 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
1208
1211
}
1209
1212
}
1210
1213
1214
+ /// Compares a broadcasted commitment transaction's HTLCs with those in the latest state,
1215
+ /// failing any HTLCs which didn't make it into the broadcasted commitment transaction back
1216
+ /// after ANTI_REORG_DELAY blocks.
1217
+ ///
1218
+ /// We always compare against the set of HTLCs in counterparty commitment transactions, as those
1219
+ /// are the commitment transactions which are generated by us. The off-chain state machine in
1220
+ /// `Channel` will automatically resolve any HTLCs which were never included in a commitment
1221
+ /// transaction when it detects channel closure, but it is up to us to ensure any HTLCs which were
1222
+ /// included in a remote commitment transaction are failed back if they are not present in the
1223
+ /// broadcasted commitment transaction.
1224
+ ///
1225
+ /// Specifically, the removal process for HTLCs in `Channel` is always based on the counterparty
1226
+ /// sending a `revoke_and_ack`, which causes us to clear `prev_counterparty_commitment_txid`. Thus,
1227
+ /// as long as we examine both the current counterparty commitment transaction and, if it hasn't
1228
+ /// been revoked yet, the previous one, we we will never "forget" to resolve an HTLC.
1229
+ macro_rules! fail_unbroadcast_htlcs {
1230
+ ( $self: expr, $commitment_tx_type: expr, $commitment_tx_conf_height: expr, $confirmed_htlcs_list: expr, $logger: expr) => { {
1231
+ macro_rules! check_htlc_fails {
1232
+ ( $txid: expr, $commitment_tx: expr) => {
1233
+ if let Some ( ref latest_outpoints) = $self. counterparty_claimable_outpoints. get( $txid) {
1234
+ for & ( ref htlc, ref source_option) in latest_outpoints. iter( ) {
1235
+ if let & Some ( ref source) = source_option {
1236
+ // Check if the HTLC is present in the commitment transaction that was
1237
+ // broadcast, but not if it was below the dust limit, which we should
1238
+ // fail backwards immediately as there is no way for us to learn the
1239
+ // payment_preimage.
1240
+ // Note that if the dust limit were allowed to change between
1241
+ // commitment transactions we'd want to be check whether *any*
1242
+ // broadcastable commitment transaction has the HTLC in it, but it
1243
+ // cannot currently change after channel initialization, so we don't
1244
+ // need to here.
1245
+ let confirmed_htlcs_iter: & mut Iterator <Item = ( & HTLCOutputInCommitment , Option <& HTLCSource >) > = & mut $confirmed_htlcs_list;
1246
+ let mut matched_htlc = false ;
1247
+ for ( ref broadcast_htlc, ref broadcast_source) in confirmed_htlcs_iter {
1248
+ if broadcast_htlc. transaction_output_index. is_some( ) && Some ( & * * source) == * broadcast_source {
1249
+ matched_htlc = true ;
1250
+ break ;
1251
+ }
1252
+ }
1253
+ if matched_htlc { continue ; }
1254
+ $self. onchain_events_awaiting_threshold_conf. retain( |ref entry| {
1255
+ if entry. height != $commitment_tx_conf_height { return true ; }
1256
+ match entry. event {
1257
+ OnchainEvent :: HTLCUpdate { source: ref update_source, .. } => {
1258
+ * update_source != * * source
1259
+ } ,
1260
+ _ => true ,
1261
+ }
1262
+ } ) ;
1263
+ let entry = OnchainEventEntry {
1264
+ txid: * $txid,
1265
+ height: $commitment_tx_conf_height,
1266
+ event: OnchainEvent :: HTLCUpdate {
1267
+ source: ( * * source) . clone( ) ,
1268
+ payment_hash: htlc. payment_hash. clone( ) ,
1269
+ onchain_value_satoshis: Some ( htlc. amount_msat / 1000 ) ,
1270
+ } ,
1271
+ } ;
1272
+ log_trace!( $logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of {} commitment transaction, waiting for confirmation (at height {})" ,
1273
+ log_bytes!( htlc. payment_hash. 0 ) , $commitment_tx, $commitment_tx_type, entry. confirmation_threshold( ) ) ;
1274
+ $self. onchain_events_awaiting_threshold_conf. push( entry) ;
1275
+ }
1276
+ }
1277
+ }
1278
+ }
1279
+ }
1280
+ if let Some ( ref txid) = $self. current_counterparty_commitment_txid {
1281
+ check_htlc_fails!( txid, "current" ) ;
1282
+ }
1283
+ if let Some ( ref txid) = $self. prev_counterparty_commitment_txid {
1284
+ check_htlc_fails!( txid, "previous" ) ;
1285
+ }
1286
+ } }
1287
+ }
1288
+
1211
1289
impl < Signer : Sign > ChannelMonitorImpl < Signer > {
1212
1290
/// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither
1213
1291
/// needed by holder commitment transactions HTCLs nor by counterparty ones. Unless we haven't already seen
@@ -1571,43 +1649,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
1571
1649
}
1572
1650
self . counterparty_commitment_txn_on_chain . insert ( commitment_txid, commitment_number) ;
1573
1651
1574
- macro_rules! check_htlc_fails {
1575
- ( $txid: expr, $commitment_tx: expr) => {
1576
- if let Some ( ref outpoints) = self . counterparty_claimable_outpoints. get( $txid) {
1577
- for & ( ref htlc, ref source_option) in outpoints. iter( ) {
1578
- if let & Some ( ref source) = source_option {
1579
- self . onchain_events_awaiting_threshold_conf. retain( |ref entry| {
1580
- if entry. height != height { return true ; }
1581
- match entry. event {
1582
- OnchainEvent :: HTLCUpdate { source: ref update_source, .. } => {
1583
- * update_source != * * source
1584
- } ,
1585
- _ => true ,
1586
- }
1587
- } ) ;
1588
- let entry = OnchainEventEntry {
1589
- txid: * $txid,
1590
- height,
1591
- event: OnchainEvent :: HTLCUpdate {
1592
- source: ( * * source) . clone( ) ,
1593
- payment_hash: htlc. payment_hash. clone( ) ,
1594
- onchain_value_satoshis: Some ( htlc. amount_msat / 1000 ) ,
1595
- } ,
1596
- } ;
1597
- log_info!( logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of revoked counterparty commitment transaction, waiting for confirmation (at height {})" , log_bytes!( htlc. payment_hash. 0 ) , $commitment_tx, entry. confirmation_threshold( ) ) ;
1598
- self . onchain_events_awaiting_threshold_conf. push( entry) ;
1599
- }
1600
- }
1601
- }
1602
- }
1603
- }
1604
- if let Some ( ref txid) = self . current_counterparty_commitment_txid {
1605
- check_htlc_fails ! ( txid, "current" ) ;
1606
- }
1607
- if let Some ( ref txid) = self . prev_counterparty_commitment_txid {
1608
- check_htlc_fails ! ( txid, "counterparty" ) ;
1609
- }
1610
- // No need to check holder commitment txn, symmetric HTLCSource must be present as per-htlc data on counterparty commitment tx
1652
+ fail_unbroadcast_htlcs ! ( self , "revoked counterparty" , height, [ ] . iter( ) . map( |a| * a) , logger) ;
1611
1653
}
1612
1654
} else if let Some ( per_commitment_data) = per_commitment_option {
1613
1655
// While this isn't useful yet, there is a potential race where if a counterparty
@@ -1623,56 +1665,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
1623
1665
self . counterparty_commitment_txn_on_chain . insert ( commitment_txid, commitment_number) ;
1624
1666
1625
1667
log_info ! ( logger, "Got broadcast of non-revoked counterparty commitment transaction {}" , commitment_txid) ;
1626
-
1627
- macro_rules! check_htlc_fails {
1628
- ( $txid: expr, $commitment_tx: expr, $id: tt) => {
1629
- if let Some ( ref latest_outpoints) = self . counterparty_claimable_outpoints. get( $txid) {
1630
- $id: for & ( ref htlc, ref source_option) in latest_outpoints. iter( ) {
1631
- if let & Some ( ref source) = source_option {
1632
- // Check if the HTLC is present in the commitment transaction that was
1633
- // broadcast, but not if it was below the dust limit, which we should
1634
- // fail backwards immediately as there is no way for us to learn the
1635
- // payment_preimage.
1636
- // Note that if the dust limit were allowed to change between
1637
- // commitment transactions we'd want to be check whether *any*
1638
- // broadcastable commitment transaction has the HTLC in it, but it
1639
- // cannot currently change after channel initialization, so we don't
1640
- // need to here.
1641
- for & ( ref broadcast_htlc, ref broadcast_source) in per_commitment_data. iter( ) {
1642
- if broadcast_htlc. transaction_output_index. is_some( ) && Some ( source) == broadcast_source. as_ref( ) {
1643
- continue $id;
1644
- }
1645
- }
1646
- log_trace!( logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of counterparty commitment transaction" , log_bytes!( htlc. payment_hash. 0 ) , $commitment_tx) ;
1647
- self . onchain_events_awaiting_threshold_conf. retain( |ref entry| {
1648
- if entry. height != height { return true ; }
1649
- match entry. event {
1650
- OnchainEvent :: HTLCUpdate { source: ref update_source, .. } => {
1651
- * update_source != * * source
1652
- } ,
1653
- _ => true ,
1654
- }
1655
- } ) ;
1656
- self . onchain_events_awaiting_threshold_conf. push( OnchainEventEntry {
1657
- txid: * $txid,
1658
- height,
1659
- event: OnchainEvent :: HTLCUpdate {
1660
- source: ( * * source) . clone( ) ,
1661
- payment_hash: htlc. payment_hash. clone( ) ,
1662
- onchain_value_satoshis: Some ( htlc. amount_msat / 1000 ) ,
1663
- } ,
1664
- } ) ;
1665
- }
1666
- }
1667
- }
1668
- }
1669
- }
1670
- if let Some ( ref txid) = self . current_counterparty_commitment_txid {
1671
- check_htlc_fails ! ( txid, "current" , ' current_loop) ;
1672
- }
1673
- if let Some ( ref txid) = self . prev_counterparty_commitment_txid {
1674
- check_htlc_fails ! ( txid, "previous" , ' prev_loop) ;
1675
- }
1668
+ fail_unbroadcast_htlcs ! ( self , "counterparty" , height, per_commitment_data. iter( ) . map( |( a, b) | ( a, b. as_ref( ) . map( |b| b. as_ref( ) ) ) ) , logger) ;
1676
1669
1677
1670
let htlc_claim_reqs = self . get_counterparty_htlc_output_claim_reqs ( commitment_number, commitment_txid, Some ( tx) ) ;
1678
1671
for req in htlc_claim_reqs {
@@ -1815,52 +1808,19 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
1815
1808
let res = self . get_broadcasted_holder_claims ( & self . current_holder_commitment_tx , height) ;
1816
1809
let mut to_watch = self . get_broadcasted_holder_watch_outputs ( & self . current_holder_commitment_tx , tx) ;
1817
1810
append_onchain_update ! ( res, to_watch) ;
1811
+ fail_unbroadcast_htlcs ! ( self , "latest holder" , height, self . current_holder_commitment_tx. htlc_outputs. iter( ) . map( |( a, _, c) | ( a, c. as_ref( ) ) ) , logger) ;
1818
1812
} else if let & Some ( ref holder_tx) = & self . prev_holder_signed_commitment_tx {
1819
1813
if holder_tx. txid == commitment_txid {
1820
1814
is_holder_tx = true ;
1821
1815
log_info ! ( logger, "Got broadcast of previous holder commitment tx {}, searching for available HTLCs to claim" , commitment_txid) ;
1822
1816
let res = self . get_broadcasted_holder_claims ( holder_tx, height) ;
1823
1817
let mut to_watch = self . get_broadcasted_holder_watch_outputs ( holder_tx, tx) ;
1824
1818
append_onchain_update ! ( res, to_watch) ;
1825
- }
1826
- }
1827
-
1828
- macro_rules! fail_dust_htlcs_after_threshold_conf {
1829
- ( $holder_tx: expr, $commitment_tx: expr) => {
1830
- for & ( ref htlc, _, ref source) in & $holder_tx. htlc_outputs {
1831
- if htlc. transaction_output_index. is_none( ) {
1832
- if let & Some ( ref source) = source {
1833
- self . onchain_events_awaiting_threshold_conf. retain( |ref entry| {
1834
- if entry. height != height { return true ; }
1835
- match entry. event {
1836
- OnchainEvent :: HTLCUpdate { source: ref update_source, .. } => {
1837
- update_source != source
1838
- } ,
1839
- _ => true ,
1840
- }
1841
- } ) ;
1842
- let entry = OnchainEventEntry {
1843
- txid: commitment_txid,
1844
- height,
1845
- event: OnchainEvent :: HTLCUpdate {
1846
- source: source. clone( ) , payment_hash: htlc. payment_hash,
1847
- onchain_value_satoshis: Some ( htlc. amount_msat / 1000 )
1848
- } ,
1849
- } ;
1850
- log_trace!( logger, "Failing HTLC with payment_hash {} from {} holder commitment tx due to broadcast of transaction, waiting confirmation (at height{})" ,
1851
- log_bytes!( htlc. payment_hash. 0 ) , $commitment_tx, entry. confirmation_threshold( ) ) ;
1852
- self . onchain_events_awaiting_threshold_conf. push( entry) ;
1853
- }
1854
- }
1855
- }
1819
+ fail_unbroadcast_htlcs ! ( self , "previous holder" , height, holder_tx. htlc_outputs. iter( ) . map( |( a, _, c) | ( a, c. as_ref( ) ) ) , logger) ;
1856
1820
}
1857
1821
}
1858
1822
1859
1823
if is_holder_tx {
1860
- fail_dust_htlcs_after_threshold_conf ! ( self . current_holder_commitment_tx, "latest" ) ;
1861
- if let & Some ( ref holder_tx) = & self . prev_holder_signed_commitment_tx {
1862
- fail_dust_htlcs_after_threshold_conf ! ( holder_tx, "previous" ) ;
1863
- }
1864
1824
}
1865
1825
1866
1826
( claim_requests, ( commitment_txid, watch_outputs) )
0 commit comments