Skip to content

Commit 1ddb475

Browse files
committed
Introduce persisted NodeMetrics struct
Previously, we persisted some of the `latest_` fields exposed via `NodeStatus`. Here, we now refactor this via a persisted `NodeMetrics` struct which allows to persist more fields across restarts. In particular, we now persist the latest time we sync the on-chain wallet, resulting in only doing a full scan on first initialization, and doing incremental syncing afterwards. As both of these operations are really really lightweight, we don't bother to migrate the old persisted timestamps for RGS updates and node announcement broadcasts over to the new data format.
1 parent 694cd37 commit 1ddb475

File tree

6 files changed

+195
-191
lines changed

6 files changed

+195
-191
lines changed

bindings/ldk_node.udl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,12 @@ dictionary NodeStatus {
218218
boolean is_running;
219219
boolean is_listening;
220220
BestBlock current_best_block;
221-
u64? latest_wallet_sync_timestamp;
221+
u64? latest_lightning_wallet_sync_timestamp;
222222
u64? latest_onchain_wallet_sync_timestamp;
223223
u64? latest_fee_rate_cache_update_timestamp;
224224
u64? latest_rgs_snapshot_timestamp;
225225
u64? latest_node_announcement_broadcast_timestamp;
226+
u32? latest_channel_monitor_archival_height;
226227
};
227228

