1
- use crate :: common:: { ConfirmedTx , SyncState , FilterQueue } ;
2
- use crate :: error:: { TxSyncError , InternalError } ;
1
+ use crate :: common:: { ConfirmedTx , FilterQueue , SyncState } ;
2
+ use crate :: error:: { InternalError , TxSyncError } ;
3
3
4
4
use electrum_client:: Client as ElectrumClient ;
5
5
use electrum_client:: ElectrumApi ;
6
6
use electrum_client:: GetMerkleRes ;
7
7
8
- use lightning:: util:: logger:: Logger ;
9
- use lightning:: { log_error, log_debug, log_trace} ;
10
8
use lightning:: chain:: WatchedOutput ;
11
9
use lightning:: chain:: { Confirm , Filter } ;
10
+ use lightning:: util:: logger:: Logger ;
11
+ use lightning:: { log_debug, log_error, log_trace} ;
12
12
13
- use bitcoin:: { BlockHash , Script , Transaction , Txid } ;
14
13
use bitcoin:: block:: Header ;
15
14
use bitcoin:: hash_types:: TxMerkleNode ;
16
- use bitcoin:: hashes:: Hash ;
17
15
use bitcoin:: hashes:: sha256d:: Hash as Sha256d ;
16
+ use bitcoin:: hashes:: Hash ;
17
+ use bitcoin:: { BlockHash , Script , Transaction , Txid } ;
18
18
19
+ use std:: collections:: HashSet ;
19
20
use std:: ops:: Deref ;
20
21
use std:: sync:: Mutex ;
21
- use std:: collections:: HashSet ;
22
22
use std:: time:: Instant ;
23
23
24
24
/// Synchronizes LDK with a given Electrum server.
64
64
let sync_state = Mutex :: new ( SyncState :: new ( ) ) ;
65
65
let queue = Mutex :: new ( FilterQueue :: new ( ) ) ;
66
66
67
- Ok ( Self {
68
- sync_state,
69
- queue,
70
- client,
71
- logger,
72
- } )
67
+ Ok ( Self { sync_state, queue, client, logger } )
73
68
}
74
69
75
70
/// Synchronizes the given `confirmables` via their [`Confirm`] interface implementations. This
84
79
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
85
80
/// [`Filter`]: lightning::chain::Filter
86
81
pub fn sync < C : Deref > ( & self , confirmables : Vec < C > ) -> Result < ( ) , TxSyncError >
87
- where C :: Target : Confirm
82
+ where
83
+ C :: Target : Confirm ,
88
84
{
89
85
// This lock makes sure we're syncing once at a time.
90
86
let mut sync_state = self . sync_state . lock ( ) . unwrap ( ) ;
@@ -124,15 +120,15 @@ where
124
120
num_unconfirmed += unconfirmed_txs. len ( ) ;
125
121
sync_state. sync_unconfirmed_transactions (
126
122
& confirmables,
127
- unconfirmed_txs
123
+ unconfirmed_txs,
128
124
) ;
129
- }
125
+ } ,
130
126
Ok ( true ) => {
131
127
log_debug ! ( self . logger,
132
128
"Encountered inconsistency during transaction sync, restarting." ) ;
133
129
sync_state. pending_sync = true ;
134
130
continue ;
135
- }
131
+ } ,
136
132
Err ( err) => {
137
133
// (Semi-)permanent failure, retry later.
138
134
log_error ! ( self . logger,
@@ -142,7 +138,7 @@ where
142
138
) ;
143
139
sync_state. pending_sync = true ;
144
140
return Err ( TxSyncError :: from ( err) ) ;
145
- }
141
+ } ,
146
142
}
147
143
} ,
148
144
Err ( err) => {
@@ -154,7 +150,7 @@ where
154
150
) ;
155
151
sync_state. pending_sync = true ;
156
152
return Err ( TxSyncError :: from ( err) ) ;
157
- }
153
+ } ,
158
154
}
159
155
160
156
// Update the best block.
@@ -173,17 +169,15 @@ where
173
169
match self . check_update_tip ( & mut tip_header, & mut tip_height) {
174
170
Ok ( false ) => {
175
171
num_confirmed += confirmed_txs. len ( ) ;
176
- sync_state. sync_confirmed_transactions (
177
- & confirmables,
178
- confirmed_txs
179
- ) ;
180
- }
172
+ sync_state
173
+ . sync_confirmed_transactions ( & confirmables, confirmed_txs) ;
174
+ } ,
181
175
Ok ( true ) => {
182
176
log_debug ! ( self . logger,
183
177
"Encountered inconsistency during transaction sync, restarting." ) ;
184
178
sync_state. pending_sync = true ;
185
179
continue ;
186
- }
180
+ } ,
187
181
Err ( err) => {
188
182
// (Semi-)permanent failure, retry later.
189
183
log_error ! ( self . logger,
@@ -193,16 +187,18 @@ where
193
187
) ;
194
188
sync_state. pending_sync = true ;
195
189
return Err ( TxSyncError :: from ( err) ) ;
196
- }
190
+ } ,
197
191
}
198
- }
192
+ } ,
199
193
Err ( InternalError :: Inconsistency ) => {
200
194
// Immediately restart syncing when we encounter any inconsistencies.
201
- log_debug ! ( self . logger,
202
- "Encountered inconsistency during transaction sync, restarting." ) ;
195
+ log_debug ! (
196
+ self . logger,
197
+ "Encountered inconsistency during transaction sync, restarting."
198
+ ) ;
203
199
sync_state. pending_sync = true ;
204
200
continue ;
205
- }
201
+ } ,
206
202
Err ( err) => {
207
203
// (Semi-)permanent failure, retry later.
208
204
log_error ! ( self . logger,
@@ -212,27 +208,35 @@ where
212
208
) ;
213
209
sync_state. pending_sync = true ;
214
210
return Err ( TxSyncError :: from ( err) ) ;
215
- }
211
+ } ,
216
212
}
217
213
sync_state. last_sync_hash = Some ( tip_header. block_hash ( ) ) ;
218
214
sync_state. pending_sync = false ;
219
215
}
220
216
}
221
217
#[ cfg( feature = "time" ) ]
222
- log_debug ! ( self . logger,
218
+ log_debug ! (
219
+ self . logger,
223
220
"Finished transaction sync at tip {} in {}ms: {} confirmed, {} unconfirmed." ,
224
- tip_header. block_hash( ) , start_time. elapsed( ) . as_millis( ) , num_confirmed,
225
- num_unconfirmed) ;
221
+ tip_header. block_hash( ) ,
222
+ start_time. elapsed( ) . as_millis( ) ,
223
+ num_confirmed,
224
+ num_unconfirmed
225
+ ) ;
226
226
#[ cfg( not( feature = "time" ) ) ]
227
- log_debug ! ( self . logger,
227
+ log_debug ! (
228
+ self . logger,
228
229
"Finished transaction sync at tip {}: {} confirmed, {} unconfirmed." ,
229
- tip_header. block_hash( ) , num_confirmed, num_unconfirmed) ;
230
+ tip_header. block_hash( ) ,
231
+ num_confirmed,
232
+ num_unconfirmed
233
+ ) ;
230
234
Ok ( ( ) )
231
235
}
232
236
233
- fn check_update_tip ( & self , cur_tip_header : & mut Header , cur_tip_height : & mut u32 )
234
- -> Result < bool , InternalError >
235
- {
237
+ fn check_update_tip (
238
+ & self , cur_tip_header : & mut Header , cur_tip_height : & mut u32 ,
239
+ ) -> Result < bool , InternalError > {
236
240
let check_notification = self . client . block_headers_subscribe ( ) ?;
237
241
let check_tip_hash = check_notification. header . block_hash ( ) ;
238
242
@@ -258,12 +262,12 @@ where
258
262
fn get_confirmed_transactions (
259
263
& self , sync_state : & SyncState ,
260
264
) -> Result < Vec < ConfirmedTx > , InternalError > {
261
-
262
265
// First, check the confirmation status of registered transactions as well as the
263
266
// status of dependent transactions of registered outputs.
264
267
let mut confirmed_txs: Vec < ConfirmedTx > = Vec :: new ( ) ;
265
268
let mut watched_script_pubkeys = Vec :: with_capacity (
266
- sync_state. watched_transactions . len ( ) + sync_state. watched_outputs . len ( ) ) ;
269
+ sync_state. watched_transactions . len ( ) + sync_state. watched_outputs . len ( ) ,
270
+ ) ;
267
271
let mut watched_txs = Vec :: with_capacity ( sync_state. watched_transactions . len ( ) ) ;
268
272
269
273
for txid in & sync_state. watched_transactions {
@@ -280,14 +284,14 @@ where
280
284
log_error ! ( self . logger, "Failed due to retrieving invalid tx data." ) ;
281
285
return Err ( InternalError :: Failed ) ;
282
286
}
283
- }
287
+ } ,
284
288
Err ( electrum_client:: Error :: Protocol ( _) ) => {
285
289
// We couldn't find the tx, do nothing.
286
- }
290
+ } ,
287
291
Err ( e) => {
288
292
log_error ! ( self . logger, "Failed to look up transaction {}: {}." , txid, e) ;
289
293
return Err ( InternalError :: Failed ) ;
290
- }
294
+ } ,
291
295
}
292
296
}
293
297
@@ -312,18 +316,18 @@ where
312
316
if confirmed_txs. iter ( ) . any ( |ctx| ctx. txid == * * txid) {
313
317
continue ;
314
318
}
315
- let mut filtered_history = script_history . iter ( ) . filter ( |h| h . tx_hash == * * txid ) ;
316
- if let Some ( history ) = filtered_history . next ( )
317
- {
319
+ let mut filtered_history =
320
+ script_history . iter ( ) . filter ( |h| h . tx_hash == * * txid ) ;
321
+ if let Some ( history ) = filtered_history . next ( ) {
318
322
let prob_conf_height = history. height as u32 ;
319
323
let confirmed_tx = self . get_confirmed_tx ( tx, prob_conf_height) ?;
320
324
confirmed_txs. push ( confirmed_tx) ;
321
325
}
322
326
debug_assert ! ( filtered_history. next( ) . is_none( ) ) ;
323
327
}
324
328
325
- for ( watched_output, script_history) in sync_state . watched_outputs . values ( )
326
- . zip ( output_results)
329
+ for ( watched_output, script_history) in
330
+ sync_state . watched_outputs . values ( ) . zip ( output_results)
327
331
{
328
332
for possible_output_spend in script_history {
329
333
if possible_output_spend. height <= 0 {
@@ -339,8 +343,8 @@ where
339
343
Ok ( tx) => {
340
344
let mut is_spend = false ;
341
345
for txin in & tx. input {
342
- let watched_outpoint = watched_output . outpoint
343
- . into_bitcoin_outpoint ( ) ;
346
+ let watched_outpoint =
347
+ watched_output . outpoint . into_bitcoin_outpoint ( ) ;
344
348
if txin. previous_output == watched_outpoint {
345
349
is_spend = true ;
346
350
break ;
@@ -354,21 +358,24 @@ where
354
358
let prob_conf_height = possible_output_spend. height as u32 ;
355
359
let confirmed_tx = self . get_confirmed_tx ( & tx, prob_conf_height) ?;
356
360
confirmed_txs. push ( confirmed_tx) ;
357
- }
361
+ } ,
358
362
Err ( e) => {
359
- log_trace ! ( self . logger,
363
+ log_trace ! (
364
+ self . logger,
360
365
"Inconsistency: Tx {} was unconfirmed during syncing: {}" ,
361
- txid, e) ;
366
+ txid,
367
+ e
368
+ ) ;
362
369
return Err ( InternalError :: Inconsistency ) ;
363
- }
370
+ } ,
364
371
}
365
372
}
366
373
}
367
- }
374
+ } ,
368
375
Err ( e) => {
369
376
log_error ! ( self . logger, "Failed to look up script histories: {}." , e) ;
370
377
return Err ( InternalError :: Failed ) ;
371
- }
378
+ } ,
372
379
}
373
380
374
381
// Sort all confirmed transactions first by block height, then by in-block
@@ -383,7 +390,8 @@ where
383
390
fn get_unconfirmed_transactions < C : Deref > (
384
391
& self , confirmables : & Vec < C > ,
385
392
) -> Result < Vec < Txid > , InternalError >
386
- where C :: Target : Confirm
393
+ where
394
+ C :: Target : Confirm ,
387
395
{
388
396
// Query the interface for relevant txids and check whether the relevant blocks are still
389
397
// in the best chain, mark them unconfirmed otherwise
@@ -412,46 +420,57 @@ where
412
420
Ok ( unconfirmed_txs)
413
421
}
414
422
415
- fn get_confirmed_tx ( & self , tx : & Transaction , prob_conf_height : u32 )
416
- -> Result < ConfirmedTx , InternalError >
417
- {
423
+ fn get_confirmed_tx (
424
+ & self , tx : & Transaction , prob_conf_height : u32 ,
425
+ ) -> Result < ConfirmedTx , InternalError > {
418
426
let txid = tx. txid ( ) ;
419
427
match self . client . transaction_get_merkle ( & txid, prob_conf_height as usize ) {
420
428
Ok ( merkle_res) => {
421
429
debug_assert_eq ! ( prob_conf_height, merkle_res. block_height as u32 ) ;
422
430
match self . client . block_header ( prob_conf_height as usize ) {
423
431
Ok ( block_header) => {
424
432
let pos = merkle_res. pos ;
425
- if !self . validate_merkle_proof ( & txid,
426
- & block_header. merkle_root , merkle_res) ?
427
- {
428
- log_trace ! ( self . logger,
433
+ if !self . validate_merkle_proof (
434
+ & txid,
435
+ & block_header. merkle_root ,
436
+ merkle_res,
437
+ ) ? {
438
+ log_trace ! (
439
+ self . logger,
429
440
"Inconsistency: Block {} was unconfirmed during syncing." ,
430
- block_header. block_hash( ) ) ;
441
+ block_header. block_hash( )
442
+ ) ;
431
443
return Err ( InternalError :: Inconsistency ) ;
432
444
}
433
445
let confirmed_tx = ConfirmedTx {
434
446
tx : tx. clone ( ) ,
435
447
txid,
436
- block_header, block_height : prob_conf_height,
448
+ block_header,
449
+ block_height : prob_conf_height,
437
450
pos,
438
451
} ;
439
452
Ok ( confirmed_tx)
440
- }
453
+ } ,
441
454
Err ( e) => {
442
- log_error ! ( self . logger,
455
+ log_error ! (
456
+ self . logger,
443
457
"Failed to retrieve block header for height {}: {}." ,
444
- prob_conf_height, e) ;
458
+ prob_conf_height,
459
+ e
460
+ ) ;
445
461
Err ( InternalError :: Failed )
446
- }
462
+ } ,
447
463
}
448
- }
464
+ } ,
449
465
Err ( e) => {
450
- log_trace ! ( self . logger,
466
+ log_trace ! (
467
+ self . logger,
451
468
"Inconsistency: Tx {} was unconfirmed during syncing: {}" ,
452
- txid, e) ;
469
+ txid,
470
+ e
471
+ ) ;
453
472
Err ( InternalError :: Inconsistency )
454
- }
473
+ } ,
455
474
}
456
475
}
457
476
@@ -462,20 +481,16 @@ where
462
481
& self . client
463
482
}
464
483
465
- fn validate_merkle_proof ( & self , txid : & Txid , merkle_root : & TxMerkleNode ,
466
- merkle_res : GetMerkleRes ) -> Result < bool , InternalError >
467
- {
484
+ fn validate_merkle_proof (
485
+ & self , txid : & Txid , merkle_root : & TxMerkleNode , merkle_res : GetMerkleRes ,
486
+ ) -> Result < bool , InternalError > {
468
487
let mut index = merkle_res. pos ;
469
488
let mut cur = txid. to_raw_hash ( ) ;
470
489
for mut bytes in merkle_res. merkle {
471
490
bytes. reverse ( ) ;
472
491
// unwrap() safety: `bytes` has len 32 so `from_slice` can never fail.
473
492
let next_hash = Sha256d :: from_slice ( & bytes) . unwrap ( ) ;
474
- let ( left, right) = if index % 2 == 0 {
475
- ( cur, next_hash)
476
- } else {
477
- ( next_hash, cur)
478
- } ;
493
+ let ( left, right) = if index % 2 == 0 { ( cur, next_hash) } else { ( next_hash, cur) } ;
479
494
480
495
let data = [ & left[ ..] , & right[ ..] ] . concat ( ) ;
481
496
cur = Sha256d :: hash ( & data) ;
0 commit comments