Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,29 @@ panic = 'abort' # Abort on panic
default = []

[dependencies]
lightning = { version = "0.2.0-rc1", features = ["std"] }
lightning-types = { version = "0.3.0-rc1" }
lightning-invoice = { version = "0.34.0-rc1", features = ["std"] }
lightning-net-tokio = { version = "0.2.0-rc1" }
lightning-persister = { version = "0.2.0-rc1", features = ["tokio"] }
lightning-background-processor = { version = "0.2.0-rc1" }
lightning-rapid-gossip-sync = { version = "0.2.0-rc1" }
lightning-block-sync = { version = "0.2.0-rc1", features = ["rest-client", "rpc-client", "tokio"] }
lightning-transaction-sync = { version = "0.2.0-rc1", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
lightning-liquidity = { version = "0.2.0-rc1", features = ["std"] }
lightning-macros = { version = "0.2.0-rc1" }

#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main", features = ["std"] }
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main", features = ["std"] }
#lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main", features = ["tokio"] }
#lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main", features = ["rest-client", "rpc-client", "tokio"] }
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main", features = ["esplora-async-https", "electrum-rustls-ring", "time"] }
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning = { version = "0.2.0-rc1", features = ["std"] }
#lightning-types = { version = "0.3.0-rc1" }
#lightning-invoice = { version = "0.34.0-rc1", features = ["std"] }
#lightning-net-tokio = { version = "0.2.0-rc1" }
#lightning-persister = { version = "0.2.0-rc1", features = ["tokio"] }
#lightning-background-processor = { version = "0.2.0-rc1" }
#lightning-rapid-gossip-sync = { version = "0.2.0-rc1" }
#lightning-block-sync = { version = "0.2.0-rc1", features = ["rest-client", "rpc-client", "tokio"] }
#lightning-transaction-sync = { version = "0.2.0-rc1", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
#lightning-liquidity = { version = "0.2.0-rc1", features = ["std"] }
#lightning-macros = { version = "0.2.0-rc1" }

lightning = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box", features = ["std"] }
lightning-types = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box" }
lightning-invoice = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box", features = ["std"] }
lightning-net-tokio = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box" }
lightning-persister = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box", features = ["tokio"] }
lightning-background-processor = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box" }
lightning-rapid-gossip-sync = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box" }
lightning-block-sync = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box", features = ["rest-client", "rpc-client", "tokio"] }
lightning-transaction-sync = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box", features = ["esplora-async-https", "electrum-rustls-ring", "time"] }
lightning-liquidity = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box" }
lightning-macros = { git = "https://git.bitcoin.ninja/rust-lightning", branch = "2025-10-msrv-less-box" }

#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03", features = ["std"] }
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
Expand Down Expand Up @@ -108,9 +108,9 @@ prost = { version = "0.11.6", default-features = false}
winapi = { version = "0.3", features = ["winbase"] }

[dev-dependencies]
lightning = { version = "0.2.0-rc1", features = ["std", "_test_utils"] }
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std", "_test_utils"] }
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03", features = ["std", "_test_utils"] }
#lightning = { version = "0.2.0-rc1", features = ["std", "_test_utils"] }
lightning = { git = "https://git.bitcoin.ninja/rust-lightning", branch="2025-10-msrv-less-box", features = ["std", "_test_utils"] }
#lightning = { git = "https://git.bitcoin.ninja/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03", features = ["std", "_test_utils"] }
#lightning = { path = "../rust-lightning/lightning", features = ["std", "_test_utils"] }
proptest = "1.0.0"
regex = "1.5.6"
Expand Down
26 changes: 12 additions & 14 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ use crate::peer_store::PeerStore;
use crate::runtime::Runtime;
use crate::tx_broadcaster::TransactionBroadcaster;
use crate::types::{
ChainMonitor, ChannelManager, DynStore, GossipSync, Graph, KeysManager, MessageRouter,
OnionMessenger, PaymentStore, PeerManager, Persister,
ChainMonitor, ChannelManager, DynStore, DynStoreWrapper, GossipSync, Graph, KeysManager,
MessageRouter, OnionMessenger, PaymentStore, PeerManager, Persister, SyncAndAsyncKVStore,
};
use crate::wallet::persist::KVStoreWalletPersister;
use crate::wallet::Wallet;
Expand Down Expand Up @@ -588,14 +588,12 @@ impl NodeBuilder {
let storage_dir_path = self.config.storage_dir_path.clone();
fs::create_dir_all(storage_dir_path.clone())
.map_err(|_| BuildError::StoragePathAccessFailed)?;
let kv_store = Arc::new(
SqliteStore::new(
storage_dir_path.into(),
Some(io::sqlite_store::SQLITE_DB_FILE_NAME.to_string()),
Some(io::sqlite_store::KV_TABLE_NAME.to_string()),
)
.map_err(|_| BuildError::KVStoreSetupFailed)?,
);
let kv_store = SqliteStore::new(
storage_dir_path.into(),
Some(io::sqlite_store::SQLITE_DB_FILE_NAME.to_string()),
Some(io::sqlite_store::KV_TABLE_NAME.to_string()),
)
.map_err(|_| BuildError::KVStoreSetupFailed)?;
self.build_with_store(kv_store)
}

Expand All @@ -607,7 +605,7 @@ impl NodeBuilder {

fs::create_dir_all(storage_dir_path.clone())
.map_err(|_| BuildError::StoragePathAccessFailed)?;
let kv_store = Arc::new(FilesystemStore::new(storage_dir_path));
let kv_store = FilesystemStore::new(storage_dir_path);
self.build_with_store(kv_store)
}

Expand Down Expand Up @@ -743,12 +741,12 @@ impl NodeBuilder {
seed_bytes,
runtime,
logger,
Arc::new(vss_store),
Arc::new(DynStoreWrapper(vss_store)),
)
}