228229
dictionary BestBlock {

src/builder.rs

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use crate::connection::ConnectionManager;
1212
use crate::event::EventQueue;
1313
use crate::fee_estimator::OnchainFeeEstimator;
1414
use crate::gossip::GossipSource;
15-
use crate::io;
1615
use crate::io::sqlite_store::SqliteStore;
16+
use crate::io::utils::{read_node_metrics, write_node_metrics};
1717
#[cfg(any(vss, vss_test))]
1818
use crate::io::vss_store::VssStore;
1919
use crate::liquidity::LiquiditySource;
@@ -28,6 +28,7 @@ use crate::types::{
2828
};
2929
use crate::wallet::persist::KVStoreWalletPersister;
3030
use crate::wallet::Wallet;
31+
use crate::{io, NodeMetrics};
3132
use crate::{LogLevel, Node};
3233

3334
use lightning::chain::{chainmonitor, BestBlock, Watch};
@@ -554,12 +555,16 @@ fn build_with_store_internal(
554555
) -> Result<Node, BuildError> {
555556
// Initialize the status fields.
556557
let is_listening = Arc::new(AtomicBool::new(false));
557-
let latest_wallet_sync_timestamp = Arc::new(RwLock::new(None));
558-
let latest_onchain_wallet_sync_timestamp = Arc::new(RwLock::new(None));
559-
let latest_fee_rate_cache_update_timestamp = Arc::new(RwLock::new(None));
560-
let latest_rgs_snapshot_timestamp = Arc::new(RwLock::new(None));
561-
let latest_node_announcement_broadcast_timestamp = Arc::new(RwLock::new(None));
562-
let latest_channel_monitor_archival_height = Arc::new(RwLock::new(None));
558+
let node_metrics = match read_node_metrics(Arc::clone(&kv_store), Arc::clone(&logger)) {
559+
Ok(metrics) => Arc::new(RwLock::new(metrics)),
560+
Err(e) => {
561+
if e.kind() == std::io::ErrorKind::NotFound {
562+
Arc::new(RwLock::new(NodeMetrics::default()))
563+
} else {
564+
return Err(BuildError::ReadFailed);
565+
}
566+
},
567+
};
563568

564569
// Initialize the on-chain wallet and chain access
565570
let xprv = bitcoin::bip32::Xpriv::new_master(config.network, &seed_bytes).map_err(|e| {
@@ -608,12 +613,10 @@ fn build_with_store_internal(
608613
Arc::clone(&wallet),
609614
Arc::clone(&fee_estimator),
610615
Arc::clone(&tx_broadcaster),
616+
Arc::clone(&kv_store),
611617
Arc::clone(&config),
612618
Arc::clone(&logger),
613-
Arc::clone(&latest_wallet_sync_timestamp),
614-
Arc::clone(&latest_onchain_wallet_sync_timestamp),
615-
Arc::clone(&latest_fee_rate_cache_update_timestamp),
616-
latest_channel_monitor_archival_height,
619+
Arc::clone(&node_metrics),
617620
)),
618621
None => {
619622
// Default to Esplora client.
@@ -623,12 +626,10 @@ fn build_with_store_internal(
623626
Arc::clone(&wallet),
624627
Arc::clone(&fee_estimator),
625628
Arc::clone(&tx_broadcaster),
629+
Arc::clone(&kv_store),
626630
Arc::clone(&config),
627631
Arc::clone(&logger),
628-
Arc::clone(&latest_wallet_sync_timestamp),
629-
Arc::clone(&latest_onchain_wallet_sync_timestamp),
630-
Arc::clone(&latest_fee_rate_cache_update_timestamp),
631-
latest_channel_monitor_archival_height,
632+
Arc::clone(&node_metrics),
632633
))
633634
},
634635
};
@@ -820,23 +821,24 @@ fn build_with_store_internal(
820821
Arc::new(GossipSource::new_p2p(Arc::clone(&network_graph), Arc::clone(&logger)));
821822

822823
// Reset the RGS sync timestamp in case we somehow switch gossip sources
823-
io::utils::write_latest_rgs_sync_timestamp(
824-
0,
825-
Arc::clone(&kv_store),
826-
Arc::clone(&logger),
827-
)
828-
.map_err(|e| {
829-
log_error!(logger, "Failed writing to store: {}", e);
830-
BuildError::WriteFailed
831-
})?;
824+
{
825+
let mut locked_node_metrics = node_metrics.write().unwrap();
826+
locked_node_metrics.latest_rgs_snapshot_timestamp = None;
827+
write_node_metrics(
828+
&*locked_node_metrics,
829+
Arc::clone(&kv_store),
830+
Arc::clone(&logger),
831+
)
832+
.map_err(|e| {
833+
log_error!(logger, "Failed writing to store: {}", e);
834+
BuildError::WriteFailed
835+
})?;
836+
}
832837
p2p_source
833838
},
834839
GossipSourceConfig::RapidGossipSync(rgs_server) => {
835-
let latest_sync_timestamp = io::utils::read_latest_rgs_sync_timestamp(
836-
Arc::clone(&kv_store),
837-
Arc::clone(&logger),
838-
)
839-
.unwrap_or(0);
840+
let latest_sync_timestamp =
841+
node_metrics.read().unwrap().latest_rgs_snapshot_timestamp.unwrap_or(0);
840842
Arc::new(GossipSource::new_rgs(
841843
rgs_server.clone(),
842844
latest_sync_timestamp,
@@ -1021,11 +1023,7 @@ fn build_with_store_internal(
10211023
peer_store,
10221024
payment_store,
10231025
is_listening,
1024-
latest_wallet_sync_timestamp,
1025-
latest_onchain_wallet_sync_timestamp,
1026-
latest_fee_rate_cache_update_timestamp,
1027-
latest_rgs_snapshot_timestamp,
1028-
latest_node_announcement_broadcast_timestamp,
1026+
node_metrics,
10291027
})
10301028
}
10311029

src/chain/mod.rs

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ use crate::fee_estimator::{
1515
apply_post_estimation_adjustments, get_all_conf_targets, get_num_block_defaults_for_target,
1616
OnchainFeeEstimator,
1717
};
18+
use crate::io::utils::write_node_metrics;
1819
use crate::logger::{log_bytes, log_error, log_info, log_trace, FilesystemLogger, Logger};
19-
use crate::types::{Broadcaster, ChainMonitor, ChannelManager, Sweeper, Wallet};
20-
use crate::Error;
20+
use crate::types::{Broadcaster, ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet};
21+
use crate::{Error, NodeMetrics};
2122

2223
use lightning::chain::{Confirm, Filter};
2324
use lightning::util::ser::Writeable;
@@ -102,23 +103,18 @@ pub(crate) enum ChainSource {
102103
lightning_wallet_sync_status: Mutex<WalletSyncStatus>,
103104
fee_estimator: Arc<OnchainFeeEstimator>,
104105
tx_broadcaster: Arc<Broadcaster>,
106+
kv_store: Arc<DynStore>,
105107
config: Arc<Config>,
106108
logger: Arc<FilesystemLogger>,
107-
latest_wallet_sync_timestamp: Arc<RwLock<Option<u64>>>,
108-
latest_onchain_wallet_sync_timestamp: Arc<RwLock<Option<u64>>>,
109-
latest_fee_rate_cache_update_timestamp: Arc<RwLock<Option<u64>>>,
110-
latest_channel_monitor_archival_height: Arc<RwLock<Option<u32>>>,
109+
node_metrics: Arc<RwLock<NodeMetrics>>,
111110
},
112111
}
113112

114113
impl ChainSource {
115114
pub(crate) fn new_esplora(
116115
server_url: String, onchain_wallet: Arc<Wallet>, fee_estimator: Arc<OnchainFeeEstimator>,
117-
tx_broadcaster: Arc<Broadcaster>, config: Arc<Config>, logger: Arc<FilesystemLogger>,
118-
latest_wallet_sync_timestamp: Arc<RwLock<Option<u64>>>,
119-
latest_onchain_wallet_sync_timestamp: Arc<RwLock<Option<u64>>>,
120-
latest_fee_rate_cache_update_timestamp: Arc<RwLock<Option<u64>>>,
121-
latest_channel_monitor_archival_height: Arc<RwLock<Option<u32>>>,
116+
tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>, config: Arc<Config>,
117+
logger: Arc<FilesystemLogger>, node_metrics: Arc<RwLock<NodeMetrics>>,
122118
) -> Self {
123119
let mut client_builder = esplora_client::Builder::new(&server_url);
124120
client_builder = client_builder.timeout(DEFAULT_ESPLORA_CLIENT_TIMEOUT_SECS);
@@ -135,12 +131,10 @@ impl ChainSource {
135131
lightning_wallet_sync_status,
136132
fee_estimator,
137133
tx_broadcaster,
134+
kv_store,
138135
config,
139136
logger,
140-
latest_wallet_sync_timestamp,
141-
latest_onchain_wallet_sync_timestamp,
142-
latest_fee_rate_cache_update_timestamp,
143-
latest_channel_monitor_archival_height,
137+
node_metrics,
144138
}
145139
}
146140

@@ -211,8 +205,9 @@ impl ChainSource {
211205
esplora_client,
212206
onchain_wallet,
213207
onchain_wallet_sync_status,
208+
kv_store,
214209
logger,
215-
latest_onchain_wallet_sync_timestamp,
210+
node_metrics,
216211
..
217212
} => {
218213
let receiver_res = {
@@ -232,7 +227,7 @@ impl ChainSource {
232227
// If this is our first sync, do a full scan with the configured gap limit.
233228
// Otherwise just do an incremental sync.
234229
let incremental_sync =
235-
latest_onchain_wallet_sync_timestamp.read().unwrap().is_some();
230+
node_metrics.read().unwrap().latest_onchain_wallet_sync_timestamp.is_some();
236231

237232
macro_rules! get_and_apply_wallet_update {
238233
($sync_future: expr) => {{
@@ -251,8 +246,11 @@ impl ChainSource {
251246
.duration_since(UNIX_EPOCH)
252247
.ok()
253248
.map(|d| d.as_secs());
254-
*latest_onchain_wallet_sync_timestamp.write().unwrap() =
255-
unix_time_secs_opt;
249+
{
250+
let mut locked_node_metrics = node_metrics.write().unwrap();
251+
locked_node_metrics.latest_onchain_wallet_sync_timestamp = unix_time_secs_opt;
252+
write_node_metrics(&*locked_node_metrics, Arc::clone(&kv_store), Arc::clone(&logger))?;
253+
}
256254
Ok(())
257255
},
258256
Err(e) => Err(e),
@@ -327,9 +325,9 @@ impl ChainSource {
327325
Self::Esplora {
328326
tx_sync,
329327
lightning_wallet_sync_status,
328+
kv_store,
330329
logger,
331-
latest_wallet_sync_timestamp,
332-
latest_channel_monitor_archival_height,
330+
node_metrics,
333331
..
334332
} => {
335333
let sync_cman = Arc::clone(&channel_manager);
@@ -372,13 +370,24 @@ impl ChainSource {
372370
.duration_since(UNIX_EPOCH)
373371
.ok()
374372
.map(|d| d.as_secs());
375-
*latest_wallet_sync_timestamp.write().unwrap() = unix_time_secs_opt;
373+
{
374+
let mut locked_node_metrics = node_metrics.write().unwrap();
375+
locked_node_metrics.latest_lightning_wallet_sync_timestamp =
376+
unix_time_secs_opt;
377+
write_node_metrics(
378+
&*locked_node_metrics,
379+
Arc::clone(&kv_store),
380+
Arc::clone(&logger),
381+
)?;
382+
}
376383

377384
periodically_archive_fully_resolved_monitors(
378385
Arc::clone(&channel_manager),
379386
Arc::clone(&chain_monitor),
380-
Arc::clone(&latest_channel_monitor_archival_height),
381-
);
387+
Arc::clone(&kv_store),
388+
Arc::clone(&logger),
389+
Arc::clone(&node_metrics),
390+
)?;
382391
Ok(())
383392
},
384393
Err(e) => {
@@ -406,8 +415,9 @@ impl ChainSource {
406415
esplora_client,
407416
fee_estimator,
408417
config,
418+
kv_store,
409419
logger,
410-
latest_fee_rate_cache_update_timestamp,
420+
node_metrics,
411421
..
412422
} => {
413423
let now = Instant::now();
@@ -479,7 +489,15 @@ impl ChainSource {
479489
);
480490
let unix_time_secs_opt =
481491
SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs());
482-
*latest_fee_rate_cache_update_timestamp.write().unwrap() = unix_time_secs_opt;
492+
{
493+
let mut locked_node_metrics = node_metrics.write().unwrap();
494+
locked_node_metrics.latest_fee_rate_cache_update_timestamp = unix_time_secs_opt;
495+
write_node_metrics(
496+
&*locked_node_metrics,
497+
Arc::clone(&kv_store),
498+
Arc::clone(&logger),
499+
)?;
500+
}
483501

484502
Ok(())
485503
},
@@ -580,16 +598,19 @@ impl Filter for ChainSource {
580598

581599
fn periodically_archive_fully_resolved_monitors(
582600
channel_manager: Arc<ChannelManager>, chain_monitor: Arc<ChainMonitor>,
583-
latest_channel_monitor_archival_height: Arc<RwLock<Option<u32>>>,
584-
) {
585-
let mut latest_archival_height_lock = latest_channel_monitor_archival_height.write().unwrap();
601+
kv_store: Arc<DynStore>, logger: Arc<FilesystemLogger>, node_metrics: Arc<RwLock<NodeMetrics>>,
602+
) -> Result<(), Error> {
603+
let mut locked_node_metrics = node_metrics.write().unwrap();
586604
let cur_height = channel_manager.current_best_block().height;
587-
let should_archive = latest_archival_height_lock
605+
let should_archive = locked_node_metrics
606+
.latest_channel_monitor_archival_height
588607
.as_ref()
589608
.map_or(true, |h| cur_height >= h + RESOLVED_CHANNEL_MONITOR_ARCHIVAL_INTERVAL);
590609

591610
if should_archive {
592611
chain_monitor.archive_fully_resolved_channel_monitors();
593-
*latest_archival_height_lock = Some(cur_height);
612+
locked_node_metrics.latest_channel_monitor_archival_height = Some(cur_height);
613+
write_node_metrics(&*locked_node_metrics, kv_store, logger)?;
594614
}
615+
Ok(())
595616
}

src/io/mod.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,10 @@ pub(crate) const DEPRECATED_SPENDABLE_OUTPUT_INFO_PERSISTENCE_PRIMARY_NAMESPACE:
3333
"spendable_outputs";
3434
pub(crate) const DEPRECATED_SPENDABLE_OUTPUT_INFO_PERSISTENCE_SECONDARY_NAMESPACE: &str = "";
3535

36-
/// RapidGossipSync's `latest_sync_timestamp` will be persisted under this key.
37-
pub(crate) const LATEST_RGS_SYNC_TIMESTAMP_PRIMARY_NAMESPACE: &str = "";
38-
pub(crate) const LATEST_RGS_SYNC_TIMESTAMP_SECONDARY_NAMESPACE: &str = "";
39-
pub(crate) const LATEST_RGS_SYNC_TIMESTAMP_KEY: &str = "latest_rgs_sync_timestamp";
40-
41-
/// The last time we broadcast a node announcement will be persisted under this key.
42-
pub(crate) const LATEST_NODE_ANN_BCAST_TIMESTAMP_PRIMARY_NAMESPACE: &str = "";
43-
pub(crate) const LATEST_NODE_ANN_BCAST_TIMESTAMP_SECONDARY_NAMESPACE: &str = "";
44-
pub(crate) const LATEST_NODE_ANN_BCAST_TIMESTAMP_KEY: &str = "latest_node_ann_bcast_timestamp";
36+
/// The node metrics will be persisted under this key.
37+
pub(crate) const NODE_METRICS_PRIMARY_NAMESPACE: &str = "";
38+
pub(crate) const NODE_METRICS_SECONDARY_NAMESPACE: &str = "";
39+
pub(crate) const NODE_METRICS_KEY: &str = "node_metrics";
4540

4641
/// The BDK wallet's [`ChangeSet::descriptor`] will be persisted under this key.
4742
///

0 commit comments

Comments
 (0)