@@ -107,7 +107,7 @@ pub use error::Error as NodeError;
107
107
use error:: Error ;
108
108
109
109
pub use event:: Event ;
110
- pub use types:: ChannelConfig ;
110
+ pub use types:: { BestBlock , ChannelConfig } ;
111
111
112
112
pub use io:: utils:: generate_entropy_mnemonic;
113
113
@@ -164,8 +164,9 @@ use rand::Rng;
164
164
165
165
use std:: default:: Default ;
166
166
use std:: net:: ToSocketAddrs ;
167
+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
167
168
use std:: sync:: { Arc , Mutex , RwLock } ;
168
- use std:: time:: { Duration , Instant , SystemTime } ;
169
+ use std:: time:: { Duration , Instant , SystemTime , UNIX_EPOCH } ;
169
170
170
171
#[ cfg( feature = "uniffi" ) ]
171
172
uniffi:: include_scaffolding!( "ldk_node" ) ;
@@ -196,6 +197,12 @@ pub struct Node {
196
197
scorer : Arc < Mutex < Scorer > > ,
197
198
peer_store : Arc < PeerStore < Arc < FilesystemLogger > > > ,
198
199
payment_store : Arc < PaymentStore < Arc < FilesystemLogger > > > ,
200
+ is_listening : Arc < AtomicBool > ,
201
+ latest_wallet_sync_timestamp : Arc < RwLock < Option < u64 > > > ,
202
+ latest_onchain_wallet_sync_timestamp : Arc < RwLock < Option < u64 > > > ,
203
+ latest_fee_rate_cache_update_timestamp : Arc < RwLock < Option < u64 > > > ,
204
+ latest_rgs_snapshot_timestamp : Arc < RwLock < Option < u64 > > > ,
205
+ latest_node_announcement_broadcast_timestamp : Arc < RwLock < Option < u64 > > > ,
199
206
}
200
207
201
208
impl Node {
@@ -219,6 +226,8 @@ impl Node {
219
226
// Block to ensure we update our fee rate cache once on startup
220
227
let fee_estimator = Arc :: clone ( & self . fee_estimator ) ;
221
228
let sync_logger = Arc :: clone ( & self . logger ) ;
229
+ let sync_fee_rate_update_timestamp =
230
+ Arc :: clone ( & self . latest_fee_rate_cache_update_timestamp ) ;
222
231
let runtime_ref = & runtime;
223
232
tokio:: task:: block_in_place ( move || {
224
233
runtime_ref. block_on ( async move {
@@ -230,6 +239,9 @@ impl Node {
230
239
"Initial fee rate cache update finished in {}ms." ,
231
240
now. elapsed( ) . as_millis( )
232
241
) ;
242
+ let unix_time_secs_opt =
243
+ SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . ok ( ) . map ( |d| d. as_secs ( ) ) ;
244
+ * sync_fee_rate_update_timestamp. write ( ) . unwrap ( ) = unix_time_secs_opt;
233
245
Ok ( ( ) )
234
246
} ,
235
247
Err ( e) => {
@@ -243,6 +255,7 @@ impl Node {
243
255
// Setup wallet sync
244
256
let wallet = Arc :: clone ( & self . wallet ) ;
245
257
let sync_logger = Arc :: clone ( & self . logger ) ;
258
+ let sync_onchain_wallet_timestamp = Arc :: clone ( & self . latest_onchain_wallet_sync_timestamp ) ;
246
259
let mut stop_sync = self . stop_sender . subscribe ( ) ;
247
260
let onchain_wallet_sync_interval_secs = self
248
261
. config
@@ -264,11 +277,16 @@ impl Node {
264
277
_ = onchain_wallet_sync_interval. tick( ) => {
265
278
let now = Instant :: now( ) ;
266
279
match wallet. sync( ) . await {
267
- Ok ( ( ) ) => log_trace!(
280
+ Ok ( ( ) ) => {
281
+ log_trace!(
268
282
sync_logger,
269
283
"Background sync of on-chain wallet finished in {}ms." ,
270
284
now. elapsed( ) . as_millis( )
271
- ) ,
285
+ ) ;
286
+ let unix_time_secs_opt =
287
+ SystemTime :: now( ) . duration_since( UNIX_EPOCH ) . ok( ) . map( |d| d. as_secs( ) ) ;
288
+ * sync_onchain_wallet_timestamp. write( ) . unwrap( ) = unix_time_secs_opt;
289
+ }
272
290
Err ( err) => {
273
291
log_error!(
274
292
sync_logger,
@@ -286,6 +304,7 @@ impl Node {
286
304
287
305
let mut stop_fee_updates = self . stop_sender . subscribe ( ) ;
288
306
let fee_update_logger = Arc :: clone ( & self . logger ) ;
307
+ let fee_update_timestamp = Arc :: clone ( & self . latest_fee_rate_cache_update_timestamp ) ;
289
308
let fee_estimator = Arc :: clone ( & self . fee_estimator ) ;
290
309
let fee_rate_cache_update_interval_secs =
291
310
self . config . fee_rate_cache_update_interval_secs . max ( WALLET_SYNC_INTERVAL_MINIMUM_SECS ) ;
@@ -304,11 +323,16 @@ impl Node {
304
323
_ = fee_rate_update_interval. tick( ) => {
305
324
let now = Instant :: now( ) ;
306
325
match fee_estimator. update_fee_estimates( ) . await {
307
- Ok ( ( ) ) => log_trace!(
326
+ Ok ( ( ) ) => {
327
+ log_trace!(
308
328
fee_update_logger,
309
329
"Background update of fee rate cache finished in {}ms." ,
310
330
now. elapsed( ) . as_millis( )
311
- ) ,
331
+ ) ;
332
+ let unix_time_secs_opt =
333
+ SystemTime :: now( ) . duration_since( UNIX_EPOCH ) . ok( ) . map( |d| d. as_secs( ) ) ;
334
+ * fee_update_timestamp. write( ) . unwrap( ) = unix_time_secs_opt;
335
+ }
312
336
Err ( err) => {
313
337
log_error!(
314
338
fee_update_logger,
@@ -327,6 +351,7 @@ impl Node {
327
351
let sync_cmon = Arc :: clone ( & self . chain_monitor ) ;
328
352
let sync_sweeper = Arc :: clone ( & self . output_sweeper ) ;
329
353
let sync_logger = Arc :: clone ( & self . logger ) ;
354
+ let sync_wallet_timestamp = Arc :: clone ( & self . latest_wallet_sync_timestamp ) ;
330
355
let mut stop_sync = self . stop_sender . subscribe ( ) ;
331
356
let wallet_sync_interval_secs =
332
357
self . config . wallet_sync_interval_secs . max ( WALLET_SYNC_INTERVAL_MINIMUM_SECS ) ;
@@ -347,11 +372,16 @@ impl Node {
347
372
] ;
348
373
let now = Instant :: now( ) ;
349
374
match tx_sync. sync( confirmables) . await {
350
- Ok ( ( ) ) => log_trace!(
375
+ Ok ( ( ) ) => {
376
+ log_trace!(
351
377
sync_logger,
352
378
"Background sync of Lightning wallet finished in {}ms." ,
353
379
now. elapsed( ) . as_millis( )
354
- ) ,
380
+ ) ;
381
+ let unix_time_secs_opt =
382
+ SystemTime :: now( ) . duration_since( UNIX_EPOCH ) . ok( ) . map( |d| d. as_secs( ) ) ;
383
+ * sync_wallet_timestamp. write( ) . unwrap( ) = unix_time_secs_opt;
384
+ }
355
385
Err ( e) => {
356
386
log_error!( sync_logger, "Background sync of Lightning wallet failed: {}" , e)
357
387
}
@@ -365,6 +395,7 @@ impl Node {
365
395
let gossip_source = Arc :: clone ( & self . gossip_source ) ;
366
396
let gossip_sync_store = Arc :: clone ( & self . kv_store ) ;
367
397
let gossip_sync_logger = Arc :: clone ( & self . logger ) ;
398
+ let gossip_rgs_sync_timestamp = Arc :: clone ( & self . latest_rgs_snapshot_timestamp ) ;
368
399
let mut stop_gossip_sync = self . stop_sender . subscribe ( ) ;
369
400
runtime. spawn ( async move {
370
401
let mut interval = tokio:: time:: interval ( RGS_SYNC_INTERVAL ) ;
@@ -392,6 +423,7 @@ impl Node {
392
423
log_error!( gossip_sync_logger, "Persistence failed: {}" , e) ;
393
424
panic!( "Persistence failed" ) ;
394
425
} ) ;
426
+ * gossip_rgs_sync_timestamp. write( ) . unwrap( ) = Some ( updated_timestamp as u64 ) ;
395
427
}
396
428
Err ( e) => log_error!(
397
429
gossip_sync_logger,
@@ -410,6 +442,7 @@ impl Node {
410
442
let peer_manager_connection_handler = Arc :: clone ( & self . peer_manager ) ;
411
443
let mut stop_listen = self . stop_sender . subscribe ( ) ;
412
444
let listening_logger = Arc :: clone ( & self . logger ) ;
445
+ let listening_indicator = Arc :: clone ( & self . is_listening ) ;
413
446
414
447
let mut bind_addrs = Vec :: with_capacity ( listening_addresses. len ( ) ) ;
415
448
@@ -428,6 +461,7 @@ impl Node {
428
461
}
429
462
430
463
runtime. spawn ( async move {
464
+ {
431
465
let listener =
432
466
tokio:: net:: TcpListener :: bind ( & * bind_addrs) . await
433
467
. unwrap_or_else ( |e| {
@@ -437,11 +471,13 @@ impl Node {
437
471
) ;
438
472
} ) ;
439
473
474
+ listening_indicator. store ( true , Ordering :: Release ) ;
475
+
440
476
loop {
441
477
let peer_mgr = Arc :: clone ( & peer_manager_connection_handler) ;
442
478
tokio:: select! {
443
479
_ = stop_listen. changed( ) => {
444
- return ;
480
+ break ;
445
481
}
446
482
res = listener. accept( ) => {
447
483
let tcp_stream = res. unwrap( ) . 0 ;
@@ -455,6 +491,9 @@ impl Node {
455
491
}
456
492
}
457
493
}
494
+ }
495
+
496
+ listening_indicator. store ( false , Ordering :: Release ) ;
458
497
} ) ;
459
498
}
460
499
@@ -505,6 +544,7 @@ impl Node {
505
544
let bcast_config = Arc :: clone ( & self . config ) ;
506
545
let bcast_store = Arc :: clone ( & self . kv_store ) ;
507
546
let bcast_logger = Arc :: clone ( & self . logger ) ;
547
+ let bcast_ann_timestamp = Arc :: clone ( & self . latest_node_announcement_broadcast_timestamp ) ;
508
548
let mut stop_bcast = self . stop_sender . subscribe ( ) ;
509
549
runtime. spawn ( async move {
510
550
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
@@ -550,12 +590,17 @@ impl Node {
550
590
551
591
bcast_pm. broadcast_node_announcement( [ 0 ; 3 ] , [ 0 ; 32 ] , addresses) ;
552
592
553
- let unix_time_secs = SystemTime :: now( ) . duration_since( SystemTime :: UNIX_EPOCH ) . unwrap( ) . as_secs( ) ;
554
- io:: utils:: write_latest_node_ann_bcast_timestamp( unix_time_secs, Arc :: clone( & bcast_store) , Arc :: clone( & bcast_logger) )
555
- . unwrap_or_else( |e| {
556
- log_error!( bcast_logger, "Persistence failed: {}" , e) ;
557
- panic!( "Persistence failed" ) ;
558
- } ) ;
593
+ let unix_time_secs_opt =
594
+ SystemTime :: now( ) . duration_since( UNIX_EPOCH ) . ok( ) . map( |d| d. as_secs( ) ) ;
595
+ * bcast_ann_timestamp. write( ) . unwrap( ) = unix_time_secs_opt;
596
+
597
+ if let Some ( unix_time_secs) = unix_time_secs_opt {
598
+ io:: utils:: write_latest_node_ann_bcast_timestamp( unix_time_secs, Arc :: clone( & bcast_store) , Arc :: clone( & bcast_logger) )
599
+ . unwrap_or_else( |e| {
600
+ log_error!( bcast_logger, "Persistence failed: {}" , e) ;
601
+ panic!( "Persistence failed" ) ;
602
+ } ) ;
603
+ }
559
604
}
560
605
}
561
606
}
@@ -659,11 +704,6 @@ impl Node {
659
704
Ok ( ( ) )
660
705
}
661
706
662
- /// Returns whether the [`Node`] is running.
663
- pub fn is_running ( & self ) -> bool {
664
- self . runtime . read ( ) . unwrap ( ) . is_some ( )
665
- }
666
-
667
707
/// Disconnects all peers, stops all running background tasks, and shuts down [`Node`].
668
708
///
669
709
/// After this returns most API methods will return [`Error::NotRunning`].
@@ -694,6 +734,32 @@ impl Node {
694
734
Ok ( ( ) )
695
735
}
696
736
737
+ /// Returns the status of the [`Node`].
738
+ pub fn status ( & self ) -> NodeStatus {
739
+ let is_running = self . runtime . read ( ) . unwrap ( ) . is_some ( ) ;
740
+ let is_listening = self . is_listening . load ( Ordering :: Acquire ) ;
741
+ let current_best_block = self . channel_manager . current_best_block ( ) . into ( ) ;
742
+ let latest_wallet_sync_timestamp = * self . latest_wallet_sync_timestamp . read ( ) . unwrap ( ) ;
743
+ let latest_onchain_wallet_sync_timestamp =
744
+ * self . latest_onchain_wallet_sync_timestamp . read ( ) . unwrap ( ) ;
745
+ let latest_fee_rate_cache_update_timestamp =
746
+ * self . latest_fee_rate_cache_update_timestamp . read ( ) . unwrap ( ) ;
747
+ let latest_rgs_snapshot_timestamp = * self . latest_rgs_snapshot_timestamp . read ( ) . unwrap ( ) ;
748
+ let latest_node_announcement_broadcast_timestamp =
749
+ * self . latest_node_announcement_broadcast_timestamp . read ( ) . unwrap ( ) ;
750
+
751
+ NodeStatus {
752
+ is_running,
753
+ is_listening,
754
+ current_best_block,
755
+ latest_wallet_sync_timestamp,
756
+ latest_onchain_wallet_sync_timestamp,
757
+ latest_fee_rate_cache_update_timestamp,
758
+ latest_rgs_snapshot_timestamp,
759
+ latest_node_announcement_broadcast_timestamp,
760
+ }
761
+ }
762
+
697
763
/// Returns the next event in the event queue, if currently available.
698
764
///
699
765
/// Will return `Some(..)` if an event is available and `None` otherwise.
@@ -1740,8 +1806,50 @@ impl Drop for Node {
1740
1806
}
1741
1807
}
1742
1808
1809
+ <<<<<<< HEAD
1743
1810
async fn connect_peer_if_necessary (
1744
1811
node_id : PublicKey , addr : SocketAddress , peer_manager : Arc < PeerManager > ,
1812
+ =======
1813
+ /// Represents the status of the [`Node`].
1814
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
1815
+ pub struct NodeStatus {
1816
+ /// Indicates whether the [`Node`] is running.
1817
+ pub is_running : bool,
1818
+ /// Indicates whether the [`Node`] is listening for incoming connections on the addresses
1819
+ /// configured via [`Config::listening_addresses`].
1820
+ pub is_listening : bool,
1821
+ /// The best block to which our Lightning wallet is currently synced.
1822
+ pub current_best_block : BestBlock ,
1823
+ /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced
1824
+ /// our Lightning wallet to the chain tip.
1825
+ ///
1826
+ /// Will be `None` if the wallet hasn't been synced since the [`Node`] was initialized.
1827
+ pub latest_wallet_sync_timestamp : Option < u64 > ,
1828
+ /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced
1829
+ /// our on-chain wallet to the chain tip.
1830
+ ///
1831
+ /// Will be `None` if the wallet hasn't been synced since the [`Node`] was initialized.
1832
+ pub latest_onchain_wallet_sync_timestamp: Option < u64 > ,
1833
+ /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully update
1834
+ /// our fee rate cache.
1835
+ ///
1836
+ /// Will be `None` if the cache hasn't been updated since the [`Node`] was initialized.
1837
+ pub latest_fee_rate_cache_update_timestamp: Option < u64 > ,
1838
+ /// The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync
1839
+ /// (RGS) snapshot we successfully applied was generated.
1840
+ ///
1841
+ /// Will be `None` if RGS isn't configured or the snapshot hasn't been updated since the [`Node`] was initialized.
1842
+ pub latest_rgs_snapshot_timestamp: Option < u64 > ,
1843
+ /// The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node
1844
+ /// announcement.
1845
+ ///
1846
+ /// Will be `None` if we have no public channels or we haven't broadcasted since the [`Node`] was initialized.
1847
+ pub latest_node_announcement_broadcast_timestamp: Option < u64 > ,
1848
+ }
1849
+
1850
+ async fn connect_peer_if_necessary < K : KVStore + Sync + Send + ' static > (
1851
+ node_id: PublicKey , addr : SocketAddress , peer_manager : Arc < PeerManager < K > > ,
1852
+ >>>>>>> 98 f2c5a ( Introduce `status` method allowing to query the `Node `' s status)
1745
1853
logger: Arc < FilesystemLogger > ,
1746
1854
) -> Result < ( ) , Error > {
1747
1855
if peer_manager. peer_by_node_id( & node_id) . is_some( ) {
0 commit comments