Skip to content

Commit 3bcf278

Browse files
committed
Implement sync_lightning_wallet for ChainSource::Electrum
1 parent e3af9d4 commit 3bcf278

2 files changed

Lines changed: 111 additions & 5 deletions

File tree

src/chain/electrum.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66
// accordance with one or both of these licenses.
77

8-
use crate::config::{Config, FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, TX_BROADCAST_TIMEOUT_SECS};
8+
use crate::config::{
9+
Config, FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, LDK_WALLET_SYNC_TIMEOUT_SECS,
10+
TX_BROADCAST_TIMEOUT_SECS,
11+
};
912
use crate::error::Error;
1013
use crate::fee_estimator::{
1114
apply_post_estimation_adjustments, get_all_conf_targets, get_num_block_defaults_for_target,
1215
ConfirmationTarget,
1316
};
14-
use crate::logger::{log_bytes, log_error, log_trace, LdkLogger, Logger};
17+
use crate::logger::{log_bytes, log_error, log_info, log_trace, LdkLogger, Logger};
1518

16-
use lightning::chain::{Filter, WatchedOutput};
19+
use lightning::chain::{Confirm, Filter, WatchedOutput};
1720
use lightning::util::ser::Writeable;
1821
use lightning_transaction_sync::ElectrumSyncClient;
1922

@@ -25,7 +28,7 @@ use bitcoin::{FeeRate, Network, Script, Transaction, Txid};
2528

2629
use std::collections::HashMap;
2730
use std::sync::Arc;
28-
use std::time::Duration;
31+
use std::time::{Duration, Instant};
2932

3033
pub(crate) struct ElectrumRuntimeClient {
3134
electrum_client: Arc<ElectrumClient>,
@@ -59,6 +62,40 @@ impl ElectrumRuntimeClient {
5962
Ok(Self { electrum_client, bdk_electrum_client, tx_sync, runtime, config, logger })
6063
}
6164

65+
pub(crate) async fn sync_confirmables(
66+
&self, confirmables: Vec<Arc<dyn Confirm + Sync + Send>>,
67+
) -> Result<(), Error> {
68+
let now = Instant::now();
69+
70+
let tx_sync = Arc::clone(&self.tx_sync);
71+
let spawn_fut = self.runtime.spawn_blocking(move || tx_sync.sync(confirmables));
72+
let timeout_fut =
73+
tokio::time::timeout(Duration::from_secs(LDK_WALLET_SYNC_TIMEOUT_SECS), spawn_fut);
74+
75+
let res = timeout_fut
76+
.await
77+
.map_err(|e| {
78+
log_error!(self.logger, "Sync of Lightning wallet timed out: {}", e);
79+
Error::TxSyncTimeout
80+
})?
81+
.map_err(|e| {
82+
log_error!(self.logger, "Sync of Lightning wallet failed: {}", e);
83+
Error::TxSyncFailed
84+
})?
85+
.map_err(|e| {
86+
log_error!(self.logger, "Sync of Lightning wallet failed: {}", e);
87+
Error::TxSyncFailed
88+
})?;
89+
90+
log_info!(
91+
self.logger,
92+
"Sync of Lightning wallet finished in {}ms.",
93+
now.elapsed().as_millis()
94+
);
95+
96+
Ok(res)
97+
}
98+
6299
pub(crate) async fn broadcast(&self, tx: Transaction) {
63100
let electrum_client = Arc::clone(&self.electrum_client);
64101

src/chain/mod.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,76 @@ impl ChainSource {
778778

779779
res
780780
},
781-
Self::Electrum { .. } => todo!(),
781+
Self::Electrum {
782+
electrum_runtime_client,
783+
lightning_wallet_sync_status,
784+
kv_store,
785+
logger,
786+
node_metrics,
787+
..
788+
} => {
789+
let electrum_client: Arc<ElectrumRuntimeClient> =
790+
if let Some(client) = electrum_runtime_client.read().unwrap().as_ref() {
791+
Arc::clone(client)
792+
} else {
793+
debug_assert!(
794+
false,
795+
"We should have started the chain source before syncing the lightning wallet"
796+
);
797+
return Err(Error::FeerateEstimationUpdateFailed);
798+
};
799+
800+
let sync_cman = Arc::clone(&channel_manager);
801+
let sync_cmon = Arc::clone(&chain_monitor);
802+
let sync_sweeper = Arc::clone(&output_sweeper);
803+
let confirmables = vec![
804+
sync_cman as Arc<dyn Confirm + Sync + Send>,
805+
sync_cmon as Arc<dyn Confirm + Sync + Send>,
806+
sync_sweeper as Arc<dyn Confirm + Sync + Send>,
807+
];
808+
809+
let receiver_res = {
810+
let mut status_lock = lightning_wallet_sync_status.lock().unwrap();
811+
status_lock.register_or_subscribe_pending_sync()
812+
};
813+
if let Some(mut sync_receiver) = receiver_res {
814+
log_info!(logger, "Sync in progress, skipping.");
815+
return sync_receiver.recv().await.map_err(|e| {
816+
debug_assert!(false, "Failed to receive wallet sync result: {:?}", e);
817+
log_error!(logger, "Failed to receive wallet sync result: {:?}", e);
818+
Error::WalletOperationFailed
819+
})?;
820+
}
821+
822+
let res = electrum_client.sync_confirmables(confirmables).await;
823+
824+
if let Ok(_) = res {
825+
let unix_time_secs_opt =
826+
SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs());
827+
{
828+
let mut locked_node_metrics = node_metrics.write().unwrap();
829+
locked_node_metrics.latest_lightning_wallet_sync_timestamp =
830+
unix_time_secs_opt;
831+
write_node_metrics(
832+
&*locked_node_metrics,
833+
Arc::clone(&kv_store),
834+
Arc::clone(&logger),
835+
)?;
836+
}
837+
838+
periodically_archive_fully_resolved_monitors(
839+
Arc::clone(&channel_manager),
840+
Arc::clone(&chain_monitor),
841+
Arc::clone(&kv_store),
842+
Arc::clone(&logger),
843+
Arc::clone(&node_metrics),
844+
)?;
845+
}
846+
847+
lightning_wallet_sync_status.lock().unwrap().propagate_result_to_subscribers(res);
848+
849+
res
850+
},
782851
Self::BitcoindRpc { .. } => {
783852
// In BitcoindRpc mode we sync lightning and onchain wallet in one go by via
784853
// `ChainPoller`. So nothing to do here.

0 commit comments

Comments
 (0)