Skip to content
Open
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
36 changes: 35 additions & 1 deletion .clippy.toml
Original file line number Diff line number Diff line change
@@ -1 +1,35 @@
msrv = "1.63.0"
msrv = "1.63.0"

# Keep library clock reads behind src/time.rs so they work on wasm32. Tokio's runtime timers
# are separate.
disallowed-methods = [
{ path = "std::time::SystemTime::now", reason = "use crate::time instead" },
{ path = "std::time::SystemTime::elapsed", reason = "use crate::time instead" },
{ path = "std::time::Instant::now", reason = "use crate::time::Instant instead" },
{ path = "std::time::Instant::elapsed", reason = "use crate::time::Instant instead" },
{ path = "tokio::time::Instant::now", reason = "use crate::time::Instant for clock reads; runtime timers remain separate" },
{ path = "tokio::time::Instant::elapsed", reason = "use crate::time::Instant for elapsed measurements" },
{ path = "chrono::Utc::now", reason = "use crate::time::now_utc instead", allow-invalid = true },
{ path = "chrono::Local::now", reason = "use crate::time::now_utc instead", allow-invalid = true },
# Dependency APIs that read the platform clock internally. Use their explicit-time variants.
{ path = "bdk_wallet::Wallet::start_full_scan", reason = "use start_full_scan_at with crate::time" },
{ path = "bdk_wallet::Wallet::start_sync_with_revealed_spks", reason = "use start_sync_with_revealed_spks_at with crate::time" },
{ path = "lightning_liquidity::LiquidityManager::new", reason = "use new_with_custom_time_provider with crate::time::LdkTimeProvider" },
{ path = "lightning_invoice::InvoiceBuilder::current_timestamp", reason = "use duration_since_epoch with crate::time" },
{ path = "lightning_invoice::Bolt11Invoice::is_expired", reason = "use would_expire with crate::time" },
{ path = "lightning_invoice::Bolt11Invoice::duration_until_expiry", reason = "use expiration_remaining_from_epoch with crate::time" },
{ path = "lightning::offers::offer::Offer::is_expired", reason = "use is_expired_no_std with crate::time" },
{ path = "lightning::offers::refund::Refund::is_expired", reason = "use is_expired_no_std with crate::time" },
{ path = "lightning::offers::invoice::Bolt12Invoice::is_expired", reason = "use is_expired_no_std with crate::time" },
{ path = "lightning::offers::static_invoice::StaticInvoice::is_expired", reason = "use is_expired_no_std with crate::time" },
{ path = "lightning::offers::invoice_request::InvoiceRequest::respond_with", reason = "use respond_with_no_std with crate::time" },
{ path = "lightning::offers::invoice_request::VerifiedInvoiceRequest::respond_with", reason = "use respond_with_no_std with crate::time" },
{ path = "lightning::offers::invoice_request::VerifiedInvoiceRequest::respond_using_derived_keys", reason = "use respond_using_derived_keys_no_std with crate::time" },
{ path = "lightning::offers::refund::Refund::respond_with", reason = "use respond_with_no_std with crate::time" },
{ path = "lightning::offers::refund::Refund::respond_using_derived_keys", reason = "use respond_using_derived_keys_no_std with crate::time" },
{ path = "lightning_rapid_gossip_sync::RapidGossipSync::update_network_graph", reason = "use update_network_graph_no_std with Some(crate::time::unix_time_secs().expect(...)) to retain freshness validation" },
{ path = "lightning_rapid_gossip_sync::RapidGossipSync::sync_network_graph_with_file_path", reason = "read the snapshot and use update_network_graph_no_std with current time" },
{ path = "lightning::routing::gossip::NetworkGraph::remove_stale_channels_and_tracking", reason = "use remove_stale_channels_and_tracking_with_time with crate::time" },
{ path = "bdk_chain::bdk_core::spk_client::SyncRequest::builder", reason = "use builder_at with crate::time" },
{ path = "bdk_chain::bdk_core::spk_client::FullScanRequest::builder", reason = "use builder_at with crate::time" },
]
27 changes: 27 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,33 @@ jobs:
cargo clippy --lib --verbose --color always -- -A warnings -D clippy::unwrap_used -A clippy::tabs_in_doc_comments
cargo clippy --lib --no-default-features --features uniffi-default --verbose --color always -- -A warnings -D clippy::unwrap_used -A clippy::tabs_in_doc_comments

