Skip to content

Commit d840bbd

Browse files
authored
Merge pull request #486 from tnull/2025-02-add-electrum-support
Add support for sourcing chain data from Electrum
2 parents 523727d + 5cdd2e3 commit d840bbd

17 files changed

+950
-130
lines changed

.github/workflows/kotlin.yml

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ jobs:
3939
- name: Generate Kotlin JVM
4040
run: ./scripts/uniffi_bindgen_generate_kotlin.sh
4141

42+
- name: Install `bindgen-cli`
43+
run: cargo install --force bindgen-cli
44+
4245
- name: Generate Kotlin Android
4346
run: ./scripts/uniffi_bindgen_generate_kotlin_android.sh
4447

Cargo.toml

+6-5
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ lightning-persister = { version = "0.1.0" }
3636
lightning-background-processor = { version = "0.1.0", features = ["futures"] }
3737
lightning-rapid-gossip-sync = { version = "0.1.0" }
3838
lightning-block-sync = { version = "0.1.0", features = ["rpc-client", "tokio"] }
39-
lightning-transaction-sync = { version = "0.1.0", features = ["esplora-async-https", "time"] }
39+
lightning-transaction-sync = { version = "0.1.0", features = ["esplora-async-https", "time", "electrum"] }
4040
lightning-liquidity = { version = "0.1.0", features = ["std"] }
4141

4242
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main", features = ["std"] }
@@ -63,6 +63,7 @@ lightning-liquidity = { version = "0.1.0", features = ["std"] }
6363

6464
bdk_chain = { version = "0.21.1", default-features = false, features = ["std"] }
6565
bdk_esplora = { version = "0.20.1", default-features = false, features = ["async-https-rustls", "tokio"]}
66+
bdk_electrum = { version = "0.20.1", default-features = false, features = ["use-rustls"]}
6667
bdk_wallet = { version = "1.0.0", default-features = false, features = ["std", "keys-bip39"]}
6768

6869
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
@@ -76,6 +77,7 @@ rand = "0.8.5"
7677
chrono = { version = "0.4", default-features = false, features = ["clock"] }
7778
tokio = { version = "1.37", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros" ] }
7879
esplora-client = { version = "0.11", default-features = false, features = ["tokio", "async-https-rustls"] }
80+
electrum-client = { version = "0.22.0", default-features = true }
7981
libc = "0.2"
8082
uniffi = { version = "0.27.3", features = ["build"], optional = true }
8183
serde = { version = "1.0.210", default-features = false, features = ["std", "derive"] }
@@ -92,16 +94,15 @@ winapi = { version = "0.3", features = ["winbase"] }
9294
lightning = { version = "0.1.0", features = ["std", "_test_utils"] }
9395
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std", "_test_utils"] }
9496
#lightning = { path = "../rust-lightning/lightning", features = ["std", "_test_utils"] }
95-
electrum-client = { version = "0.21.0", default-features = true }
96-
bitcoincore-rpc = { version = "0.19.0", default-features = false }
9797
proptest = "1.0.0"
9898
regex = "1.5.6"
9999

100100
[target.'cfg(not(no_download))'.dev-dependencies]
101-
electrsd = { version = "0.29.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_25_0"] }
101+
electrsd = { version = "0.33.0", default-features = false, features = ["legacy", "esplora_a33e97e1", "corepc-node_27_2"] }
102102

103103
[target.'cfg(no_download)'.dev-dependencies]
104-
electrsd = { version = "0.29.0", features = ["legacy"] }
104+
electrsd = { version = "0.33.0", default-features = false, features = ["legacy"] }
105+
corepc-node = { version = "0.7.0", default-features = false, features = ["27_2"] }
105106