/// Builds a [`Node`] instance according to the options previously configured.
pub fn build_with_store(&self, kv_store: Arc<DynStore>) -> Result<Node, BuildError> {
pub fn build_with_store<S: SyncAndAsyncKVStore + Send + Sync + 'static>(&self, kv_store: S) -> Result<Node, BuildError> {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Expand Down Expand Up @@ -777,7 +775,7 @@ impl NodeBuilder {
seed_bytes,
runtime,
logger,
kv_store,
Arc::new(DynStoreWrapper(kv_store)),
)
}
}
Expand Down
141 changes: 109 additions & 32 deletions src/chain/bitcoind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
// accordance with one or both of these licenses.

use std::collections::{HashMap, VecDeque};
use std::future::Future;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

use base64::prelude::BASE64_STANDARD;
use base64::Engine;
use bitcoin::{BlockHash, FeeRate, Network, Transaction, Txid};
use bitcoin::{BlockHash, FeeRate, Network, OutPoint, Transaction, Txid};
use lightning::chain::chaininterface::ConfirmationTarget as LdkConfirmationTarget;
use lightning::chain::Listen;
use lightning::util::ser::Writeable;
Expand All @@ -23,7 +24,7 @@ use lightning_block_sync::poll::{ChainPoller, ChainTip, ValidatedBlockHeader};
use lightning_block_sync::rest::RestClient;
use lightning_block_sync::rpc::{RpcClient, RpcError};
use lightning_block_sync::{
AsyncBlockSourceResult, BlockData, BlockHeaderData, BlockSource, BlockSourceErrorKind, Cache,
BlockData, BlockHeaderData, BlockSource, BlockSourceError, BlockSourceErrorKind, Cache,
SpvClient,
};
use serde::Serialize;
Expand Down Expand Up @@ -120,7 +121,7 @@ impl BitcoindChainSource {
}
}

pub(super) fn as_utxo_source(&self) -> Arc<dyn UtxoSource> {
pub(super) fn as_utxo_source(&self) -> UtxoSourceClient {
self.api_client.utxo_source()
}

Expand Down Expand Up @@ -625,6 +626,78 @@ impl BitcoindChainSource {
}
}

#[derive(Clone)]
pub(crate) enum UtxoSourceClient {
Rpc(Arc<RpcClient>),
Rest(Arc<RestClient>),
}

