@@ -515,6 +515,28 @@ impl<R: ::std::io::Read> Readable<R> for InputMaterial {
515515 }
516516}
517517
518+ /// ClaimRequest is a descriptor structure to communicate between detection
519+ /// and reaction module. They are generated by ChannelMonitor while parsing
520+ /// onchain txn leaked from a channel and handed over to OnchainTxHandler which
521+ /// is responsible for opportunistic aggregation, selecting and enforcing
522+ /// bumping logic, building and signing transactions.
523+ pub ( crate ) struct ClaimRequest {
524+ // Block height before which claiming is exclusive to one party,
525+ // after reaching it, claiming may be contentious.
526+ pub ( crate ) absolute_timelock : u32 ,
527+ // Timeout tx must have nLocktime set which means aggregating multiple
528+ // ones must take the higher nLocktime among them to satisfy all of them.
529+ // Sadly it has few pitfalls, a) it takes longuer to get fund back b) CLTV_DELTA
530+ // of a sooner-HTLC could be swallowed by the highest nLocktime of the HTLC set.
531+ // Do simplify we mark them as non-aggregable.
532+ pub ( crate ) aggregable : bool ,
533+ // Basic bitcoin outpoint (txid, vout)
534+ pub ( crate ) outpoint : BitcoinOutPoint ,
535+ // Following outpoint type, set of data needed to generate transaction digest
536+ // and satisfy witness program.
537+ pub ( crate ) witness_data : InputMaterial
538+ }
539+
518540/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
519541/// once they mature to enough confirmations (ANTI_REORG_DELAY)
520542#[ derive( Clone , PartialEq ) ]
@@ -1247,7 +1269,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
12471269 /// HTLC-Success/HTLC-Timeout transactions.
12481270 /// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
12491271 /// revoked remote commitment tx
1250- fn check_spend_remote_transaction ( & mut self , tx : & Transaction , height : u32 ) -> ( HashMap < Sha256dHash , Vec < ( u32 , bool , BitcoinOutPoint , InputMaterial ) > > , ( Sha256dHash , Vec < TxOut > ) , Option < SpendableOutputDescriptor > ) {
1272+ fn check_spend_remote_transaction ( & mut self , tx : & Transaction , height : u32 ) -> ( HashMap < Sha256dHash , Vec < ClaimRequest > > , ( Sha256dHash , Vec < TxOut > ) , Option < SpendableOutputDescriptor > ) {
12511273 // Most secp and related errors trying to create keys means we have no hope of constructing
12521274 // a spend transaction...so we return no transactions to broadcast
12531275 let mut claimable_outpoints = HashMap :: new ( ) ;
@@ -1302,7 +1324,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
13021324 // First, process non-htlc outputs (to_local & to_remote)
13031325 for ( idx, outp) in tx. output . iter ( ) . enumerate ( ) {
13041326 if outp. script_pubkey == revokeable_p2wsh {
1305- 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 } ) ) ;
1327+ let witness_data = InputMaterial :: Revoked { script : revokeable_redeemscript. clone ( ) , pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : outp. value } ;
1328+ 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} ) ;
13061329 } else if Some ( & outp. script_pubkey ) == local_payment_p2wpkh. as_ref ( ) {
13071330 spendable_descriptor = Some ( SpendableOutputDescriptor :: DynamicOutputP2WPKH {
13081331 outpoint : BitcoinOutPoint { txid : commitment_txid, vout : idx as u32 } ,
@@ -1322,7 +1345,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
13221345 tx. output [ transaction_output_index as usize ] . script_pubkey != expected_script. to_v0_p2wsh ( ) {
13231346 return ( claimable_outpoints, ( commitment_txid, watch_outputs) , spendable_descriptor) ; // Corrupted per_commitment_data, fuck this user
13241347 }
1325- 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 } ) ) ;
1348+ 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 } ;
1349+ outpoints. push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable : true , outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
13261350 }
13271351 }
13281352 }
@@ -1485,7 +1509,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
14851509 let preimage = if htlc. offered { if let Some ( p) = self . payment_preimages . get ( & htlc. payment_hash ) { Some ( * p) } else { None } } else { None } ;
14861510 let aggregable = if !htlc. offered { false } else { true } ;
14871511 if preimage. is_some ( ) || !htlc. offered {
1488- 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 } ) ) ;
1512+ let witness_data = InputMaterial :: RemoteHTLC { script : expected_script, key : htlc_privkey, preimage, amount : htlc. amount_msat / 1000 , locktime : htlc. cltv_expiry } ;
1513+ outpoints. push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable, outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
14891514 }
14901515 }
14911516 }
@@ -1507,7 +1532,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15071532 }
15081533
15091534 /// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key
1510- fn check_spend_remote_htlc ( & mut self , tx : & Transaction , commitment_number : u64 , height : u32 ) -> HashMap < Sha256dHash , Vec < ( u32 , bool , BitcoinOutPoint , InputMaterial ) > > {
1535+ fn check_spend_remote_htlc ( & mut self , tx : & Transaction , commitment_number : u64 , height : u32 ) -> HashMap < Sha256dHash , Vec < ClaimRequest > > {
15111536 //TODO: send back new outputs to guarantee pending_claim_request consistency
15121537 if tx. input . len ( ) != 1 || tx. output . len ( ) != 1 || tx. input [ 0 ] . witness . len ( ) != 5 {
15131538 return HashMap :: new ( )
@@ -1540,7 +1565,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15401565 let htlc_txid = tx. txid ( ) ; //TODO: This is gonna be a performance bottleneck for watchtowers!
15411566
15421567 log_trace ! ( self , "Remote HTLC broadcast {}:{}" , htlc_txid, 0 ) ;
1543- 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 } ) ) ;
1568+ let witness_data = InputMaterial :: Revoked { script : redeemscript, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : tx. output [ 0 ] . value } ;
1569+ 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 } ) ;
15441570 let mut claimable_outpoints = HashMap :: with_capacity ( 1 ) ;
15451571 claimable_outpoints. insert ( htlc_txid, outpoints) ;
15461572 claimable_outpoints
@@ -1809,7 +1835,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
18091835 let mut watch_outputs = Vec :: new ( ) ;
18101836 let mut spendable_outputs = Vec :: new ( ) ;
18111837 let mut htlc_updated = Vec :: new ( ) ;
1812- let mut claimable_outpoints = HashMap :: new ( ) ;
1838+ let mut claim_requests = HashMap :: new ( ) ;
18131839 for tx in txn_matched {
18141840 if tx. input . len ( ) == 1 {
18151841 // Assuming our keys were not leaked (in which case we're screwed no matter what),
@@ -1827,14 +1853,14 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
18271853 } ;
18281854 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 ) {
18291855 if ( tx. input [ 0 ] . sequence >> 8 * 3 ) as u8 == 0x80 && ( tx. lock_time >> 8 * 3 ) as u8 == 0x20 {
1830- let ( mut new_outpoints , new_outputs, spendable_output) = self . check_spend_remote_transaction ( & tx, height) ;
1856+ let ( mut new_claim_requests , new_outputs, spendable_output) = self . check_spend_remote_transaction ( & tx, height) ;
18311857 if !new_outputs. 1 . is_empty ( ) {
18321858 watch_outputs. push ( new_outputs) ;
18331859 }
18341860 if let Some ( spendable_output) = spendable_output {
18351861 spendable_outputs. push ( spendable_output) ;
18361862 }
1837- if new_outpoints . is_empty ( ) {
1863+ if new_claim_requests . is_empty ( ) {
18381864 let ( local_txn, mut spendable_output, new_outputs) = self . check_spend_local_transaction ( & tx, height) ;
18391865 spendable_outputs. append ( & mut spendable_output) ;
18401866 for tx in local_txn. iter ( ) {
@@ -1845,23 +1871,23 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
18451871 watch_outputs. push ( new_outputs) ;
18461872 }
18471873 }
1848- for ( k, v) in new_outpoints . drain ( ) {
1849- claimable_outpoints . insert ( k, v) ;
1874+ for ( k, v) in new_claim_requests . drain ( ) {
1875+ claim_requests . insert ( k, v) ;
18501876 }
18511877 }
1852- if !funding_txo. is_none ( ) && claimable_outpoints . is_empty ( ) {
1878+ if !funding_txo. is_none ( ) && claim_requests . is_empty ( ) {
18531879 if let Some ( spendable_output) = self . check_spend_closing_transaction ( & tx) {
18541880 spendable_outputs. push ( spendable_output) ;
18551881 }
18561882 }
18571883 } else {
18581884 if let Some ( & ( commitment_number, _) ) = self . remote_commitment_txn_on_chain . get ( & prevout. txid ) {
1859- let mut new_outpoints = self . check_spend_remote_htlc ( & tx, commitment_number, height) ;
1860- for ( k, v) in new_outpoints . drain ( ) {
1861- claimable_outpoints . insert ( k, v) ;
1885+ let mut new_claim_requests = self . check_spend_remote_htlc ( & tx, commitment_number, height) ;
1886+ for ( k, v) in new_claim_requests . drain ( ) {
1887+ claim_requests . insert ( k, v) ;
18621888 }
1863- for ( k, v) in new_outpoints . drain ( ) {
1864- claimable_outpoints . insert ( k, v) ;
1889+ for ( k, v) in new_claim_requests . drain ( ) {
1890+ claim_requests . insert ( k, v) ;
18651891 }
18661892 }
18671893 }
@@ -1918,7 +1944,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
19181944 }
19191945 }
19201946
1921- let mut spendable_output = self . onchain_tx_handler . block_connected ( txn_matched, claimable_outpoints , height, broadcaster, fee_estimator) ;
1947+ let mut spendable_output = self . onchain_tx_handler . block_connected ( txn_matched, claim_requests , height, broadcaster, fee_estimator) ;
19221948 spendable_outputs. append ( & mut spendable_output) ;
19231949
19241950 self . last_block_hash = block_hash. clone ( ) ;
0 commit comments