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
30 changes: 15 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@ postgres = ["dep:tokio-postgres", "dep:native-tls", "dep:postgres-native-tls"]
#lightning-macros = { version = "0.2.0" }
#lightning-dns-resolver = { version = "0.3.0" }

lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["std"] }
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["std"] }
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["tokio"] }
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["rest-client", "rpc-client", "tokio"] }
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["std"] }
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341", features = ["std"] }
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341" }
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341", features = ["std"] }
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341" }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341", features = ["tokio"] }
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341" }
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341" }
lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341", features = ["rest-client", "rpc-client", "tokio"] }
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341", features = ["std"] }
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341" }
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341" }

bdk_chain = { version = "0.23.3", default-features = false, features = ["std"] }
bdk_esplora = { version = "0.22.2", default-features = false, features = ["async-https-rustls", "tokio"]}
Expand Down Expand Up @@ -85,14 +85,14 @@ postgres-native-tls = { version = "0.5", default-features = false, features = ["
vss-client = { package = "vss-client-ng", version = "0.6" }
prost = { version = "0.11.6", default-features = false}
#bitcoin-payment-instructions = { version = "0.6" }
bitcoin-payment-instructions = { git = "https://github.com/tnull/bitcoin-payment-instructions", rev = "0e430be98c09540624a68a68022ee0551e86d1be" }
bitcoin-payment-instructions = { git = "https://github.com/benthecarman/bitcoin-payment-instructions", rev = "766f554ee0e44f4fb209f14c56c8b8bd7dadb46b" }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }

[dev-dependencies]
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["std", "_test_utils"] }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["tokio"] }
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341", features = ["std", "_test_utils"] }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "f680fd37d8bea69383e1b18730423f347e6a8341", features = ["tokio"] }
rand = { version = "0.9.2", default-features = false, features = ["std", "thread_rng", "os_rng"] }
proptest = "1.0.0"
regex = "1.5.6"
Expand Down
20 changes: 20 additions & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ typedef dictionary ElectrumSyncConfig;

typedef dictionary TorConfig;

typedef enum ForwardedPaymentTrackingMode;

typedef interface NodeEntropy;