clock-boundary:
name: Clock boundary
timeout-minutes: 120
runs-on: self-hosted
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install Rust stable toolchain
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain stable
- name: Add clippy component
run: rustup component add clippy
# Clock reads must go through `src/time.rs` so they work on wasm32. See `.clippy.toml`.
- name: Ban direct clock reads in library code
run: |
cargo clippy --lib --verbose --color always -- -A warnings -D clippy::disallowed_methods
cargo clippy --lib --no-default-features --features uniffi-default --verbose --color always -- -A warnings -D clippy::disallowed_methods
cargo clippy --lib --no-default-features --features chain-esplora,storage-sqlite --verbose --color always -- -A warnings -D clippy::disallowed_methods
# LDK's `std` and `time` features read the system clock internally.
- name: Check LDK clock features are disabled without ldk-std
run: |
features=$(cargo tree --target wasm32-unknown-unknown --no-default-features -e normal --prefix none --format '{p} {f}')
if grep -E '^lightning' <<< "$features" | grep -E '\b(std|time)\b'; then
echo "LDK std or time features are enabled without ldk-std"
exit 1
fi

doc:
name: Documentation
timeout-minutes: 120
Expand Down
41 changes: 30 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ panic = 'abort' # Abort on panic

[features]
default = [
"ldk-std",
"net-tokio",
"chain-esplora",
"chain-electrum",
"chain-bitcoind",
Expand All @@ -37,23 +39,38 @@ default = [
"storage-vss",
"unified-payments",
]
# LDK's `std` feature reads the system clock internally. Disable it for wasm32, where clock reads
# must go through `crate::time` and LDK's explicit-time APIs instead. Features whose LDK crates
# require `std` enable this.
ldk-std = [
"lightning/std",
"lightning-invoice/std",
"lightning-liquidity/std",
"lightning-liquidity/time",
"lightning-background-processor/std",
"lightning-rapid-gossip-sync/std",
]
# Tokio TCP transport for peer connections. Without it, connecting to peers fails and listening
# addresses are rejected.
net-tokio = ["dep:lightning-net-tokio"]
chain-esplora = [
"ldk-std",
"dep:bdk_esplora",
"dep:esplora-client",
"dep:ldk-esplora-client",
"dep:lightning-transaction-sync",
"lightning-transaction-sync/esplora-async-https",
"lightning-transaction-sync/time",
]
chain-electrum = [
"ldk-std",
"dep:bdk_electrum",
"dep:electrum-client",
"dep:lightning-transaction-sync",
"lightning-transaction-sync/electrum-rustls-ring",
]
chain-bitcoind = ["dep:lightning-block-sync"]
chain-bitcoind = ["ldk-std", "dep:lightning-block-sync"]
storage-sqlite = ["dep:rusqlite"]
storage-filesystem = ["dep:lightning-persister"]
storage-filesystem = ["ldk-std", "dep:lightning-persister"]
storage-vss = ["dep:vss-client", "dep:prost"]
storage-postgres = ["dep:tokio-postgres", "dep:native-tls", "dep:postgres-native-tls"]
storage-postgres-vendored-tls = ["storage-postgres", "native-tls/vendored"]
Expand All @@ -65,6 +82,7 @@ unified-payments = [
uniffi = ["dep:uniffi"]
uniffi-default = [
"uniffi",
"net-tokio",
"chain-esplora",
"chain-electrum",
"storage-sqlite",
Expand All @@ -86,16 +104,17 @@ uniffi-default = [
#lightning-macros = { version = "0.2.0" }
#lightning-dns-resolver = { version = "0.3.0" }

lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", features = ["std"] }
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", default-features = false, features = ["grind_signatures"] }
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457" }
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", features = ["std"] }
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457" }
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", default-features = false }
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", optional = true }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", features = ["tokio"], optional = true }
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457" }
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457" }
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", default-features = false }
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", default-features = false }
lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", features = ["rest-client", "rpc-client", "tokio"], optional = true }
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", optional = true }
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", features = ["std"] }
# Measure sync durations in the node's time module, not the dependency's `time` feature.
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", default-features = false, optional = true }
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", default-features = false }
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457" }
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "2985bd95fdbce06bf9f25f684772b0ba9903e457", optional = true }

Expand All @@ -113,7 +132,7 @@ bip21 = { version = "0.5", features = ["std"], default-features = false, optiona

base64 = { version = "0.22.1", default-features = false, features = ["std"] }
getrandom = { version = "0.3", default-features = false }
chrono = { version = "0.4", default-features = false, features = ["clock"] }
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
tokio = { version = "1.39", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros", "net" ] }
tokio-util = { version = "0.7.10", default-features = false, features = ["rt"] }
esplora-client = { version = "0.12", default-features = false, features = ["tokio", "async-https-rustls"], optional = true }
Expand Down
16 changes: 11 additions & 5 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use std::net::ToSocketAddrs;
#[cfg(feature = "storage-filesystem")]
use std::path::PathBuf;
use std::sync::{Arc, Mutex, Once, RwLock};
use std::time::SystemTime;

use bdk_wallet::template::Bip84;
use bdk_wallet::{KeychainKind, Wallet as BdkWallet};
Expand Down Expand Up @@ -102,6 +101,7 @@ use crate::probing::{
RandomWalkStrategy,
};
use crate::runtime::{Runtime, RuntimeSpawner};
use crate::time;
use crate::tx_broadcaster::TransactionBroadcaster;
use crate::types::{
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreRef, DynStoreWrapper,
Expand Down Expand Up @@ -1542,6 +1542,12 @@ fn build_with_store_internal(
}
}

#[cfg(not(feature = "net-tokio"))]
if config.listening_addresses.is_some() {
log_error!(logger, "Listening addresses were set but no network transport is enabled.");
return Err(BuildError::InvalidListeningAddresses);
}

let tx_broadcaster = Arc::new(TransactionBroadcaster::new(Arc::clone(&logger)));
let fee_estimator = Arc::new(OnchainFeeEstimator::new());

Expand Down Expand Up @@ -1938,8 +1944,8 @@ fn build_with_store_internal(
tx_broadcaster.set_wallet(Arc::downgrade(&wallet));

// Initialize the KeysManager
let cur_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).map_err(|e| {
log_error!(logger, "Failed to get current time: {}", e);
let cur_time = time::duration_since_epoch().ok_or_else(|| {
log_error!(logger, "Failed to get current time: system time is before the Unix epoch");
BuildError::InvalidSystemTime
})?;

Expand Down Expand Up @@ -2361,8 +2367,8 @@ fn build_with_store_internal(
},
};

let cur_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).map_err(|e| {
log_error!(logger, "Failed to get current time: {}", e);
let cur_time = time::duration_since_epoch().ok_or_else(|| {
log_error!(logger, "Failed to get current time: system time is before the Unix epoch");
BuildError::InvalidSystemTime
})?;

Expand Down
24 changes: 11 additions & 13 deletions src/chain/bitcoind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::fmt;
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 std::time::Duration;

use base64::prelude::BASE64_STANDARD;
use base64::Engine;
Expand Down Expand Up @@ -42,6 +42,7 @@ use crate::fee_estimator::{
};
use crate::io::utils::update_and_persist_node_metrics;
use crate::logger::{log_bytes, log_debug, log_error, log_info, log_trace, LdkLogger, Logger};
use crate::time::{self, Instant};
use crate::tx_broadcaster::SortedTransactions;
use crate::types::{ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet};
use crate::{Error, PersistedNodeMetrics};
Expand Down Expand Up @@ -236,7 +237,7 @@ impl BitcoindChainSource {
));
}

let now = SystemTime::now();
let now = Instant::now();
match synchronize_listeners(
self.api_client.as_ref(),
self.config.network,
Expand All @@ -255,15 +256,14 @@ impl BitcoindChainSource {
);
*self.spv_client.lock().await = Some(spv_client);
{
let elapsed_ms = now.elapsed().map(|d| d.as_millis()).unwrap_or(0);
let elapsed_ms = now.elapsed().as_millis();
log_info!(
self.logger,
"Finished synchronizing listeners in {}ms",
elapsed_ms,
);
*self.latest_chain_tip.write().expect("lock") = Some(chain_tip);
let unix_time_secs_opt =
SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs());
let unix_time_secs_opt = time::unix_time_secs();
update_and_persist_node_metrics(
&self.node_metrics,
&*self.kv_store,
Expand Down Expand Up @@ -479,10 +479,10 @@ impl BitcoindChainSource {
}
let spv_client = spv_client_lock.as_mut().expect("initialized above");

let now = SystemTime::now();
let now = Instant::now();
match spv_client.poll_best_tip().await {
Ok((ChainTip::Better(tip), true)) => {
let elapsed_ms = now.elapsed().map(|d| d.as_millis()).unwrap_or(0);
let elapsed_ms = now.elapsed().as_millis();
log_trace!(self.logger, "Finished polling best tip in {}ms", elapsed_ms);
*self.latest_chain_tip.write().expect("lock") = Some(tip);
},
Expand All @@ -496,15 +496,15 @@ impl BitcoindChainSource {

let cur_height = channel_manager.current_best_block().height;

let now = SystemTime::now();
let now = Instant::now();
let bdk_unconfirmed_txids = onchain_wallet.get_unconfirmed_txids();
match self
.api_client
.get_updated_mempool_transactions(cur_height, bdk_unconfirmed_txids)
.await
{
Ok((unconfirmed_txs, evicted_txids)) => {
let elapsed_ms = now.elapsed().map(|d| d.as_millis()).unwrap_or(0);
let elapsed_ms = now.elapsed().as_millis();
log_trace!(
self.logger,
"Finished polling mempool of size {} and {} evicted transactions in {}ms",
Expand All @@ -525,8 +525,7 @@ impl BitcoindChainSource {
},
}

let unix_time_secs_opt =
SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs());
let unix_time_secs_opt = time::unix_time_secs();
update_and_persist_node_metrics(&self.node_metrics, &*self.kv_store, &*self.logger, |m| {
m.latest_lightning_wallet_sync_timestamp = unix_time_secs_opt;
m.latest_onchain_wallet_sync_timestamp = unix_time_secs_opt;
Expand Down Expand Up @@ -654,8 +653,7 @@ impl BitcoindChainSource {
);
}

let unix_time_secs_opt =
SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs());
let unix_time_secs_opt = time::unix_time_secs();
update_and_persist_node_metrics(&self.node_metrics, &*self.kv_store, &*self.logger, |m| {
m.latest_fee_rate_cache_update_timestamp = unix_time_secs_opt
})
Expand Down
12 changes: 5 additions & 7 deletions src/chain/electrum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock, Weak};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use std::time::Duration;

use bdk_chain::bdk_core::spk_client::{
FullScanRequest as BdkFullScanRequest, FullScanResponse as BdkFullScanResponse,
Expand Down Expand Up @@ -38,6 +38,7 @@ use crate::fee_estimator::{
use crate::io::utils::update_and_persist_node_metrics;
use crate::logger::{log_bytes, log_debug, log_error, log_trace, log_warn, LdkLogger, Logger};
use crate::runtime::Runtime;
use crate::time::{self, Instant};
use crate::tx_broadcaster::SortedTransactions;
use crate::types::{ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet};
use crate::PersistedNodeMetrics;
Expand Down Expand Up @@ -202,8 +203,7 @@ impl ElectrumChainSource {
if incremental_sync { "Incremental sync" } else { "Sync" },
now.elapsed().as_millis()
);
let unix_time_secs_opt =
SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs());
let unix_time_secs_opt = time::unix_time_secs();
update_and_persist_node_metrics(
&self.node_metrics,
&*self.kv_store,
Expand Down Expand Up @@ -275,8 +275,7 @@ impl ElectrumChainSource {
let res = electrum_client.sync_confirmables(vec![confirmable]).await;

if let Ok(_) = res {
let unix_time_secs_opt =
SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs());
let unix_time_secs_opt = time::unix_time_secs();
update_and_persist_node_metrics(
&self.node_metrics,
&*self.kv_store,
Expand Down Expand Up @@ -310,8 +309,7 @@ impl ElectrumChainSource {
now.elapsed().as_millis()
);

let unix_time_secs_opt =
SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs());
let unix_time_secs_opt = time::unix_time_secs();
update_and_persist_node_metrics(&self.node_metrics, &*self.kv_store, &*self.logger, |m| {
m.latest_fee_rate_cache_update_timestamp = unix_time_secs_opt
})
Expand Down
Loading
Loading