106107
[target.'cfg(cln_test)'.dev-dependencies]
107108
clightningrpc = { version = "0.3.0-beta.8", default-features = false }

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fn main() {
5555
LDK Node currently comes with a decidedly opinionated set of design choices:
5656

5757
- On-chain data is handled by the integrated [BDK][bdk] wallet.
58-
- Chain data may currently be sourced from the Bitcoin Core RPC interface or an [Esplora][esplora] server, while support for Electrum will follow soon.
58+
- Chain data may currently be sourced from the Bitcoin Core RPC interface, or from an [Electrum][electrum] or [Esplora][esplora] server.
5959
- Wallet and channel state may be persisted to an [SQLite][sqlite] database, to file system, or to a custom back-end to be implemented by the user.
6060
- Gossip data may be sourced via Lightning's peer-to-peer network or the [Rapid Gossip Sync](https://docs.rs/lightning-rapid-gossip-sync/*/lightning_rapid_gossip_sync/) protocol.
6161
- Entropy for the Lightning and on-chain wallets may be sourced from raw bytes or a [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic. In addition, LDK Node offers the means to generate and persist the entropy bytes to disk.
@@ -72,6 +72,7 @@ The Minimum Supported Rust Version (MSRV) is currently 1.75.0.
7272
[rust_crate]: https://crates.io/
7373
[ldk]: https://lightningdevkit.org/
7474
[bdk]: https://bitcoindevkit.org/
75+
[electrum]: https://github.com/spesmilo/electrum-protocol
7576
[esplora]: https://github.com/Blockstream/esplora
7677
[sqlite]: https://sqlite.org/
7778
[rust]: https://www.rust-lang.org/

bindings/ldk_node.udl

+5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ dictionary EsploraSyncConfig {
3030
BackgroundSyncConfig? background_sync_config;
3131
};
3232

33+
dictionary ElectrumSyncConfig {
34+
BackgroundSyncConfig? background_sync_config;
35+
};
36+
3337
dictionary LSPS2ServiceConfig {
3438
string? require_token;
3539
boolean advertise_service;
@@ -72,6 +76,7 @@ interface Builder {
7276
void set_entropy_seed_bytes(sequence<u8> seed_bytes);
7377
void set_entropy_bip39_mnemonic(Mnemonic mnemonic, string? passphrase);
7478
void set_chain_source_esplora(string server_url, EsploraSyncConfig? config);
79+
void set_chain_source_electrum(string server_url, ElectrumSyncConfig? config);
7580
void set_chain_source_bitcoind_rpc(string rpc_host, u16 rpc_port, string rpc_user, string rpc_password);
7681
void set_gossip_source_p2p();
7782
void set_gossip_source_rgs(string rgs_server_url);

docker-compose-cln.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
version: '3'
2-
31
services:
42
bitcoin:
5-
image: blockstream/bitcoind:24.1
3+
image: blockstream/bitcoind:27.2
64
platform: linux/amd64
75
command:
86
[

scripts/download_bitcoind_electrs.sh

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#!/bin/bash
2+
set -eox pipefail
3+
14
# Our Esplora-based tests require `electrs` and `bitcoind`
25
# binaries. Here, we download the binaries, validate them, and export their
36
# location via `ELECTRS_EXE`/`BITCOIND_EXE` which will be used by the
@@ -7,19 +10,20 @@ HOST_PLATFORM="$(rustc --version --verbose | grep "host:" | awk '{ print $2 }')"
710
ELECTRS_DL_ENDPOINT="https://github.com/RCasatta/electrsd/releases/download/electrs_releases"
811
ELECTRS_VERSION="esplora_a33e97e1a1fc63fa9c20a116bb92579bbf43b254"
912
BITCOIND_DL_ENDPOINT="https://bitcoincore.org/bin/"
10-
BITCOIND_VERSION="25.1"
13+
BITCOIND_VERSION="27.2"
1114
if [[ "$HOST_PLATFORM" == *linux* ]]; then
1215
ELECTRS_DL_FILE_NAME=electrs_linux_"$ELECTRS_VERSION".zip
1316
ELECTRS_DL_HASH="865e26a96e8df77df01d96f2f569dcf9622fc87a8d99a9b8fe30861a4db9ddf1"
1417
BITCOIND_DL_FILE_NAME=bitcoin-"$BITCOIND_VERSION"-x86_64-linux-gnu.tar.gz
15-
BITCOIND_DL_HASH="a978c407b497a727f0444156e397b50491ce862d1f906fef9b521415b3611c8b"
18+
BITCOIND_DL_HASH="acc223af46c178064c132b235392476f66d486453ddbd6bca6f1f8411547da78"
1619
elif [[ "$HOST_PLATFORM" == *darwin* ]]; then
1720
ELECTRS_DL_FILE_NAME=electrs_macos_"$ELECTRS_VERSION".zip
1821
ELECTRS_DL_HASH="2d5ff149e8a2482d3658e9b386830dfc40c8fbd7c175ca7cbac58240a9505bcd"
1922
BITCOIND_DL_FILE_NAME=bitcoin-"$BITCOIND_VERSION"-x86_64-apple-darwin.tar.gz
20-
BITCOIND_DL_HASH="1acfde0ec3128381b83e3e5f54d1c7907871d324549129592144dd12a821eff1"
23+
BITCOIND_DL_HASH="6ebc56ca1397615d5a6df2b5cf6727b768e3dcac320c2d5c2f321dcaabc7efa2"
2124
else
22-
echo "\n\nUnsupported platform: $HOST_PLATFORM Exiting.."
25+
printf "\n\n"
26+
echo "Unsupported platform: $HOST_PLATFORM Exiting.."
2327
exit 1
2428
fi
2529

src/builder.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
use crate::chain::{ChainSource, DEFAULT_ESPLORA_SERVER_URL};
99
use crate::config::{
10-
default_user_config, may_announce_channel, AnnounceError, Config, EsploraSyncConfig,
11-
DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL, WALLET_KEYS_SEED_LEN,
10+
default_user_config, may_announce_channel, AnnounceError, Config, ElectrumSyncConfig,
11+
EsploraSyncConfig, DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL, WALLET_KEYS_SEED_LEN,
1212
};
1313

1414
use crate::connection::ConnectionManager;
@@ -83,6 +83,7 @@ const LSPS_HARDENED_CHILD_INDEX: u32 = 577;
8383
#[derive(Debug, Clone)]
8484
enum ChainDataSourceConfig {
8585
Esplora { server_url: String, sync_config: Option<EsploraSyncConfig> },
86+
Electrum { server_url: String, sync_config: Option<ElectrumSyncConfig> },
8687
BitcoindRpc { rpc_host: String, rpc_port: u16, rpc_user: String, rpc_password: String },
8788
}
8889

@@ -284,6 +285,18 @@ impl NodeBuilder {
284285
self
285286
}
286287

288+
/// Configures the [`Node`] instance to source its chain data from the given Electrum server.
289+
///
290+
/// If no `sync_config` is given, default values are used. See [`ElectrumSyncConfig`] for more
291+
/// information.
292+
pub fn set_chain_source_electrum(
293+
&mut self, server_url: String, sync_config: Option<ElectrumSyncConfig>,
294+
) -> &mut Self {
295+
self.chain_data_source_config =
296+
Some(ChainDataSourceConfig::Electrum { server_url, sync_config });
297+
self
298+
}
299+
287300
/// Configures the [`Node`] instance to source its chain data from the given Bitcoin Core RPC
288301
/// endpoint.
289302
pub fn set_chain_source_bitcoind_rpc(
@@ -691,6 +704,16 @@ impl ArcedNodeBuilder {
691704
self.inner.write().unwrap().set_chain_source_esplora(server_url, sync_config);
692705
}
693706

707+
/// Configures the [`Node`] instance to source its chain data from the given Electrum server.
708+
///
709+
/// If no `sync_config` is given, default values are used. See [`ElectrumSyncConfig`] for more
710+
/// information.
711+
pub fn set_chain_source_electrum(
712+
&self, server_url: String, sync_config: Option<ElectrumSyncConfig>,
713+
) {
714+
self.inner.write().unwrap().set_chain_source_electrum(server_url, sync_config);
715+
}
716+
694717
/// Configures the [`Node`] instance to source its chain data from the given Bitcoin Core RPC
695718
/// endpoint.
696719
pub fn set_chain_source_bitcoind_rpc(
@@ -1024,6 +1047,20 @@ fn build_with_store_internal(
10241047
Arc::clone(&node_metrics),
10251048
))
10261049
},
1050+
Some(ChainDataSourceConfig::Electrum { server_url, sync_config }) => {
1051+
let sync_config = sync_config.unwrap_or(ElectrumSyncConfig::default());
1052+
Arc::new(ChainSource::new_electrum(
1053+
server_url.clone(),
1054+
sync_config,
1055+
Arc::clone(&wallet),
1056+
Arc::clone(&fee_estimator),
1057+
Arc::clone(&tx_broadcaster),
1058+
Arc::clone(&kv_store),
1059+
Arc::clone(&config),
1060+
Arc::clone(&logger),
1061+
Arc::clone(&node_metrics),
1062+
))
1063+
},
10271064
Some(ChainDataSourceConfig::BitcoindRpc { rpc_host, rpc_port, rpc_user, rpc_password }) => {
10281065
Arc::new(ChainSource::new_bitcoind_rpc(
10291066
rpc_host.clone(),

0 commit comments

Comments
 (0)