@@ -1150,6 +1150,25 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1150
1150
L :: Target : Logger ,
1151
1151
{
1152
1152
self . payment_preimages . insert ( payment_hash. clone ( ) , payment_preimage. clone ( ) ) ;
1153
+ // If the channel is force closed, try to claim the output from this preimage
1154
+ if self . lockdown_from_offchain || self . holder_tx_signed {
1155
+ if let Some ( txid) = self . current_counterparty_commitment_txid {
1156
+ if let Some ( commitment_number) = self . counterparty_commitment_txn_on_chain . get ( & txid) {
1157
+ let ( htlc_claim_reqs, set_script) = self . get_counterparty_htlc_output_claim_reqs ( * commitment_number, txid, None ) ;
1158
+ if set_script {
1159
+ self . counterparty_payment_script = {
1160
+ // Note that the Network here is ignored as we immediately drop the address for the
1161
+ // script_pubkey version
1162
+ let payment_hash160 = WPubkeyHash :: hash ( & self . keys . pubkeys ( ) . payment_point . serialize ( ) ) ;
1163
+ Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_PUSHBYTES_0 ) . push_slice ( & payment_hash160[ ..] ) . into_script ( )
1164
+ } ;
1165
+ }
1166
+ for req in htlc_claim_reqs {
1167
+ self . onchain_tx_handler . claim_counterparty_htlc ( req, broadcaster, fee_estimator, logger) ;
1168
+ }
1169
+ }
1170
+ }
1171
+ }
1153
1172
}
1154
1173
1155
1174
pub ( crate ) fn broadcast_latest_holder_commitment_txn < B : Deref , L : Deref > ( & mut self , broadcaster : & B , logger : & L )
@@ -1166,11 +1185,16 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1166
1185
/// itself.
1167
1186
///
1168
1187
/// panics if the given update is not the next update by update_id.
1169
- pub fn update_monitor < B : Deref , L : Deref > ( & mut self , updates : & ChannelMonitorUpdate , broadcaster : & B , logger : & L ) -> Result < ( ) , MonitorUpdateError >
1170
- where B :: Target : BroadcasterInterface ,
1171
- L :: Target : Logger ,
1188
+ pub fn update_monitor < B : Deref , F : Deref , L : Deref > ( & mut self , updates : & ChannelMonitorUpdate , broadcaster : & B , fee_estimator : & F , logger : & L ) -> Result < ( ) , MonitorUpdateError >
1189
+ where B :: Target : BroadcasterInterface ,
1190
+ F :: Target : FeeEstimator ,
1191
+ L :: Target : Logger ,
1172
1192
{
1173
- if self . latest_update_id + 1 != updates. update_id {
1193
+ // ChannelMonitor updates may be applied after force close if we receive a
1194
+ // preimage for a broadcasted counterparty HTLC output that we'd like to
1195
+ // claim on-chain. If this is the case, we no longer have guaranteed access
1196
+ // to the monitor's update ID, so we use a sentinel value instead.
1197
+ if updates. update_id != std:: u64:: MAX && self . latest_update_id + 1 != updates. update_id {
1174
1198
panic ! ( "Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!" ) ;
1175
1199
}
1176
1200
for update in updates. updates . iter ( ) {
@@ -1438,39 +1462,61 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1438
1462
check_htlc_fails ! ( txid, "previous" , ' prev_loop) ;
1439
1463
}
1440
1464
1465
+ let ( htlc_claim_reqs, set_script) = self . get_counterparty_htlc_output_claim_reqs ( commitment_number, commitment_txid, Some ( tx) ) ;
1466
+ if set_script {
1467
+ self . counterparty_payment_script = {
1468
+ // Note that the Network here is ignored as we immediately drop the address for the
1469
+ // script_pubkey version
1470
+ let payment_hash160 = WPubkeyHash :: hash ( & self . keys . pubkeys ( ) . payment_point . serialize ( ) ) ;
1471
+ Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_PUSHBYTES_0 ) . push_slice ( & payment_hash160[ ..] ) . into_script ( )
1472
+ } ;
1473
+ }
1474
+ for req in htlc_claim_reqs {
1475
+ claimable_outpoints. push ( req) ;
1476
+ }
1477
+
1478
+ }
1479
+ ( claimable_outpoints, ( commitment_txid, watch_outputs) )
1480
+ }
1481
+
1482
+ fn get_counterparty_htlc_output_claim_reqs ( & self , commitment_number : u64 , commitment_txid : Txid , tx : Option < & Transaction > ) -> ( Vec < ClaimRequest > , bool ) {
1483
+ let mut claims = Vec :: new ( ) ;
1484
+ let mut set_counterparty_payment_script = false ;
1485
+ if let Some ( htlc_outputs) = self . counterparty_claimable_outpoints . get ( & commitment_txid) {
1441
1486
if let Some ( revocation_points) = self . their_cur_revocation_points {
1442
1487
let revocation_point_option =
1443
1488
if revocation_points. 0 == commitment_number { Some ( & revocation_points. 1 ) }
1444
- else if let Some ( point) = revocation_points. 2 . as_ref ( ) {
1445
- if revocation_points. 0 == commitment_number + 1 { Some ( point) } else { None }
1446
- } else { None } ;
1489
+ else if let Some ( point) = revocation_points. 2 . as_ref ( ) {
1490
+ if revocation_points. 0 == commitment_number + 1 { Some ( point) } else { None }
1491
+ } else { None } ;
1447
1492
if let Some ( revocation_point) = revocation_point_option {
1448
- self . counterparty_payment_script = {
1449
- // Note that the Network here is ignored as we immediately drop the address for the
1450
- // script_pubkey version
1451
- let payment_hash160 = WPubkeyHash :: hash ( & self . keys . pubkeys ( ) . payment_point . serialize ( ) ) ;
1452
- Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_PUSHBYTES_0 ) . push_slice ( & payment_hash160[ ..] ) . into_script ( )
1453
- } ;
1493
+ set_counterparty_payment_script = true ;
1454
1494
1455
1495
// Then, try to find htlc outputs
1456
- for ( _, & ( ref htlc, _) ) in per_commitment_data . iter ( ) . enumerate ( ) {
1496
+ for ( _, & ( ref htlc, _) ) in htlc_outputs . iter ( ) . enumerate ( ) {
1457
1497
if let Some ( transaction_output_index) = htlc. transaction_output_index {
1458
- if transaction_output_index as usize >= tx. output . len ( ) ||
1459
- tx. output [ transaction_output_index as usize ] . value != htlc. amount_msat / 1000 {
1460
- return ( claimable_outpoints, ( commitment_txid, watch_outputs) ) ; // Corrupted per_commitment_data, fuck this user
1498
+ if let Some ( transaction) = tx {
1499
+ if transaction_output_index as usize >= transaction. output . len ( ) ||
1500
+ transaction. output [ transaction_output_index as usize ] . value != htlc. amount_msat / 1000 {
1501
+ return ( claims, set_counterparty_payment_script) // Corrupted per_commitment_data, fuck this user
1502
+ }
1461
1503
}
1462
- let preimage = if htlc. offered { if let Some ( p) = self . payment_preimages . get ( & htlc. payment_hash ) { Some ( * p) } else { None } } else { None } ;
1504
+ let preimage = if htlc. offered {
1505
+ if let Some ( p) = self . payment_preimages . get ( & htlc. payment_hash ) {
1506
+ Some ( * p)
1507
+ } else { None }
1508
+ } else { None } ;
1463
1509
let aggregable = if !htlc. offered { false } else { true } ;
1464
1510
if preimage. is_some ( ) || !htlc. offered {
1465
1511
let witness_data = InputMaterial :: CounterpartyHTLC { per_commitment_point : * revocation_point, counterparty_delayed_payment_base_key : self . counterparty_tx_cache . counterparty_delayed_payment_base_key , counterparty_htlc_base_key : self . counterparty_tx_cache . counterparty_htlc_base_key , preimage, htlc : htlc. clone ( ) } ;
1466
- claimable_outpoints . push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable, outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
1512
+ claims . push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable, outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
1467
1513
}
1468
1514
}
1469
1515
}
1470
1516
}
1471
1517
}
1472
1518
}
1473
- ( claimable_outpoints , ( commitment_txid , watch_outputs ) )
1519
+ ( claims , set_counterparty_payment_script )
1474
1520
}
1475
1521
1476
1522
/// Attempts to claim a counterparty HTLC-Success/HTLC-Timeout's outputs using the revocation key
@@ -2499,16 +2545,18 @@ mod tests {
2499
2545
use ln:: onchaintx:: { OnchainTxHandler , InputDescriptors } ;
2500
2546
use ln:: chan_utils;
2501
2547
use ln:: chan_utils:: { HTLCOutputInCommitment , HolderCommitmentTransaction } ;
2502
- use util:: test_utils:: TestLogger ;
2548
+ use util:: test_utils:: { TestLogger , TestBroadcaster , TestFeeEstimator } ;
2503
2549
use bitcoin:: secp256k1:: key:: { SecretKey , PublicKey } ;
2504
2550
use bitcoin:: secp256k1:: Secp256k1 ;
2505
- use std:: sync:: Arc ;
2551
+ use std:: sync:: { Arc , Mutex } ;
2506
2552
use chain:: keysinterface:: InMemoryChannelKeys ;
2507
2553
2508
2554
#[ test]
2509
2555
fn test_prune_preimages ( ) {
2510
2556
let secp_ctx = Secp256k1 :: new ( ) ;
2511
2557
let logger = Arc :: new ( TestLogger :: new ( ) ) ;
2558
+ let broadcaster = Arc :: new ( TestBroadcaster { txn_broadcasted : Mutex :: new ( Vec :: new ( ) ) } ) ;
2559
+ let fee_estimator = Arc :: new ( TestFeeEstimator { sat_per_kw : 253 } ) ;
2512
2560
2513
2561
let dummy_key = PublicKey :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ) ;
2514
2562
let dummy_tx = Transaction { version : 0 , lock_time : 0 , input : Vec :: new ( ) , output : Vec :: new ( ) } ;
@@ -2584,7 +2632,7 @@ mod tests {
2584
2632
monitor. provide_latest_counterparty_commitment_tx_info ( & dummy_tx, preimages_slice_to_htlc_outputs ! ( preimages[ 17 ..20 ] ) , 281474976710653 , dummy_key, & logger) ;
2585
2633
monitor. provide_latest_counterparty_commitment_tx_info ( & dummy_tx, preimages_slice_to_htlc_outputs ! ( preimages[ 18 ..20 ] ) , 281474976710652 , dummy_key, & logger) ;
2586
2634
for & ( ref preimage, ref hash) in preimages. iter ( ) {
2587
- monitor. provide_payment_preimage ( hash, preimage) ;
2635
+ monitor. provide_payment_preimage ( hash, preimage, & broadcaster , & fee_estimator , & logger ) ;
2588
2636
}
2589
2637
2590
2638
// Now provide a secret, pruning preimages 10-15
0 commit comments