@@ -32,7 +32,7 @@ use util::logger::Logger;
32
32
use util:: ser:: { Readable , ReadableArgs , Writer , Writeable , VecWriter } ;
33
33
use util:: byte_utils;
34
34
35
- use std:: collections:: HashMap ;
35
+ use std:: collections:: { BTreeMap , HashMap } ;
36
36
use core:: cmp;
37
37
use core:: ops:: Deref ;
38
38
use core:: mem:: replace;
@@ -164,8 +164,9 @@ pub struct OnchainTxHandler<ChannelSigner: Sign> {
164
164
#[ cfg( not( test) ) ]
165
165
claimable_outpoints : HashMap < BitcoinOutPoint , ( Txid , u32 ) > ,
166
166
167
- onchain_events_awaiting_threshold_conf : Vec < OnchainEventEntry > ,
167
+ locktimed_packages : BTreeMap < u32 , Vec < PackageTemplate > > ,
168
168
169
+ onchain_events_awaiting_threshold_conf : Vec < OnchainEventEntry > ,
169
170
170
171
pub ( super ) secp_ctx : Secp256k1 < secp256k1:: All > ,
171
172
}
@@ -205,6 +206,15 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
205
206
claim_and_height. 1 . write ( writer) ?;
206
207
}
207
208
209
+ writer. write_all ( & byte_utils:: be64_to_array ( self . locktimed_packages . len ( ) as u64 ) ) ?;
210
+ for ( ref locktime, ref packages) in self . locktimed_packages . iter ( ) {
211
+ locktime. write ( writer) ?;
212
+ writer. write_all ( & byte_utils:: be64_to_array ( packages. len ( ) as u64 ) ) ?;
213
+ for ref package in packages. iter ( ) {
214
+ package. write ( writer) ?;
215
+ }
216
+ }
217
+
208
218
writer. write_all ( & byte_utils:: be64_to_array ( self . onchain_events_awaiting_threshold_conf . len ( ) as u64 ) ) ?;
209
219
for ref entry in self . onchain_events_awaiting_threshold_conf . iter ( ) {
210
220
entry. txid . write ( writer) ?;
@@ -264,6 +274,19 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::Signer> {
264
274
let height = Readable :: read ( reader) ?;
265
275
claimable_outpoints. insert ( outpoint, ( ancestor_claim_txid, height) ) ;
266
276
}
277
+
278
+ let locktimed_packages_len: u64 = Readable :: read ( reader) ?;
279
+ let mut locktimed_packages = BTreeMap :: new ( ) ;
280
+ for _ in 0 ..locktimed_packages_len {
281
+ let locktime = Readable :: read ( reader) ?;
282
+ let packages_len: u64 = Readable :: read ( reader) ?;
283
+ let mut packages = Vec :: with_capacity ( cmp:: min ( packages_len as usize , MAX_ALLOC_SIZE / std:: mem:: size_of :: < PackageTemplate > ( ) ) ) ;
284
+ for _ in 0 ..packages_len {
285
+ packages. push ( Readable :: read ( reader) ?) ;
286
+ }
287
+ locktimed_packages. insert ( locktime, packages) ;
288
+ }
289
+
267
290
let waiting_threshold_conf_len: u64 = Readable :: read ( reader) ?;
268
291
let mut onchain_events_awaiting_threshold_conf = Vec :: with_capacity ( cmp:: min ( waiting_threshold_conf_len as usize , MAX_ALLOC_SIZE / 128 ) ) ;
269
292
for _ in 0 ..waiting_threshold_conf_len {
@@ -301,6 +324,7 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::Signer> {
301
324
signer,
302
325
channel_transaction_parameters : channel_parameters,
303
326
claimable_outpoints,
327
+ locktimed_packages,
304
328
pending_claim_requests,
305
329
onchain_events_awaiting_threshold_conf,
306
330
secp_ctx,
@@ -320,6 +344,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
320
344
channel_transaction_parameters : channel_parameters,
321
345
pending_claim_requests : HashMap :: new ( ) ,
322
346
claimable_outpoints : HashMap :: new ( ) ,
347
+ locktimed_packages : BTreeMap :: new ( ) ,
323
348
onchain_events_awaiting_threshold_conf : Vec :: new ( ) ,
324
349
325
350
secp_ctx,
@@ -375,9 +400,17 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
375
400
376
401
// Try to aggregate outputs if their timelock expiration isn't imminent (package timelock
377
402
// <= CLTV_SHARED_CLAIM_BUFFER) and they don't require an immediate nLockTime (aggregable).
378
- for req in requests {
403
+ ' req_walk : for req in requests {
379
404
// Don't claim a outpoint twice that would be bad for privacy and may uselessly lock a CPFP input for a while
380
- if let Some ( _) = self . claimable_outpoints . get ( req. outpoints ( ) [ 0 ] ) { log_trace ! ( logger, "Bouncing off outpoint {}:{}, already registered its claiming request" , req. outpoints( ) [ 0 ] . txid, req. outpoints( ) [ 0 ] . vout) ; } else {
405
+ if let Some ( _) = self . claimable_outpoints . get ( req. outpoints ( ) [ 0 ] ) {
406
+ log_trace ! ( logger, "Bouncing off outpoint {}:{}, already registered its claiming request" , req. outpoints( ) [ 0 ] . txid, req. outpoints( ) [ 0 ] . vout) ;
407
+ } else {
408
+ for locked_package in self . locktimed_packages . iter ( ) . map ( |v| v. 1 . iter ( ) ) . flatten ( ) {
409
+ if locked_package. outpoints ( ) == req. outpoints ( ) {
410
+ continue ' req_walk;
411
+ }
412
+ }
413
+
381
414
log_trace ! ( logger, "Test if outpoint can be aggregated with expiration {} against {}" , req. timelock( ) , height + CLTV_SHARED_CLAIM_BUFFER ) ;
382
415
if req. timelock ( ) <= height + CLTV_SHARED_CLAIM_BUFFER || !req. aggregable ( ) {
383
416
// Don't aggregate if outpoint package timelock is soon or marked as non-aggregable
@@ -393,10 +426,26 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
393
426
preprocessed_requests. push ( req) ;
394
427
}
395
428
429
+ loop {
430
+ let pop_height = if let Some ( first_entry) = self . locktimed_packages . iter ( ) . next ( ) {
431
+ if * first_entry. 0 <= height + 1 {
432
+ * first_entry. 0
433
+ } else { break ; }
434
+ } else { break ; } ;
435
+ log_trace ! ( logger, "Restoring delayed claim of package(s) at their timelock at {}." , pop_height) ;
436
+ preprocessed_requests. append ( & mut self . locktimed_packages . remove ( & pop_height) . unwrap ( ) ) ;
437
+ }
438
+
396
439
// Generate claim transactions and track them to bump if necessary at
397
440
// height timer expiration (i.e in how many blocks we're going to take action).
398
441
for mut req in preprocessed_requests {
399
- if let Some ( ( new_timer, new_feerate, tx) ) = self . generate_claim_tx ( height, & req, & * fee_estimator, & * logger) {
442
+ if req. package_timelock ( ) > height + 1 {
443
+ log_debug ! ( logger, "Delaying claim of package until its timelock at {} (current height {}), the following outpoints are spent:" , req. package_timelock( ) , height) ;
444
+ for outpoint in req. outpoints ( ) {
445
+ log_debug ! ( logger, " Outpoint {}" , outpoint) ;
446
+ }
447
+ self . locktimed_packages . entry ( req. package_timelock ( ) ) . or_insert ( Vec :: new ( ) ) . push ( req) ;
448
+ } else if let Some ( ( new_timer, new_feerate, tx) ) = self . generate_claim_tx ( height, & req, & * fee_estimator, & * logger) {
400
449
req. set_timer ( new_timer) ;
401
450
req. set_feerate ( new_feerate) ;
402
451
let txid = tx. txid ( ) ;
0 commit comments