impl std::ops::Deref for UtxoSourceClient {
type Target = Self;
fn deref(&self) -> &Self {
self
}
}

impl BlockSource for UtxoSourceClient {
fn get_header<'a>(
&'a self,
header_hash: &'a BlockHash,
height_hint: Option<u32>,
) -> impl Future<Output = Result<BlockHeaderData, BlockSourceError>> + 'a {
async move {
match self {
Self::Rpc(client) => client.get_header(header_hash, height_hint).await,
Self::Rest(client) => client.get_header(header_hash, height_hint).await,
}
}
}

fn get_block<'a>(
&'a self,
header_hash: &'a BlockHash,
) -> impl Future<Output = Result<BlockData, BlockSourceError>> + 'a {
async move {
match self {
Self::Rpc(client) => client.get_block(header_hash).await,
Self::Rest(client) => client.get_block(header_hash).await,
}
}
}

fn get_best_block<'a>(
&'a self,
) -> impl Future<Output = Result<(BlockHash, Option<u32>), BlockSourceError>> + 'a {
async move {
match self {
Self::Rpc(client) => client.get_best_block().await,
Self::Rest(client) => client.get_best_block().await,
}
}
}
}


impl UtxoSource for UtxoSourceClient {
fn get_block_hash_by_height<'a>(&'a self, block_height: u32) -> impl Future<Output = Result<BlockHash, BlockSourceError>> + 'a {
async move {
match self {
Self::Rpc(client) => client.get_block_hash_by_height(block_height).await,
Self::Rest(client) => client.get_block_hash_by_height(block_height).await,
}
}
}

fn is_output_unspent<'a>(&'a self, outpoint: OutPoint) -> impl Future<Output = Result<bool, BlockSourceError>> + 'a {
async move {
match self {
Self::Rpc(client) => client.is_output_unspent(outpoint).await,
Self::Rest(client) => client.is_output_unspent(outpoint).await,
}
}
}
}

pub enum BitcoindClient {
Rpc {
rpc_client: Arc<RpcClient>,
Expand Down Expand Up @@ -686,12 +759,10 @@ impl BitcoindClient {
}
}

pub(crate) fn utxo_source(&self) -> Arc<dyn UtxoSource> {
fn utxo_source(&self) -> UtxoSourceClient {
match self {
BitcoindClient::Rpc { rpc_client, .. } => Arc::clone(rpc_client) as Arc<dyn UtxoSource>,
BitcoindClient::Rest { rest_client, .. } => {
Arc::clone(rest_client) as Arc<dyn UtxoSource>
},
Self::Rpc { rpc_client, .. } => UtxoSourceClient::Rpc(Arc::clone(&rpc_client)),
Self::Rest { rest_client, .. } => UtxoSourceClient::Rest(Arc::clone(&rest_client)),
}
}

Expand Down Expand Up @@ -1175,38 +1246,44 @@ impl BitcoindClient {
impl BlockSource for BitcoindClient {
fn get_header<'a>(
&'a self, header_hash: &'a bitcoin::BlockHash, height_hint: Option<u32>,
) -> AsyncBlockSourceResult<'a, BlockHeaderData> {
match self {
BitcoindClient::Rpc { rpc_client, .. } => {
Box::pin(async move { rpc_client.get_header(header_hash, height_hint).await })
},
BitcoindClient::Rest { rest_client, .. } => {
Box::pin(async move { rest_client.get_header(header_hash, height_hint).await })
},
) -> impl Future<Output = Result<BlockHeaderData, BlockSourceError>> + 'a {
async move {
match self {
BitcoindClient::Rpc { rpc_client, .. } => {
rpc_client.get_header(header_hash, height_hint).await
},
BitcoindClient::Rest { rest_client, .. } => {
rest_client.get_header(header_hash, height_hint).await
},
}
}
}

fn get_block<'a>(
&'a self, header_hash: &'a bitcoin::BlockHash,
) -> AsyncBlockSourceResult<'a, BlockData> {
match self {
BitcoindClient::Rpc { rpc_client, .. } => {
Box::pin(async move { rpc_client.get_block(header_hash).await })
},
BitcoindClient::Rest { rest_client, .. } => {
Box::pin(async move { rest_client.get_block(header_hash).await })
},
) -> impl Future<Output = Result<BlockData, BlockSourceError>> + 'a {
async move {
match self {
BitcoindClient::Rpc { rpc_client, .. } => {
rpc_client.get_block(header_hash).await
},
BitcoindClient::Rest { rest_client, .. } => {
rest_client.get_block(header_hash).await
},
}
}
}

