@@ -515,6 +515,28 @@ impl<R: ::std::io::Read> Readable<R> for InputMaterial {
515
515
}
516
516
}
517
517
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
+
518
540
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
519
541
/// once they mature to enough confirmations (ANTI_REORG_DELAY)
520
542
#[ derive( Clone , PartialEq ) ]
@@ -1247,7 +1269,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1247
1269
/// HTLC-Success/HTLC-Timeout transactions.
1248
1270
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
1249
1271
/// 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 > ) {
1251
1273
// Most secp and related errors trying to create keys means we have no hope of constructing
1252
1274
// a spend transaction...so we return no transactions to broadcast
1253
1275
let mut claimable_outpoints = HashMap :: new ( ) ;
@@ -1302,7 +1324,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1302
1324
// First, process non-htlc outputs (to_local & to_remote)
1303
1325
for ( idx, outp) in tx. output . iter ( ) . enumerate ( ) {
1304
1326
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} ) ;
1306
1329
} else if Some ( & outp. script_pubkey ) == local_payment_p2wpkh. as_ref ( ) {
1307
1330
spendable_descriptor = Some ( SpendableOutputDescriptor :: DynamicOutputP2WPKH {
1308
1331
outpoint : BitcoinOutPoint { txid : commitment_txid, vout : idx as u32 } ,
@@ -1322,7 +1345,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1322
1345
tx. output [ transaction_output_index as usize ] . script_pubkey != expected_script. to_v0_p2wsh ( ) {
1323
1346
return ( claimable_outpoints, ( commitment_txid, watch_outputs) , spendable_descriptor) ; // Corrupted per_commitment_data, fuck this user
1324
1347
}
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 } ) ;
1326
1350
}
1327
1351
}
1328
1352
}
@@ -1485,7 +1509,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1485
1509
let preimage = if htlc. offered { if let Some ( p) = self . payment_preimages . get ( & htlc. payment_hash ) { Some ( * p) } else { None } } else { None } ;
1486
1510
let aggregable = if !htlc. offered { false } else { true } ;
1487
1511
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 } ) ;
1489
1514
}
1490
1515
}
1491
1516
}
@@ -1507,7 +1532,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1507
1532
}
1508
1533
1509
1534
/// 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 > > {
1511
1536
//TODO: send back new outputs to guarantee pending_claim_request consistency
1512
1537
if tx. input . len ( ) != 1 || tx. output . len ( ) != 1 || tx. input [ 0 ] . witness . len ( ) != 5 {
1513
1538
return HashMap :: new ( )
@@ -1540,7 +1565,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1540
1565
let htlc_txid = tx. txid ( ) ; //TODO: This is gonna be a performance bottleneck for watchtowers!
1541
1566
1542
1567
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 } ) ;
1544
1570
let mut claimable_outpoints = HashMap :: with_capacity ( 1 ) ;
1545
1571
claimable_outpoints. insert ( htlc_txid, outpoints) ;
1546
1572
claimable_outpoints
@@ -1809,7 +1835,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1809
1835
let mut watch_outputs = Vec :: new ( ) ;
1810
1836
let mut spendable_outputs = Vec :: new ( ) ;
1811
1837
let mut htlc_updated = Vec :: new ( ) ;
1812
- let mut claimable_outpoints = HashMap :: new ( ) ;
1838
+ let mut claim_requests = HashMap :: new ( ) ;
1813
1839
for tx in txn_matched {
1814
1840
if tx. input . len ( ) == 1 {
1815
1841
// Assuming our keys were not leaked (in which case we're screwed no matter what),
@@ -1827,14 +1853,14 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1827
1853
} ;
1828
1854
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 ) {
1829
1855
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) ;
1831
1857
if !new_outputs. 1 . is_empty ( ) {
1832
1858
watch_outputs. push ( new_outputs) ;
1833
1859
}
1834
1860
if let Some ( spendable_output) = spendable_output {
1835
1861
spendable_outputs. push ( spendable_output) ;
1836
1862
}
1837
- if new_outpoints . is_empty ( ) {
1863
+ if new_claim_requests . is_empty ( ) {
1838
1864
let ( local_txn, mut spendable_output, new_outputs) = self . check_spend_local_transaction ( & tx, height) ;
1839
1865
spendable_outputs. append ( & mut spendable_output) ;
1840
1866
for tx in local_txn. iter ( ) {
@@ -1845,23 +1871,23 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1845
1871
watch_outputs. push ( new_outputs) ;
1846
1872
}
1847
1873
}
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) ;
1850
1876
}
1851
1877
}
1852
- if !funding_txo. is_none ( ) && claimable_outpoints . is_empty ( ) {
1878
+ if !funding_txo. is_none ( ) && claim_requests . is_empty ( ) {
1853
1879
if let Some ( spendable_output) = self . check_spend_closing_transaction ( & tx) {
1854
1880
spendable_outputs. push ( spendable_output) ;
1855
1881
}
1856
1882
}
1857
1883
} else {
1858
1884
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) ;
1862
1888
}
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) ;
1865
1891
}
1866
1892
}
1867
1893
}
@@ -1918,7 +1944,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
1918
1944
}
1919
1945
}
1920
1946
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) ;
1922
1948
spendable_outputs. append ( & mut spendable_output) ;
1923
1949
1924
1950
self . last_block_hash = block_hash. clone ( ) ;
0 commit comments