Skip to content

Commit 174f0dc

Browse files
committed
Implement sync_lightning_wallet for ChainSource::Electrum
1 parent 2d2dfbe commit 174f0dc

File tree

2 files changed

+111
-5
lines changed

2 files changed

+111
-5
lines changed

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
@@ -776,7 +776,76 @@ impl ChainSource {
776776

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

0 commit comments

Comments
 (0)