fn get_best_block(&self) -> AsyncBlockSourceResult<'_, (bitcoin::BlockHash, Option<u32>)> {
match self {
BitcoindClient::Rpc { rpc_client, .. } => {
Box::pin(async move { rpc_client.get_best_block().await })
},
BitcoindClient::Rest { rest_client, .. } => {
Box::pin(async move { rest_client.get_best_block().await })
},
fn get_best_block<'a>(&'a self) -> impl Future<Output = Result<(bitcoin::BlockHash, Option<u32>), BlockSourceError>> + 'a {
async move {
match self {
BitcoindClient::Rpc { rpc_client, .. } => {
rpc_client.get_best_block().await
},
BitcoindClient::Rest { rest_client, .. } => {
rest_client.get_best_block().await
},
}
}
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
// accordance with one or both of these licenses.

mod bitcoind;
pub(crate) mod bitcoind;
mod electrum;
mod esplora;

Expand All @@ -15,9 +15,8 @@ use std::time::Duration;

use bitcoin::{Script, Txid};
use lightning::chain::Filter;
use lightning_block_sync::gossip::UtxoSource;

use crate::chain::bitcoind::BitcoindChainSource;
use crate::chain::bitcoind::{BitcoindChainSource, UtxoSourceClient};
use crate::chain::electrum::ElectrumChainSource;
use crate::chain::esplora::EsploraChainSource;
use crate::config::{
Expand Down Expand Up @@ -205,7 +204,7 @@ impl ChainSource {
}
}

pub(crate) fn as_utxo_source(&self) -> Option<Arc<dyn UtxoSource>> {
pub(crate) fn as_utxo_source(&self) -> Option<UtxoSourceClient> {
match &self.kind {
ChainSourceKind::Bitcoind(bitcoind_chain_source) => {
Some(bitcoind_chain_source.as_utxo_source())
Expand Down
3 changes: 2 additions & 1 deletion src/data_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ mod tests {

use super::*;
use crate::hex_utils;
use crate::types::DynStoreWrapper;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct TestObjectId {
Expand Down Expand Up @@ -234,7 +235,7 @@ mod tests {

#[test]
fn data_is_persisted() {
let store: Arc<DynStore> = Arc::new(TestStore::new(false));
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(TestStore::new(false)));
let logger = Arc::new(TestLogger::new());
let primary_namespace = "datastore_test_primary".to_string();
let secondary_namespace = "datastore_test_secondary".to_string();
Expand Down
5 changes: 3 additions & 2 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1608,10 +1608,11 @@ mod tests {
use lightning::util::test_utils::{TestLogger, TestStore};

use super::*;
use crate::types::DynStoreWrapper;

#[tokio::test]
async fn event_queue_persistence() {
let store: Arc<DynStore> = Arc::new(TestStore::new(false));
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(TestStore::new(false)));
let logger = Arc::new(TestLogger::new());
let event_queue = Arc::new(EventQueue::new(Arc::clone(&store), Arc::clone(&logger)));
assert_eq!(event_queue.next_event(), None);
Expand Down Expand Up @@ -1647,7 +1648,7 @@ mod tests {

#[tokio::test]
async fn event_queue_concurrency() {
let store: Arc<DynStore> = Arc::new(TestStore::new(false));
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(TestStore::new(false)));
let logger = Arc::new(TestLogger::new());
let event_queue = Arc::new(EventQueue::new(Arc::clone(&store), Arc::clone(&logger)));
assert_eq!(event_queue.next_event(), None);
Expand Down
Loading