@@ -563,6 +563,28 @@ impl<R: ::std::io::Read> Readable<R> for InputMaterial {
563563 }
564564}
565565
566+ /// ClaimRequest is a descriptor structure to communicate between detection
567+ /// and reaction module. They are generated by ChannelMonitor while parsing
568+ /// onchain txn leaked from a channel and handed over to OnchainTxHandler which
569+ /// is responsible for opportunistic aggregation, selecting and enforcing
570+ /// bumping logic, building and signing transactions.
571+ pub ( crate ) struct ClaimRequest {
572+ // Block height before which claiming is exclusive to one party,
573+ // after reaching it, claiming may be contentious.
574+ pub ( crate ) absolute_timelock : u32 ,
575+ // Timeout tx must have nLocktime set which means aggregating multiple
576+ // ones must take the higher nLocktime among them to satisfy all of them.
577+ // Sadly it has few pitfalls, a) it takes longuer to get fund back b) CLTV_DELTA
578+ // of a sooner-HTLC could be swallowed by the highest nLocktime of the HTLC set.
579+ // Do simplify we mark them as non-aggregable.
580+ pub ( crate ) aggregable : bool ,
581+ // Basic bitcoin outpoint (txid, vout)
582+ pub ( crate ) outpoint : BitcoinOutPoint ,
583+ // Following outpoint type, set of data needed to generate transaction digest
584+ // and satisfy witness program.
585+ pub ( crate ) witness_data : InputMaterial
586+ }
587+
566588/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
567589/// once they mature to enough confirmations (ANTI_REORG_DELAY)
568590#[ derive( Clone , PartialEq ) ]
@@ -1387,7 +1409,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
13871409 /// HTLC-Success/HTLC-Timeout transactions.
13881410 /// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
13891411 /// revoked remote commitment tx
1390- fn check_spend_remote_transaction ( & mut self , tx : & Transaction , height : u32 ) -> ( HashMap < Sha256dHash , Vec < ( u32 , bool , BitcoinOutPoint , InputMaterial ) > > , ( Sha256dHash , Vec < TxOut > ) , Option < SpendableOutputDescriptor > ) {
1412+ fn check_spend_remote_transaction ( & mut self , tx : & Transaction , height : u32 ) -> ( HashMap < Sha256dHash , Vec < ClaimRequest > > , ( Sha256dHash , Vec < TxOut > ) , Option < SpendableOutputDescriptor > ) {
13911413 // Most secp and related errors trying to create keys means we have no hope of constructing
13921414 // a spend transaction...so we return no transactions to broadcast
13931415 let mut claimable_outpoints = HashMap :: new ( ) ;
@@ -1442,7 +1464,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
14421464 // First, process non-htlc outputs (to_local & to_remote)
14431465 for ( idx, outp) in tx. output . iter ( ) . enumerate ( ) {
14441466 if outp. script_pubkey == revokeable_p2wsh {
1445- 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 } ) ) ;
1467+ let witness_data = InputMaterial :: Revoked { script : revokeable_redeemscript. clone ( ) , pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : outp. value } ;
1468+ 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} ) ;
14461469 } else if Some ( & outp. script_pubkey ) == local_payment_p2wpkh. as_ref ( ) {
14471470 spendable_descriptor = Some ( SpendableOutputDescriptor :: DynamicOutputP2WPKH {
14481471 outpoint : BitcoinOutPoint { txid : commitment_txid, vout : idx as u32 } ,
@@ -1462,7 +1485,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
14621485 tx. output [ transaction_output_index as usize ] . script_pubkey != expected_script. to_v0_p2wsh ( ) {
14631486 return ( claimable_outpoints, ( commitment_txid, watch_outputs) , spendable_descriptor) ; // Corrupted per_commitment_data, fuck this user
14641487 }
1465- 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 } ) ) ;
1488+ 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 } ;
1489+ outpoints. push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable : true , outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
14661490 }
14671491 }
14681492 }
@@ -1625,7 +1649,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
16251649 let preimage = if htlc. offered { if let Some ( p) = self . payment_preimages . get ( & htlc. payment_hash ) { Some ( * p) } else { None } } else { None } ;
16261650 let aggregable = if !htlc. offered { false } else { true } ;
16271651 if preimage. is_some ( ) || !htlc. offered {
1628- 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 } ) ) ;
1652+ let witness_data = InputMaterial :: RemoteHTLC { script : expected_script, key : htlc_privkey, preimage, amount : htlc. amount_msat / 1000 , locktime : htlc. cltv_expiry } ;
1653+ outpoints. push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable, outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
16291654 }
16301655 }
16311656 }
@@ -1647,7 +1672,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
16471672 }
16481673
16491674 /// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key
1650- fn check_spend_remote_htlc ( & mut self , tx : & Transaction , commitment_number : u64 , height : u32 ) -> HashMap < Sha256dHash , Vec < ( u32 , bool , BitcoinOutPoint , InputMaterial ) > > {
1675+ fn check_spend_remote_htlc ( & mut self , tx : & Transaction , commitment_number : u64 , height : u32 ) -> HashMap < Sha256dHash , Vec < ClaimRequest > > {
16511676 //TODO: send back new outputs to guarantee pending_claim_request consistency
16521677 if tx. input . len ( ) != 1 || tx. output . len ( ) != 1 || tx. input [ 0 ] . witness . len ( ) != 5 {
16531678 return HashMap :: new ( )
@@ -1680,7 +1705,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
16801705 let htlc_txid = tx. txid ( ) ; //TODO: This is gonna be a performance bottleneck for watchtowers!
16811706
16821707 log_trace ! ( self , "Remote HTLC broadcast {}:{}" , htlc_txid, 0 ) ;
1683- 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 } ) ) ;
1708+ let witness_data = InputMaterial :: Revoked { script : redeemscript, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : tx. output [ 0 ] . value } ;
1709+ 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 } ) ;
16841710 let mut claimable_outpoints = HashMap :: with_capacity ( 1 ) ;
16851711 claimable_outpoints. insert ( htlc_txid, outpoints) ;
16861712 claimable_outpoints
@@ -1955,7 +1981,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
19551981 log_trace ! ( self , "Block {} at height {} connected with {} txn matched" , block_hash, height, txn_matched. len( ) ) ;
19561982 let mut watch_outputs = Vec :: new ( ) ;
19571983 let mut spendable_outputs = Vec :: new ( ) ;
1958- let mut claimable_outpoints = HashMap :: new ( ) ;
1984+ let mut claim_requests = HashMap :: new ( ) ;
19591985 for tx in txn_matched {
19601986 if tx. input . len ( ) == 1 {
19611987 // Assuming our keys were not leaked (in which case we're screwed no matter what),
@@ -1973,14 +1999,14 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
19731999 } ;
19742000 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 ) {
19752001 if ( tx. input [ 0 ] . sequence >> 8 * 3 ) as u8 == 0x80 && ( tx. lock_time >> 8 * 3 ) as u8 == 0x20 {
1976- let ( mut new_outpoints , new_outputs, spendable_output) = self . check_spend_remote_transaction ( & tx, height) ;
2002+ let ( mut new_claim_requests , new_outputs, spendable_output) = self . check_spend_remote_transaction ( & tx, height) ;
19772003 if !new_outputs. 1 . is_empty ( ) {
19782004 watch_outputs. push ( new_outputs) ;
19792005 }
19802006 if let Some ( spendable_output) = spendable_output {
19812007 spendable_outputs. push ( spendable_output) ;
19822008 }
1983- if new_outpoints . is_empty ( ) {
2009+ if new_claim_requests . is_empty ( ) {
19842010 let ( local_txn, mut spendable_output, new_outputs) = self . check_spend_local_transaction ( & tx, height) ;
19852011 spendable_outputs. append ( & mut spendable_output) ;
19862012 for tx in local_txn. iter ( ) {
@@ -1991,23 +2017,23 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
19912017 watch_outputs. push ( new_outputs) ;
19922018 }
19932019 }
1994- for ( k, v) in new_outpoints . drain ( ) {
1995- claimable_outpoints . insert ( k, v) ;
2020+ for ( k, v) in new_claim_requests . drain ( ) {
2021+ claim_requests . insert ( k, v) ;
19962022 }
19972023 }
1998- if !funding_txo. is_none ( ) && claimable_outpoints . is_empty ( ) {
2024+ if !funding_txo. is_none ( ) && claim_requests . is_empty ( ) {
19992025 if let Some ( spendable_output) = self . check_spend_closing_transaction ( & tx) {
20002026 spendable_outputs. push ( spendable_output) ;
20012027 }
20022028 }
20032029 } else {
20042030 if let Some ( & ( commitment_number, _) ) = self . remote_commitment_txn_on_chain . get ( & prevout. txid ) {
2005- let mut new_outpoints = self . check_spend_remote_htlc ( & tx, commitment_number, height) ;
2006- for ( k, v) in new_outpoints . drain ( ) {
2007- claimable_outpoints . insert ( k, v) ;
2031+ let mut new_claim_requests = self . check_spend_remote_htlc ( & tx, commitment_number, height) ;
2032+ for ( k, v) in new_claim_requests . drain ( ) {
2033+ claim_requests . insert ( k, v) ;
20082034 }
2009- for ( k, v) in new_outpoints . drain ( ) {
2010- claimable_outpoints . insert ( k, v) ;
2035+ for ( k, v) in new_claim_requests . drain ( ) {
2036+ claim_requests . insert ( k, v) ;
20112037 }
20122038 }
20132039 }
@@ -2065,7 +2091,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
20652091 }
20662092 }
20672093
2068- let mut spendable_output = self . onchain_tx_handler . block_connected ( txn_matched, claimable_outpoints , height, broadcaster, fee_estimator) ;
2094+ let mut spendable_output = self . onchain_tx_handler . block_connected ( txn_matched, claim_requests , height, broadcaster, fee_estimator) ;
20692095 spendable_outputs. append ( & mut spendable_output) ;
20702096
20712097 self . last_block_hash = block_hash. clone ( ) ;
0 commit comments