@@ -563,6 +563,28 @@ impl<R: ::std::io::Read> Readable<R> for InputMaterial {
563
563
}
564
564
}
565
565
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
+
566
588
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
567
589
/// once they mature to enough confirmations (ANTI_REORG_DELAY)
568
590
#[ derive( Clone , PartialEq ) ]
@@ -1387,7 +1409,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1387
1409
/// HTLC-Success/HTLC-Timeout transactions.
1388
1410
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
1389
1411
/// 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 > ) {
1391
1413
// Most secp and related errors trying to create keys means we have no hope of constructing
1392
1414
// a spend transaction...so we return no transactions to broadcast
1393
1415
let mut claimable_outpoints = HashMap :: new ( ) ;
@@ -1442,7 +1464,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1442
1464
// First, process non-htlc outputs (to_local & to_remote)
1443
1465
for ( idx, outp) in tx. output . iter ( ) . enumerate ( ) {
1444
1466
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} ) ;
1446
1469
} else if Some ( & outp. script_pubkey ) == local_payment_p2wpkh. as_ref ( ) {
1447
1470
spendable_descriptor = Some ( SpendableOutputDescriptor :: DynamicOutputP2WPKH {
1448
1471
outpoint : BitcoinOutPoint { txid : commitment_txid, vout : idx as u32 } ,
@@ -1462,7 +1485,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1462
1485
tx. output [ transaction_output_index as usize ] . script_pubkey != expected_script. to_v0_p2wsh ( ) {
1463
1486
return ( claimable_outpoints, ( commitment_txid, watch_outputs) , spendable_descriptor) ; // Corrupted per_commitment_data, fuck this user
1464
1487
}
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 } ) ;
1466
1490
}
1467
1491
}
1468
1492
}
@@ -1625,7 +1649,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1625
1649
let preimage = if htlc. offered { if let Some ( p) = self . payment_preimages . get ( & htlc. payment_hash ) { Some ( * p) } else { None } } else { None } ;
1626
1650
let aggregable = if !htlc. offered { false } else { true } ;
1627
1651
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 } ) ;
1629
1654
}
1630
1655
}
1631
1656
}
@@ -1647,7 +1672,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1647
1672
}
1648
1673
1649
1674
/// 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 > > {
1651
1676
//TODO: send back new outputs to guarantee pending_claim_request consistency
1652
1677
if tx. input . len ( ) != 1 || tx. output . len ( ) != 1 || tx. input [ 0 ] . witness . len ( ) != 5 {
1653
1678
return HashMap :: new ( )
@@ -1680,7 +1705,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1680
1705
let htlc_txid = tx. txid ( ) ; //TODO: This is gonna be a performance bottleneck for watchtowers!
1681
1706
1682
1707
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 } ) ;
1684
1710
let mut claimable_outpoints = HashMap :: with_capacity ( 1 ) ;
1685
1711
claimable_outpoints. insert ( htlc_txid, outpoints) ;
1686
1712
claimable_outpoints
@@ -1955,7 +1981,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1955
1981
log_trace ! ( self , "Block {} at height {} connected with {} txn matched" , block_hash, height, txn_matched. len( ) ) ;
1956
1982
let mut watch_outputs = Vec :: new ( ) ;
1957
1983
let mut spendable_outputs = Vec :: new ( ) ;
1958
- let mut claimable_outpoints = HashMap :: new ( ) ;
1984
+ let mut claim_requests = HashMap :: new ( ) ;
1959
1985
for tx in txn_matched {
1960
1986
if tx. input . len ( ) == 1 {
1961
1987
// Assuming our keys were not leaked (in which case we're screwed no matter what),
@@ -1973,14 +1999,14 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1973
1999
} ;
1974
2000
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 ) {
1975
2001
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) ;
1977
2003
if !new_outputs. 1 . is_empty ( ) {
1978
2004
watch_outputs. push ( new_outputs) ;
1979
2005
}
1980
2006
if let Some ( spendable_output) = spendable_output {
1981
2007
spendable_outputs. push ( spendable_output) ;
1982
2008
}
1983
- if new_outpoints . is_empty ( ) {
2009
+ if new_claim_requests . is_empty ( ) {
1984
2010
let ( local_txn, mut spendable_output, new_outputs) = self . check_spend_local_transaction ( & tx, height) ;
1985
2011
spendable_outputs. append ( & mut spendable_output) ;
1986
2012
for tx in local_txn. iter ( ) {
@@ -1991,23 +2017,23 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1991
2017
watch_outputs. push ( new_outputs) ;
1992
2018
}
1993
2019
}
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) ;
1996
2022
}
1997
2023
}
1998
- if !funding_txo. is_none ( ) && claimable_outpoints . is_empty ( ) {
2024
+ if !funding_txo. is_none ( ) && claim_requests . is_empty ( ) {
1999
2025
if let Some ( spendable_output) = self . check_spend_closing_transaction ( & tx) {
2000
2026
spendable_outputs. push ( spendable_output) ;
2001
2027
}
2002
2028
}
2003
2029
} else {
2004
2030
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) ;
2008
2034
}
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) ;
2011
2037
}
2012
2038
}
2013
2039
}
@@ -2065,7 +2091,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
2065
2091
}
2066
2092
}
2067
2093
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) ;
2069
2095
spendable_outputs. append ( & mut spendable_output) ;
2070
2096
2071
2097
self . last_block_hash = block_hash. clone ( ) ;
0 commit comments