@@ -562,6 +562,28 @@ impl<R: ::std::io::Read> Readable<R> for InputMaterial {
562
562
}
563
563
}
564
564
565
+ /// ClaimRequest is a descriptor structure to communicate between detection
566
+ /// and reaction module. They are generated by ChannelMonitor while parsing
567
+ /// onchain txn leaked from a channel and handed over to OnchainTxHandler which
568
+ /// is responsible for opportunistic aggregation, selecting and enforcing
569
+ /// bumping logic, building and signing transactions.
570
+ pub ( crate ) struct ClaimRequest {
571
+ // Block height before which claiming is exclusive to one party,
572
+ // after reaching it, claiming may be contentious.
573
+ pub ( crate ) absolute_timelock : u32 ,
574
+ // Timeout tx must have nLocktime set which means aggregating multiple
575
+ // ones must take the higher nLocktime among them to satisfy all of them.
576
+ // Sadly it has few pitfalls, a) it takes longuer to get fund back b) CLTV_DELTA
577
+ // of a sooner-HTLC could be swallowed by the highest nLocktime of the HTLC set.
578
+ // Do simplify we mark them as non-aggregable.
579
+ pub ( crate ) aggregable : bool ,
580
+ // Basic bitcoin outpoint (txid, vout)
581
+ pub ( crate ) outpoint : BitcoinOutPoint ,
582
+ // Following outpoint type, set of data needed to generate transaction digest
583
+ // and satisfy witness program.
584
+ pub ( crate ) witness_data : InputMaterial
585
+ }
586
+
565
587
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
566
588
/// once they mature to enough confirmations (ANTI_REORG_DELAY)
567
589
#[ derive( Clone , PartialEq ) ]
@@ -1411,7 +1433,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1411
1433
/// HTLC-Success/HTLC-Timeout transactions.
1412
1434
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
1413
1435
/// revoked remote commitment tx
1414
- fn check_spend_remote_transaction ( & mut self , tx : & Transaction , height : u32 ) -> ( HashMap < Sha256dHash , Vec < ( u32 , bool , BitcoinOutPoint , InputMaterial ) > > , ( Sha256dHash , Vec < TxOut > ) , Vec < SpendableOutputDescriptor > ) {
1436
+ fn check_spend_remote_transaction ( & mut self , tx : & Transaction , height : u32 ) -> ( HashMap < Sha256dHash , Vec < ClaimRequest > > , ( Sha256dHash , Vec < TxOut > ) , Vec < SpendableOutputDescriptor > ) {
1415
1437
// Most secp and related errors trying to create keys means we have no hope of constructing
1416
1438
// a spend transaction...so we return no transactions to broadcast
1417
1439
let mut claim_requests_per_txid = HashMap :: new ( ) ;
@@ -1466,7 +1488,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1466
1488
// First, process non-htlc outputs (to_local & to_remote)
1467
1489
for ( idx, outp) in tx. output . iter ( ) . enumerate ( ) {
1468
1490
if outp. script_pubkey == revokeable_p2wsh {
1469
- outpoints. push ( ( height + self . our_to_self_delay as u32 , true , BitcoinOutPoint { txid : commitment_txid, vout : idx as u32 } , InputMaterial :: Revoked { script : revokeable_redeemscript. clone ( ) , pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : outp. value } ) ) ;
1491
+ let witness_data = InputMaterial :: Revoked { script : revokeable_redeemscript. clone ( ) , pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : outp. value } ;
1492
+ outpoints. push ( ClaimRequest { absolute_timelock : height + self . our_to_self_delay as u32 , aggregable : true , outpoint : BitcoinOutPoint { txid : commitment_txid, vout : idx as u32 } , witness_data} ) ;
1470
1493
} else if Some ( & outp. script_pubkey ) == local_payment_p2wpkh. as_ref ( ) {
1471
1494
spendable_outputs. push ( SpendableOutputDescriptor :: DynamicOutputP2WPKH {
1472
1495
outpoint : BitcoinOutPoint { txid : commitment_txid, vout : idx as u32 } ,
@@ -1486,7 +1509,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1486
1509
tx. output [ transaction_output_index as usize ] . script_pubkey != expected_script. to_v0_p2wsh ( ) {
1487
1510
return ( claim_requests_per_txid, ( commitment_txid, watch_outputs) , spendable_outputs) ; // Corrupted per_commitment_data, fuck this user
1488
1511
}
1489
- outpoints. push ( ( htlc. cltv_expiry , true , BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , InputMaterial :: Revoked { script : expected_script, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : true , amount : tx. output [ transaction_output_index as usize ] . value } ) ) ;
1512
+ let witness_data = InputMaterial :: Revoked { script : expected_script, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : true , amount : tx. output [ transaction_output_index as usize ] . value } ;
1513
+ outpoints. push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable : true , outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
1490
1514
}
1491
1515
}
1492
1516
}
@@ -1649,7 +1673,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1649
1673
let preimage = if htlc. offered { if let Some ( p) = self . payment_preimages . get ( & htlc. payment_hash ) { Some ( * p) } else { None } } else { None } ;
1650
1674
let aggregable = if !htlc. offered { false } else { true } ;
1651
1675
if preimage. is_some ( ) || !htlc. offered {
1652
- outpoints. push ( ( htlc. cltv_expiry , aggregable, BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , InputMaterial :: RemoteHTLC { script : expected_script, key : htlc_privkey, preimage, amount : htlc. amount_msat / 1000 , locktime : htlc. cltv_expiry } ) ) ;
1676
+ let witness_data = InputMaterial :: RemoteHTLC { script : expected_script, key : htlc_privkey, preimage, amount : htlc. amount_msat / 1000 , locktime : htlc. cltv_expiry } ;
1677
+ outpoints. push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable, outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
1653
1678
}
1654
1679
}
1655
1680
}
@@ -1671,7 +1696,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1671
1696
}
1672
1697
1673
1698
/// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key
1674
- fn check_spend_remote_htlc ( & mut self , tx : & Transaction , commitment_number : u64 , height : u32 ) -> HashMap < Sha256dHash , Vec < ( u32 , bool , BitcoinOutPoint , InputMaterial ) > > {
1699
+ fn check_spend_remote_htlc ( & mut self , tx : & Transaction , commitment_number : u64 , height : u32 ) -> HashMap < Sha256dHash , Vec < ClaimRequest > > {
1675
1700
//TODO: send back new outputs to guarantee pending_claim_request consistency
1676
1701
if tx. input . len ( ) != 1 || tx. output . len ( ) != 1 || tx. input [ 0 ] . witness . len ( ) != 5 {
1677
1702
return HashMap :: new ( )
@@ -1704,7 +1729,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1704
1729
let htlc_txid = tx. txid ( ) ; //TODO: This is gonna be a performance bottleneck for watchtowers!
1705
1730
1706
1731
log_trace ! ( self , "Remote HTLC broadcast {}:{}" , htlc_txid, 0 ) ;
1707
- let outpoints = vec ! ( ( height + self . our_to_self_delay as u32 , true , BitcoinOutPoint { txid: htlc_txid, vout: 0 } , InputMaterial :: Revoked { script: redeemscript, pubkey: Some ( revocation_pubkey) , key: revocation_key, is_htlc: false , amount: tx. output[ 0 ] . value } ) ) ;
1732
+ let witness_data = InputMaterial :: Revoked { script : redeemscript, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : tx. output [ 0 ] . value } ;
1733
+ let outpoints = vec ! ( ClaimRequest { absolute_timelock: height + self . our_to_self_delay as u32 , aggregable: true , outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0 } , witness_data } ) ;
1708
1734
let mut claimable_outpoints = HashMap :: with_capacity ( 1 ) ;
1709
1735
claimable_outpoints. insert ( htlc_txid, outpoints) ;
1710
1736
claimable_outpoints
@@ -1980,7 +2006,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1980
2006
log_trace ! ( self , "Block {} at height {} connected with {} txn matched" , block_hash, height, txn_matched. len( ) ) ;
1981
2007
let mut watch_outputs = Vec :: new ( ) ;
1982
2008
let mut spendable_outputs = Vec :: new ( ) ;
1983
- let mut claimable_outpoints = HashMap :: new ( ) ;
2009
+ let mut claim_requests = HashMap :: new ( ) ;
1984
2010
for tx in txn_matched {
1985
2011
if tx. input . len ( ) == 1 {
1986
2012
// Assuming our keys were not leaked (in which case we're screwed no matter what),
@@ -1998,12 +2024,12 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1998
2024
} ;
1999
2025
if funding_txo. is_none ( ) || ( prevout. txid == funding_txo. as_ref ( ) . unwrap ( ) . 0 . txid && prevout. vout == funding_txo. as_ref ( ) . unwrap ( ) . 0 . index as u32 ) {
2000
2026
if ( tx. input [ 0 ] . sequence >> 8 * 3 ) as u8 == 0x80 && ( tx. lock_time >> 8 * 3 ) as u8 == 0x20 {
2001
- let ( mut new_outpoints , new_outputs, mut spendable_output) = self . check_spend_remote_transaction ( & tx, height) ;
2027
+ let ( mut new_claim_requests , new_outputs, mut spendable_output) = self . check_spend_remote_transaction ( & tx, height) ;
2002
2028
spendable_outputs. append ( & mut spendable_output) ;
2003
2029
if !new_outputs. 1 . is_empty ( ) {
2004
2030
watch_outputs. push ( new_outputs) ;
2005
2031
}
2006
- if new_outpoints . is_empty ( ) {
2032
+ if new_claim_requests . is_empty ( ) {
2007
2033
let ( local_txn, mut spendable_output, new_outputs) = self . check_spend_local_transaction ( & tx, height) ;
2008
2034
spendable_outputs. append ( & mut spendable_output) ;
2009
2035
for tx in local_txn. iter ( ) {
@@ -2014,20 +2040,20 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
2014
2040
watch_outputs. push ( new_outputs) ;
2015
2041
}
2016
2042
}
2017
- for ( k, v) in new_outpoints . drain ( ) {
2018
- claimable_outpoints . insert ( k, v) ;
2043
+ for ( k, v) in new_claim_requests . drain ( ) {
2044
+ claim_requests . insert ( k, v) ;
2019
2045
}
2020
2046
}
2021
- if !funding_txo. is_none ( ) && claimable_outpoints . is_empty ( ) {
2047
+ if !funding_txo. is_none ( ) && claim_requests . is_empty ( ) {
2022
2048
if let Some ( spendable_output) = self . check_spend_closing_transaction ( & tx) {
2023
2049
spendable_outputs. push ( spendable_output) ;
2024
2050
}
2025
2051
}
2026
2052
} else {
2027
2053
if let Some ( & ( commitment_number, _) ) = self . remote_commitment_txn_on_chain . get ( & prevout. txid ) {
2028
- let mut new_outpoints = self . check_spend_remote_htlc ( & tx, commitment_number, height) ;
2029
- for ( k, v) in new_outpoints . drain ( ) {
2030
- claimable_outpoints . insert ( k, v) ;
2054
+ let mut new_claim_requests = self . check_spend_remote_htlc ( & tx, commitment_number, height) ;
2055
+ for ( k, v) in new_claim_requests . drain ( ) {
2056
+ claim_requests . insert ( k, v) ;
2031
2057
}
2032
2058
}
2033
2059
}
@@ -2084,7 +2110,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
2084
2110
}
2085
2111
}
2086
2112
}
2087
- let mut spendable_output = self . onchain_tx_handler . block_connected ( txn_matched, claimable_outpoints , height, broadcaster, & * fee_estimator) ;
2113
+ let mut spendable_output = self . onchain_tx_handler . block_connected ( txn_matched, claim_requests , height, & * broadcaster, & * fee_estimator) ;
2088
2114
spendable_outputs. append ( & mut spendable_output) ;
2089
2115
2090
2116
self . last_block_hash = block_hash. clone ( ) ;
0 commit comments