@@ -499,6 +499,28 @@ impl<R: ::std::io::Read> Readable<R> for InputMaterial {
499
499
}
500
500
}
501
501
502
+ /// ClaimRequest is a descriptor structure to communicate between detection
503
+ /// and reaction module. They are generated by ChannelMonitor while parsing
504
+ /// onchain txn leaked from a channel and handed over to OnchainTxHandler which
505
+ /// is responsible for opportunistic aggregation, selecting and enforcing
506
+ /// bumping logic, building and signing transactions.
507
+ pub ( crate ) struct ClaimRequest {
508
+ // Block height before which claiming is exclusive to one party,
509
+ // after reaching it, claiming may be contentious.
510
+ pub ( crate ) absolute_timelock : u32 ,
511
+ // Timeout tx must have nLocktime set which means aggregating multiple
512
+ // ones must take the higher nLocktime among them to satisfy all of them.
513
+ // Sadly it has few pitfalls, a) it takes longuer to get fund back b) CLTV_DELTA
514
+ // of a sooner-HTLC could be swallowed by the highest nLocktime of the HTLC set.
515
+ // Do simplify we mark them as non-aggregable.
516
+ pub ( crate ) aggregable : bool ,
517
+ // Basic bitcoin outpoint (txid, vout)
518
+ pub ( crate ) outpoint : BitcoinOutPoint ,
519
+ // Following outpoint type, set of data needed to generate transaction digest
520
+ // and satisfy witness program.
521
+ pub ( crate ) witness_data : InputMaterial
522
+ }
523
+
502
524
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
503
525
/// once they mature to enough confirmations (ANTI_REORG_DELAY)
504
526
#[ derive( Clone , PartialEq ) ]
@@ -1231,7 +1253,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1231
1253
/// HTLC-Success/HTLC-Timeout transactions.
1232
1254
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
1233
1255
/// revoked remote commitment tx
1234
- fn check_spend_remote_transaction ( & mut self , tx : & Transaction , height : u32 ) -> ( HashMap < Sha256dHash , Vec < ( u32 , bool , BitcoinOutPoint , InputMaterial ) > > , ( Sha256dHash , Vec < TxOut > ) , Option < SpendableOutputDescriptor > ) {
1256
+ fn check_spend_remote_transaction ( & mut self , tx : & Transaction , height : u32 ) -> ( HashMap < Sha256dHash , Vec < ClaimRequest > > , ( Sha256dHash , Vec < TxOut > ) , Option < SpendableOutputDescriptor > ) {
1235
1257
// Most secp and related errors trying to create keys means we have no hope of constructing
1236
1258
// a spend transaction...so we return no transactions to broadcast
1237
1259
let mut claimable_outpoints = HashMap :: new ( ) ;
@@ -1286,7 +1308,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1286
1308
// First, process non-htlc outputs (to_local & to_remote)
1287
1309
for ( idx, outp) in tx. output . iter ( ) . enumerate ( ) {
1288
1310
if outp. script_pubkey == revokeable_p2wsh {
1289
- 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 } ) ) ;
1311
+ let witness_data = InputMaterial :: Revoked { script : revokeable_redeemscript. clone ( ) , pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : outp. value } ;
1312
+ 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} ) ;
1290
1313
} else if Some ( & outp. script_pubkey ) == local_payment_p2wpkh. as_ref ( ) {
1291
1314
spendable_descriptor = Some ( SpendableOutputDescriptor :: DynamicOutputP2WPKH {
1292
1315
outpoint : BitcoinOutPoint { txid : commitment_txid, vout : idx as u32 } ,
@@ -1306,7 +1329,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1306
1329
tx. output [ transaction_output_index as usize ] . script_pubkey != expected_script. to_v0_p2wsh ( ) {
1307
1330
return ( claimable_outpoints, ( commitment_txid, watch_outputs) , spendable_descriptor) ; // Corrupted per_commitment_data, fuck this user
1308
1331
}
1309
- 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 } ) ) ;
1332
+ 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 } ;
1333
+ outpoints. push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable : true , outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
1310
1334
}
1311
1335
}
1312
1336
}
@@ -1469,7 +1493,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1469
1493
let preimage = if htlc. offered { if let Some ( p) = self . payment_preimages . get ( & htlc. payment_hash ) { Some ( * p) } else { None } } else { None } ;
1470
1494
let aggregable = if !htlc. offered { false } else { true } ;
1471
1495
if preimage. is_some ( ) || !htlc. offered {
1472
- 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 } ) ) ;
1496
+ let witness_data = InputMaterial :: RemoteHTLC { script : expected_script, key : htlc_privkey, preimage, amount : htlc. amount_msat / 1000 , locktime : htlc. cltv_expiry } ;
1497
+ outpoints. push ( ClaimRequest { absolute_timelock : htlc. cltv_expiry , aggregable, outpoint : BitcoinOutPoint { txid : commitment_txid, vout : transaction_output_index } , witness_data } ) ;
1473
1498
}
1474
1499
}
1475
1500
}
@@ -1491,7 +1516,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1491
1516
}
1492
1517
1493
1518
/// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key
1494
- fn check_spend_remote_htlc ( & mut self , tx : & Transaction , commitment_number : u64 , height : u32 ) -> HashMap < Sha256dHash , Vec < ( u32 , bool , BitcoinOutPoint , InputMaterial ) > > {
1519
+ fn check_spend_remote_htlc ( & mut self , tx : & Transaction , commitment_number : u64 , height : u32 ) -> HashMap < Sha256dHash , Vec < ClaimRequest > > {
1495
1520
//TODO: send back new outputs to guarantee pending_claim_request consistency
1496
1521
if tx. input . len ( ) != 1 || tx. output . len ( ) != 1 || tx. input [ 0 ] . witness . len ( ) != 5 {
1497
1522
return HashMap :: new ( )
@@ -1524,7 +1549,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1524
1549
let htlc_txid = tx. txid ( ) ; //TODO: This is gonna be a performance bottleneck for watchtowers!
1525
1550
1526
1551
log_trace ! ( self , "Remote HTLC broadcast {}:{}" , htlc_txid, 0 ) ;
1527
- 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 } ) ) ;
1552
+ let witness_data = InputMaterial :: Revoked { script : redeemscript, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : false , amount : tx. output [ 0 ] . value } ;
1553
+ 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 } ) ;
1528
1554
let mut claimable_outpoints = HashMap :: with_capacity ( 1 ) ;
1529
1555
claimable_outpoints. insert ( htlc_txid, outpoints) ;
1530
1556
claimable_outpoints
@@ -1793,7 +1819,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1793
1819
let mut watch_outputs = Vec :: new ( ) ;
1794
1820
let mut spendable_outputs = Vec :: new ( ) ;
1795
1821
let mut htlc_updated = Vec :: new ( ) ;
1796
- let mut claimable_outpoints = HashMap :: new ( ) ;
1822
+ let mut claim_requests = HashMap :: new ( ) ;
1797
1823
for tx in txn_matched {
1798
1824
if tx. input . len ( ) == 1 {
1799
1825
// Assuming our keys were not leaked (in which case we're screwed no matter what),
@@ -1811,14 +1837,14 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1811
1837
} ;
1812
1838
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 ) {
1813
1839
if ( tx. input [ 0 ] . sequence >> 8 * 3 ) as u8 == 0x80 && ( tx. lock_time >> 8 * 3 ) as u8 == 0x20 {
1814
- let ( mut new_outpoints , new_outputs, spendable_output) = self . check_spend_remote_transaction ( & tx, height) ;
1840
+ let ( mut new_claim_requests , new_outputs, spendable_output) = self . check_spend_remote_transaction ( & tx, height) ;
1815
1841
if !new_outputs. 1 . is_empty ( ) {
1816
1842
watch_outputs. push ( new_outputs) ;
1817
1843
}
1818
1844
if let Some ( spendable_output) = spendable_output {
1819
1845
spendable_outputs. push ( spendable_output) ;
1820
1846
}
1821
- if new_outpoints . is_empty ( ) {
1847
+ if new_claim_requests . is_empty ( ) {
1822
1848
let ( local_txn, mut spendable_output, new_outputs) = self . check_spend_local_transaction ( & tx, height) ;
1823
1849
spendable_outputs. append ( & mut spendable_output) ;
1824
1850
for tx in local_txn. iter ( ) {
@@ -1829,23 +1855,23 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1829
1855
watch_outputs. push ( new_outputs) ;
1830
1856
}
1831
1857
}
1832
- for ( k, v) in new_outpoints . drain ( ) {
1833
- claimable_outpoints . insert ( k, v) ;
1858
+ for ( k, v) in new_claim_requests . drain ( ) {
1859
+ claim_requests . insert ( k, v) ;
1834
1860
}
1835
1861
}
1836
- if !funding_txo. is_none ( ) && claimable_outpoints . is_empty ( ) {
1862
+ if !funding_txo. is_none ( ) && claim_requests . is_empty ( ) {
1837
1863
if let Some ( spendable_output) = self . check_spend_closing_transaction ( & tx) {
1838
1864
spendable_outputs. push ( spendable_output) ;
1839
1865
}
1840
1866
}
1841
1867
} else {
1842
1868
if let Some ( & ( commitment_number, _) ) = self . remote_commitment_txn_on_chain . get ( & prevout. txid ) {
1843
- let mut new_outpoints = self . check_spend_remote_htlc ( & tx, commitment_number, height) ;
1844
- for ( k, v) in new_outpoints . drain ( ) {
1845
- claimable_outpoints . insert ( k, v) ;
1869
+ let mut new_claim_requests = self . check_spend_remote_htlc ( & tx, commitment_number, height) ;
1870
+ for ( k, v) in new_claim_requests . drain ( ) {
1871
+ claim_requests . insert ( k, v) ;
1846
1872
}
1847
- for ( k, v) in new_outpoints . drain ( ) {
1848
- claimable_outpoints . insert ( k, v) ;
1873
+ for ( k, v) in new_claim_requests . drain ( ) {
1874
+ claim_requests . insert ( k, v) ;
1849
1875
}
1850
1876
}
1851
1877
}
@@ -1902,7 +1928,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1902
1928
}
1903
1929
}
1904
1930
1905
- let mut spendable_output = self . onchain_tx_handler . block_connected ( txn_matched, claimable_outpoints , height, broadcaster, fee_estimator) ;
1931
+ let mut spendable_output = self . onchain_tx_handler . block_connected ( txn_matched, claim_requests , height, broadcaster, fee_estimator) ;
1906
1932
spendable_outputs. append ( & mut spendable_output) ;
1907
1933
1908
1934
self . last_block_hash = block_hash. clone ( ) ;
0 commit comments