typedef interface ProbingConfig;
Expand Down Expand Up @@ -113,6 +115,7 @@ interface Node {
OnchainPayment onchain_payment();
UnifiedPayment unified_payment();
Liquidity liquidity();
Forwarding forwarding();
[Throws=NodeError]
void lnurl_auth(string lnurl);
[Throws=NodeError]
Expand Down Expand Up @@ -184,6 +187,8 @@ typedef interface UnifiedPayment;

typedef interface Liquidity;

typedef interface Forwarding;

[Error]
enum NodeError {
"AlreadyRunning",
Expand Down Expand Up @@ -407,6 +412,9 @@ typedef string PaymentSecret;
[Custom]
typedef string ChannelId;

[Custom]
typedef string PageToken;

[Custom]
typedef string UserChannelId;

Expand All @@ -433,3 +441,15 @@ typedef enum Event;
typedef interface HRNResolverConfig;

typedef dictionary HumanReadableNamesConfig;

typedef dictionary ForwardedPaymentDetails;

typedef dictionary ChannelForwardingStats;

typedef dictionary ChannelPairForwardingStats;

typedef dictionary ForwardedPaymentDetailsPage;

typedef dictionary ChannelForwardingStatsPage;

typedef dictionary ChannelPairForwardingStatsPage;
133 changes: 114 additions & 19 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,13 @@ use crate::io::utils::{
};
use crate::io::vss_store::VssStoreBuilder;
use crate::io::{
self, PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
self, CHANNEL_FORWARDING_STATS_PERSISTENCE_PRIMARY_NAMESPACE,
CHANNEL_FORWARDING_STATS_PERSISTENCE_SECONDARY_NAMESPACE,
CHANNEL_PAIR_FORWARDING_STATS_PERSISTENCE_PRIMARY_NAMESPACE,
CHANNEL_PAIR_FORWARDING_STATS_PERSISTENCE_SECONDARY_NAMESPACE,
FORWARDED_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
FORWARDED_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
PENDING_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
PENDING_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
};
Expand All @@ -82,7 +88,8 @@ use crate::probing::{
use crate::runtime::{Runtime, RuntimeSpawner};
use crate::tx_broadcaster::TransactionBroadcaster;
use crate::types::{
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreRef, DynStoreWrapper,
AsyncPersister, ChainMonitor, ChannelForwardingStatsStore, ChannelManager,
ChannelPairForwardingStatsStore, DynStore, DynStoreRef, DynStoreWrapper, ForwardedPaymentStore,
GossipSync, Graph, HRNResolver, KeysManager, MessageRouter, OnionMessenger, PaymentStore,
PeerManager, PendingPaymentStore,
};
Expand Down Expand Up @@ -1439,24 +1446,48 @@ fn build_with_store_internal(

let kv_store_ref = Arc::clone(&kv_store);
let logger_ref = Arc::clone(&logger);
let (payment_store_res, node_metris_res, pending_payment_store_res) =
runtime.block_on(async move {
tokio::join!(
read_all_objects(
&*kv_store_ref,
PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
Arc::clone(&logger_ref),
),
read_node_metrics(&*kv_store_ref, Arc::clone(&logger_ref)),
read_all_objects(
&*kv_store_ref,
PENDING_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
PENDING_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
Arc::clone(&logger_ref),
)
let (
payment_store_res,
forwarded_payment_store_res,
channel_forwarding_stats_res,
channel_pair_forwarding_stats_res,
node_metris_res,
pending_payment_store_res,
) = runtime.block_on(async move {
tokio::join!(
read_all_objects(
&*kv_store_ref,
PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
Arc::clone(&logger_ref),
),
read_all_objects(
&*kv_store_ref,
FORWARDED_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
FORWARDED_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
Arc::clone(&logger_ref),
),
read_all_objects(
&*kv_store_ref,
CHANNEL_FORWARDING_STATS_PERSISTENCE_PRIMARY_NAMESPACE,
CHANNEL_FORWARDING_STATS_PERSISTENCE_SECONDARY_NAMESPACE,
Arc::clone(&logger_ref),
),
read_all_objects(
&*kv_store_ref,
CHANNEL_PAIR_FORWARDING_STATS_PERSISTENCE_PRIMARY_NAMESPACE,
CHANNEL_PAIR_FORWARDING_STATS_PERSISTENCE_SECONDARY_NAMESPACE,
Arc::clone(&logger_ref),
),
read_node_metrics(&*kv_store_ref, Arc::clone(&logger_ref)),
read_all_objects(
&*kv_store_ref,
PENDING_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
PENDING_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
Arc::clone(&logger_ref),
)
});
)
});

// Initialize the status fields.
let node_metrics = match node_metris_res {
Expand Down Expand Up @@ -1485,6 +1516,55 @@ fn build_with_store_internal(
},
};

let (forwarded_payment_store, has_stored_forwarded_payments) = match forwarded_payment_store_res
{
Ok(forwarded_payments) => {
let has_stored_forwarded_payments = !forwarded_payments.is_empty();
(
Arc::new(ForwardedPaymentStore::new(
forwarded_payments,
FORWARDED_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE.to_string(),
FORWARDED_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE.to_string(),
Arc::clone(&kv_store),
Arc::clone(&logger),
)),
has_stored_forwarded_payments,
)
},
Err(e) => {
log_error!(logger, "Failed to read forwarded payment data from store: {}", e);
return Err(BuildError::ReadFailed);
},
};

let channel_forwarding_stats_store = match channel_forwarding_stats_res {
Ok(stats) => Arc::new(ChannelForwardingStatsStore::new(
stats,
CHANNEL_FORWARDING_STATS_PERSISTENCE_PRIMARY_NAMESPACE.to_string(),
CHANNEL_FORWARDING_STATS_PERSISTENCE_SECONDARY_NAMESPACE.to_string(),
Arc::clone(&kv_store),
Arc::clone(&logger),
)),
Err(e) => {
log_error!(logger, "Failed to read channel forwarding stats from store: {}", e);
return Err(BuildError::ReadFailed);
},
};

let channel_pair_forwarding_stats_store = match channel_pair_forwarding_stats_res {
Ok(stats) => Arc::new(ChannelPairForwardingStatsStore::new(
stats,
CHANNEL_PAIR_FORWARDING_STATS_PERSISTENCE_PRIMARY_NAMESPACE.to_string(),
CHANNEL_PAIR_FORWARDING_STATS_PERSISTENCE_SECONDARY_NAMESPACE.to_string(),
Arc::clone(&kv_store),
Arc::clone(&logger),
)),
Err(e) => {
log_error!(logger, "Failed to read channel pair forwarding stats from store: {}", e);
return Err(BuildError::ReadFailed);
},
};

let (chain_source, chain_tip_opt) = match chain_data_source_config {
Some(ChainDataSourceConfig::Esplora { server_url, headers, sync_config }) => {
let sync_config = sync_config.unwrap_or(EsploraSyncConfig::default());
Expand Down Expand Up @@ -2306,6 +2386,17 @@ fn build_with_store_internal(
})
});

let forwarded_payment_aggregation_retention_secs = match config.forwarded_payment_tracking_mode
{
crate::config::ForwardedPaymentTrackingMode::Detailed => {
Some(crate::payment::store::FORWARDED_PAYMENT_AGGREGATION_BUCKET_SIZE_SECS)
},
crate::config::ForwardedPaymentTrackingMode::Stats if has_stored_forwarded_payments => {
Some(0)
},
_ => None,
};

Ok(Node {
runtime,
stop_sender,
Expand Down Expand Up @@ -2333,6 +2424,10 @@ fn build_with_store_internal(
scorer,
peer_store,
payment_store,
forwarded_payment_store,
channel_forwarding_stats_store,
channel_pair_forwarding_stats_store,
forwarded_payment_aggregation_retention_secs,
lnurl_auth,
is_running,
node_metrics,
Expand Down
29 changes: 27 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,27 @@ pub(crate) const LIQUIDITY_DISCOVERY_RETRY_INITIAL_DELAY: Duration = Duration::f
// thereafter until every configured LSP has been discovered.
pub(crate) const LIQUIDITY_DISCOVERY_RETRY_MAX_DELAY: Duration = Duration::from_secs(60 * 60);

/// The mode used for tracking forwarded payments.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
pub enum ForwardedPaymentTrackingMode {
/// Track new forwarded payments only as per-channel aggregate statistics.
///
/// Any detailed records left by a previous configuration are aggregated and removed after their
/// current one-hour bucket closes.
Stats,
/// Store individual forwarded payments for the current and previous one-hour buckets.
///
/// Payments from older buckets are aggregated into channel-pair statistics and removed.
Detailed,
}

impl Default for ForwardedPaymentTrackingMode {
fn default() -> Self {
Self::Stats
}
}

#[derive(Debug, Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
/// Represents the configuration of an [`Node`] instance.
Expand All @@ -155,9 +176,10 @@ pub(crate) const LIQUIDITY_DISCOVERY_RETRY_MAX_DELAY: Duration = Duration::from_
/// | `route_parameters` | None |
/// | `tor_config` | None |
/// | `hrn_config` | HumanReadableNamesConfig::default() |
/// | `forwarded_payment_tracking_mode` | Stats |
///
/// See [`AnchorChannelsConfig`] and [`RouteParametersConfig`] for more information regarding their
/// respective default values.
/// See [`AnchorChannelsConfig`], [`RouteParametersConfig`], and
/// [`ForwardedPaymentTrackingMode`] for more information regarding their respective default values.
///
/// [`Node`]: crate::Node
pub struct Config {
Expand Down Expand Up @@ -219,6 +241,8 @@ pub struct Config {
///
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
pub hrn_config: HumanReadableNamesConfig,
/// The mode used for tracking forwarded payments.
pub forwarded_payment_tracking_mode: ForwardedPaymentTrackingMode,
}

impl Default for Config {
Expand All @@ -235,6 +259,7 @@ impl Default for Config {
route_parameters: None,
node_alias: None,
hrn_config: HumanReadableNamesConfig::default(),
forwarded_payment_tracking_mode: ForwardedPaymentTrackingMode::default(),
}
}
}
Expand Down
Loading
Loading