- name: For each commit, run cargo check (including in fuzz)
run: ci/check-each-commit.sh upstream/main
+ check_release:
+ runs-on: ubuntu-latest
+ env:
+ TOOLCHAIN: stable
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ env.TOOLCHAIN }}
+ override: true
+ profile: minimal
+ - name: Run cargo check for release build.
+ run: |
+ cargo check --release
+ cargo check --no-default-features --features=no-std --release
+ cargo doc --release
+
fuzz:
runs-on: ubuntu-latest
env:
+# 0.0.108 - 2022-06-10
+
+## Bug Fixes
+ * Fixed `lightning-background-processor` build in release mode.
+
+In total, this release features 9 files changed, 120 insertions, 74
+deletions in 5 commits from 4 authors, in alphabetical order:
+ * Elias Rohrer
+ * Matt Corallo
+ * Max Fang
+ * Viktor Tigerström
+
# 0.0.107 - 2022-06-08
## API Updates
Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(&keys_manager)));
let mut config = UserConfig::default();
- config.channel_options.forwarding_fee_proportional_millionths = 0;
- config.channel_options.announced_channel = true;
+ config.channel_config.forwarding_fee_proportional_millionths = 0;
+ config.channel_handshake_config.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
network,
Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(& $keys_manager)));
let mut config = UserConfig::default();
- config.channel_options.forwarding_fee_proportional_millionths = 0;
- config.channel_options.announced_channel = true;
+ config.channel_config.forwarding_fee_proportional_millionths = 0;
+ config.channel_handshake_config.announced_channel = true;
let mut monitors = HashMap::new();
let mut old_monitors = $old_monitors.latest_monitors.lock().unwrap();
let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone(), inbound_payment_key: KeyMaterial(inbound_payment_key.try_into().unwrap()), counter: AtomicU64::new(0) });
let mut config = UserConfig::default();
- config.channel_options.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
- config.channel_options.announced_channel = get_slice!(1)[0] != 0;
+ config.channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
+ config.channel_handshake_config.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
network,
/// Actual fuzz test, method signature and name are fixed
fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let block_hash = bitcoin::BlockHash::default();
- let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new("".to_owned(), out));
- let network_graph = lightning::routing::gossip::NetworkGraph::new(block_hash, logger);
+ let logger = test_logger::TestLogger::new("".to_owned(), out);
+ let network_graph = lightning::routing::gossip::NetworkGraph::new(block_hash, &logger);
let rapid_sync = RapidGossipSync::new(&network_graph);
let _ = rapid_sync.update_network_graph(data);
}
}
}
- let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new("".to_owned(), out));
+ let logger = test_logger::TestLogger::new("".to_owned(), out);
let our_pubkey = get_pubkey!();
- let net_graph = NetworkGraph::new(genesis_block(Network::Bitcoin).header.block_hash(), Arc::clone(&logger));
+ let net_graph = NetworkGraph::new(genesis_block(Network::Bitcoin).header.block_hash(), &logger);
let mut node_pks = HashSet::new();
let mut scid = 42;
};
let _ = find_route(&our_pubkey, &route_params, &net_graph.read_only(),
first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),
- Arc::clone(&logger), &scorer, &random_seed_bytes);
+ &logger, &scorer, &random_seed_bytes);
}
},
}
[package]
name = "lightning-background-processor"
-version = "0.0.107"
+version = "0.0.108"
authors = ["Valentine Wallace <vwallace@protonmail.com>"]
license = "MIT OR Apache-2.0"
repository = "http://github.com/lightningdevkit/rust-lightning"
[dependencies]
bitcoin = "0.28.1"
-lightning = { version = "0.0.107", path = "../lightning", features = ["std"] }
-lightning-rapid-gossip-sync = { version = "0.0.107", path = "../lightning-rapid-gossip-sync" }
+lightning = { version = "0.0.108", path = "../lightning", features = ["std"] }
+lightning-rapid-gossip-sync = { version = "0.0.108", path = "../lightning-rapid-gossip-sync" }
[dev-dependencies]
-lightning = { version = "0.0.107", path = "../lightning", features = ["_test_utils"] }
-lightning-invoice = { version = "0.15.0", path = "../lightning-invoice" }
-lightning-persister = { version = "0.0.107", path = "../lightning-persister" }
+lightning = { version = "0.0.108", path = "../lightning", features = ["_test_utils"] }
+lightning-invoice = { version = "0.16.0", path = "../lightning-invoice" }
+lightning-persister = { version = "0.0.108", path = "../lightning-persister" }
/// Prune the network graph of stale entries hourly.
const NETWORK_PRUNE_TIMER: u64 = 60 * 60;
-#[cfg(all(not(test), debug_assertions))]
+#[cfg(not(test))]
const SCORER_PERSIST_TIMER: u64 = 30;
#[cfg(test)]
const SCORER_PERSIST_TIMER: u64 = 1;
///
/// # Rapid Gossip Sync
///
- /// If rapid gossip sync is meant to run at startup, pass a [`RapidGossipSync`] to `gossip_sync`
+ /// If rapid gossip sync is meant to run at startup, pass [`RapidGossipSync`] via `gossip_sync`
/// to indicate that the [`BackgroundProcessor`] should not prune the [`NetworkGraph`] instance
/// until the [`RapidGossipSync`] instance completes its first sync.
///
[package]
name = "lightning-block-sync"
-version = "0.0.107"
+version = "0.0.108"
authors = ["Jeffrey Czyz", "Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "http://github.com/lightningdevkit/rust-lightning"
[dependencies]
bitcoin = "0.28.1"
-lightning = { version = "0.0.107", path = "../lightning" }
+lightning = { version = "0.0.108", path = "../lightning" }
futures = { version = "0.3" }
tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
[package]
name = "lightning-invoice"
description = "Data structures to parse and serialize BOLT11 lightning invoices"
-version = "0.15.0"
+version = "0.16.0"
authors = ["Sebastian Geisler <sgeisler@wh2.tu-dresden.de>"]
documentation = "https://docs.rs/lightning-invoice/"
license = "MIT OR Apache-2.0"
[dependencies]
bech32 = { version = "0.8", default-features = false }
-lightning = { version = "0.0.107", path = "../lightning", default-features = false }
+lightning = { version = "0.0.108", path = "../lightning", default-features = false }
secp256k1 = { version = "0.22", default-features = false, features = ["recovery", "alloc"] }
num-traits = { version = "0.2.8", default-features = false }
bitcoin_hashes = { version = "0.10", default-features = false }
core2 = { version = "0.3.0", default-features = false, optional = true }
[dev-dependencies]
-lightning = { version = "0.0.107", path = "../lightning", default-features = false, features = ["_test_utils"] }
+lightning = { version = "0.0.108", path = "../lightning", default-features = false, features = ["_test_utils"] }
hex = "0.4"
// `msgs::ChannelUpdate` is never handled for the node(s). As the `msgs::ChannelUpdate`
// is never handled, the `channel.counterparty.forwarding_info` is never assigned.
let mut private_chan_cfg = UserConfig::default();
- private_chan_cfg.channel_options.announced_channel = false;
+ private_chan_cfg.channel_handshake_config.announced_channel = false;
let temporary_channel_id = nodes[2].node.create_channel(nodes[0].node.get_our_node_id(), 1_000_000, 500_000_000, 42, Some(private_chan_cfg)).unwrap();
let open_channel = get_event_msg!(nodes[2], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
nodes[0].node.handle_open_channel(&nodes[2].node.get_our_node_id(), InitFeatures::known(), &open_channel);
// `msgs::ChannelUpdate` is never handled for the node(s). As the `msgs::ChannelUpdate`
// is never handled, the `channel.counterparty.forwarding_info` is never assigned.
let mut private_chan_cfg = UserConfig::default();
- private_chan_cfg.channel_options.announced_channel = false;
+ private_chan_cfg.channel_handshake_config.announced_channel = false;
let temporary_channel_id = nodes[1].node.create_channel(nodes[3].node.get_our_node_id(), 1_000_000, 500_000_000, 42, Some(private_chan_cfg)).unwrap();
let open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[3].node.get_our_node_id());
nodes[3].node.handle_open_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel);
[package]
name = "lightning-net-tokio"
-version = "0.0.107"
+version = "0.0.108"
authors = ["Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning/"
[dependencies]
bitcoin = "0.28.1"
-lightning = { version = "0.0.107", path = "../lightning" }
+lightning = { version = "0.0.108", path = "../lightning" }
tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "sync", "net", "time" ] }
[dev-dependencies]
[package]
name = "lightning-persister"
-version = "0.0.107"
+version = "0.0.108"
authors = ["Valentine Wallace", "Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning/"
[dependencies]
bitcoin = "0.28.1"
-lightning = { version = "0.0.107", path = "../lightning" }
+lightning = { version = "0.0.108", path = "../lightning" }
libc = "0.2"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }
[dev-dependencies]
-lightning = { version = "0.0.107", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.108", path = "../lightning", features = ["_test_utils"] }
[package]
name = "lightning-rapid-gossip-sync"
-version = "0.0.107"
+version = "0.0.108"
authors = ["Arik Sosman <git@arik.io>"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning"
_bench_unstable = []
[dependencies]
-lightning = { version = "0.0.107", path = "../lightning" }
+lightning = { version = "0.0.108", path = "../lightning" }
bitcoin = { version = "0.28.1", default-features = false }
[dev-dependencies]
-lightning = { version = "0.0.107", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.108", path = "../lightning", features = ["_test_utils"] }
[package]
name = "lightning"
-version = "0.0.107"
+version = "0.0.108"
authors = ["Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning/"
// Test that temporary failures when updating the monitor's shutdown script delay cooperative
// close.
let mut config = test_default_channel_config();
- config.channel_options.commit_upfront_shutdown_pubkey = false;
+ config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
// Test that permanent failures when updating the monitor's shutdown script result in a force
// close when initiating a cooperative close.
let mut config = test_default_channel_config();
- config.channel_options.commit_upfront_shutdown_pubkey = false;
+ config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
// Test that permanent failures when updating the monitor's shutdown script result in a force
// close when handling a cooperative close.
let mut config = test_default_channel_config();
- config.channel_options.commit_upfront_shutdown_pubkey = false;
+ config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
-use util::config::{UserConfig, ChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits};
+use util::config::{UserConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits};
use util::scid_utils::scid_from_parts;
use io;
// Counterparty designates channel data owned by the another channel participant entity.
pub(super) struct Channel<Signer: Sign> {
#[cfg(any(test, feature = "_test_utils"))]
- pub(crate) config: ChannelConfig,
+ pub(crate) config: LegacyChannelConfig,
#[cfg(not(any(test, feature = "_test_utils")))]
- config: ChannelConfig,
+ config: LegacyChannelConfig,
inbound_handshake_limits_override: Option<ChannelHandshakeLimits>,
// available. If it's private, we first try `scid_privacy` as it provides better privacy
// with no other changes, and fall back to `only_static_remotekey`
let mut ret = ChannelTypeFeatures::only_static_remote_key();
- if !config.channel_options.announced_channel && config.own_channel_config.negotiate_scid_privacy {
+ if !config.channel_handshake_config.announced_channel && config.channel_handshake_config.negotiate_scid_privacy {
ret.set_scid_privacy_required();
}
ret
{
let opt_anchors = false; // TODO - should be based on features
- let holder_selected_contest_delay = config.own_channel_config.our_to_self_delay;
+ let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay;
let holder_signer = keys_provider.get_channel_signer(false, channel_value_satoshis);
let pubkeys = holder_signer.pubkeys().clone();
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes());
- let shutdown_scriptpubkey = if config.channel_options.commit_upfront_shutdown_pubkey {
+ let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey {
Some(keys_provider.get_shutdown_scriptpubkey())
} else { None };
Ok(Channel {
user_id,
- config: config.channel_options.clone(),
- inbound_handshake_limits_override: Some(config.peer_channel_config_limits.clone()),
+
+ config: LegacyChannelConfig {
+ options: config.channel_config.clone(),
+ announced_channel: config.channel_handshake_config.announced_channel,
+ commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey,
+ },
+
+ inbound_handshake_limits_override: Some(config.channel_handshake_limits.clone()),
channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
counterparty_dust_limit_satoshis: 0,
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
counterparty_max_htlc_value_in_flight_msat: 0,
- holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.own_channel_config),
+ holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel
holder_selected_channel_reserve_satoshis,
counterparty_htlc_minimum_msat: 0,
- holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
+ holder_htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
counterparty_max_accepted_htlcs: 0,
minimum_depth: None, // Filled in in accept_channel
channel_transaction_parameters: ChannelTransactionParameters {
holder_pubkeys: pubkeys,
- holder_selected_contest_delay: config.own_channel_config.our_to_self_delay,
+ holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay,
is_outbound_from_holder: true,
counterparty_parameters: None,
funding_outpoint: None,
delayed_payment_basepoint: msg.delayed_payment_basepoint,
htlc_basepoint: msg.htlc_basepoint
};
- let mut local_config = (*config).channel_options.clone();
- if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
- return Err(ChannelError::Close(format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks. It must be greater than {}", config.own_channel_config.our_to_self_delay, BREAKDOWN_TIMEOUT)));
+ if config.channel_handshake_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
+ return Err(ChannelError::Close(format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks. It must be greater than {}", config.channel_handshake_config.our_to_self_delay, BREAKDOWN_TIMEOUT)));
}
// Check sanity of message fields:
- if msg.funding_satoshis > config.peer_channel_config_limits.max_funding_satoshis {
- return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.peer_channel_config_limits.max_funding_satoshis, msg.funding_satoshis)));
+ if msg.funding_satoshis > config.channel_handshake_limits.max_funding_satoshis {
+ return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.channel_handshake_limits.max_funding_satoshis, msg.funding_satoshis)));
}
if msg.funding_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS {
return Err(ChannelError::Close(format!("Funding must be smaller than the total bitcoin supply. It was {}", msg.funding_satoshis)));
}
Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
- let max_counterparty_selected_contest_delay = u16::min(config.peer_channel_config_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
+ let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
if msg.to_self_delay > max_counterparty_selected_contest_delay {
return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_counterparty_selected_contest_delay, msg.to_self_delay)));
}
}
// Now check against optional parameters as set by config...
- if msg.funding_satoshis < config.peer_channel_config_limits.min_funding_satoshis {
- return Err(ChannelError::Close(format!("Funding satoshis ({}) is less than the user specified limit ({})", msg.funding_satoshis, config.peer_channel_config_limits.min_funding_satoshis)));
+ if msg.funding_satoshis < config.channel_handshake_limits.min_funding_satoshis {
+ return Err(ChannelError::Close(format!("Funding satoshis ({}) is less than the user specified limit ({})", msg.funding_satoshis, config.channel_handshake_limits.min_funding_satoshis)));
}
- if msg.htlc_minimum_msat > config.peer_channel_config_limits.max_htlc_minimum_msat {
- return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat, config.peer_channel_config_limits.max_htlc_minimum_msat)));
+ if msg.htlc_minimum_msat > config.channel_handshake_limits.max_htlc_minimum_msat {
+ return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat, config.channel_handshake_limits.max_htlc_minimum_msat)));
}
- if msg.max_htlc_value_in_flight_msat < config.peer_channel_config_limits.min_max_htlc_value_in_flight_msat {
- return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, config.peer_channel_config_limits.min_max_htlc_value_in_flight_msat)));
+ if msg.max_htlc_value_in_flight_msat < config.channel_handshake_limits.min_max_htlc_value_in_flight_msat {
+ return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, config.channel_handshake_limits.min_max_htlc_value_in_flight_msat)));
}
- if msg.channel_reserve_satoshis > config.peer_channel_config_limits.max_channel_reserve_satoshis {
- return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, config.peer_channel_config_limits.max_channel_reserve_satoshis)));
+ if msg.channel_reserve_satoshis > config.channel_handshake_limits.max_channel_reserve_satoshis {
+ return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, config.channel_handshake_limits.max_channel_reserve_satoshis)));
}
- if msg.max_accepted_htlcs < config.peer_channel_config_limits.min_max_accepted_htlcs {
- return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, config.peer_channel_config_limits.min_max_accepted_htlcs)));
+ if msg.max_accepted_htlcs < config.channel_handshake_limits.min_max_accepted_htlcs {
+ return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, config.channel_handshake_limits.min_max_accepted_htlcs)));
}
if msg.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
// Convert things into internal flags and prep our state:
- if config.peer_channel_config_limits.force_announced_channel_preference {
- if local_config.announced_channel != announced_channel {
+ if config.channel_handshake_limits.force_announced_channel_preference {
+ if config.channel_handshake_config.announced_channel != announced_channel {
return Err(ChannelError::Close("Peer tried to open channel but their announcement preference is different from ours".to_owned()));
}
}
- // we either accept their preference or the preferences match
- local_config.announced_channel = announced_channel;
let holder_selected_channel_reserve_satoshis = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis);
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
}
} else { None };
- let shutdown_scriptpubkey = if config.channel_options.commit_upfront_shutdown_pubkey {
+ let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey {
Some(keys_provider.get_shutdown_scriptpubkey())
} else { None };
let chan = Channel {
user_id,
- config: local_config,
+
+ config: LegacyChannelConfig {
+ options: config.channel_config.clone(),
+ announced_channel,
+ commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey,
+ },
+
inbound_handshake_limits_override: None,
channel_id: msg.temporary_channel_id,
counterparty_dust_limit_satoshis: msg.dust_limit_satoshis,
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
- holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis, &config.own_channel_config),
+ holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis, &config.channel_handshake_config),
counterparty_selected_channel_reserve_satoshis: Some(msg.channel_reserve_satoshis),
holder_selected_channel_reserve_satoshis,
counterparty_htlc_minimum_msat: msg.htlc_minimum_msat,
- holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
+ holder_htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
counterparty_max_accepted_htlcs: msg.max_accepted_htlcs,
- minimum_depth: Some(cmp::max(config.own_channel_config.minimum_depth, 1)),
+ minimum_depth: Some(cmp::max(config.channel_handshake_config.minimum_depth, 1)),
counterparty_forwarding_info: None,
channel_transaction_parameters: ChannelTransactionParameters {
holder_pubkeys: pubkeys,
- holder_selected_contest_delay: config.own_channel_config.our_to_self_delay,
+ holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay,
is_outbound_from_holder: false,
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {
selected_contest_delay: msg.to_self_delay,
// We always add force_close_avoidance_max_fee_satoshis to our normal
// feerate-calculated fee, but allow the max to be overridden if we're using a
// target feerate-calculated fee.
- cmp::max(normal_feerate as u64 * tx_weight / 1000 + self.config.force_close_avoidance_max_fee_satoshis,
+ cmp::max(normal_feerate as u64 * tx_weight / 1000 + self.config.options.force_close_avoidance_max_fee_satoshis,
proposed_max_feerate as u64 * tx_weight / 1000)
} else {
self.channel_value_satoshis - (self.value_to_self_msat + 999) / 1000
}
pub fn get_fee_proportional_millionths(&self) -> u32 {
- self.config.forwarding_fee_proportional_millionths
+ self.config.options.forwarding_fee_proportional_millionths
}
pub fn get_cltv_expiry_delta(&self) -> u16 {
- cmp::max(self.config.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
+ cmp::max(self.config.options.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}
pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
- self.config.max_dust_htlc_exposure_msat
+ self.config.options.max_dust_htlc_exposure_msat
}
pub fn get_feerate(&self) -> u32 {
/// Gets the fee we'd want to charge for adding an HTLC output to this Channel
/// Allowed in any state (including after shutdown)
pub fn get_outbound_forwarding_fee_base_msat(&self) -> u32 {
- self.config.forwarding_fee_base_msat
+ self.config.options.forwarding_fee_base_msat
}
/// Returns true if we've ever received a message from the remote end for this Channel
if self.holder_selected_channel_reserve_satoshis != Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis)
{ Some(self.holder_selected_channel_reserve_satoshis) } else { None };
- let mut old_max_in_flight_percent_config = UserConfig::default().own_channel_config;
+ let mut old_max_in_flight_percent_config = UserConfig::default().channel_handshake_config;
old_max_in_flight_percent_config.max_inbound_htlc_value_in_flight_percent_of_channel = MAX_IN_FLIGHT_PERCENT_LEGACY;
let serialized_holder_htlc_max_in_flight =
if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis, &old_max_in_flight_percent_config)
let user_id = Readable::read(reader)?;
- let mut config = Some(ChannelConfig::default());
+ let mut config = Some(LegacyChannelConfig::default());
if ver == 1 {
// Read the old serialization of the ChannelConfig from version 0.0.98.
- config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
- config.as_mut().unwrap().cltv_expiry_delta = Readable::read(reader)?;
+ config.as_mut().unwrap().options.forwarding_fee_proportional_millionths = Readable::read(reader)?;
+ config.as_mut().unwrap().options.cltv_expiry_delta = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
let mut target_closing_feerate_sats_per_kw = None;
let mut monitor_pending_finalized_fulfills = Some(Vec::new());
let mut holder_selected_channel_reserve_satoshis = Some(Self::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis));
- let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &UserConfig::default().own_channel_config));
+ let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &UserConfig::default().channel_handshake_config));
// Prior to supporting channel type negotiation, all of our channels were static_remotekey
// only, so we default to that if none was written.
let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key());
// Node B --> Node A: accept channel, explicitly setting B's dust limit.
let mut accept_channel_msg = node_b_chan.accept_inbound_channel(0);
accept_channel_msg.dust_limit_satoshis = 546;
- node_a_chan.accept_channel(&accept_channel_msg, &config.peer_channel_config_limits, &InitFeatures::known()).unwrap();
+ node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &InitFeatures::known()).unwrap();
node_a_chan.holder_dust_limit_satoshis = 1560;
// Put some inbound and outbound HTLCs in A's channel.
// Node B --> Node A: accept channel
let accept_channel_msg = node_b_chan.accept_inbound_channel(0);
- node_a_chan.accept_channel(&accept_channel_msg, &config.peer_channel_config_limits, &InitFeatures::known()).unwrap();
+ node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &InitFeatures::known()).unwrap();
// Node A --> Node B: funding created
let output_script = node_a_chan.get_funding_redeemscript();
let inbound_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
let mut config_2_percent = UserConfig::default();
- config_2_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 2;
+ config_2_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 2;
let mut config_99_percent = UserConfig::default();
- config_99_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 99;
+ config_99_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 99;
let mut config_0_percent = UserConfig::default();
- config_0_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 0;
+ config_0_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 0;
let mut config_101_percent = UserConfig::default();
- config_101_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 101;
+ config_101_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 101;
// Test that `new_outbound` creates a channel with the correct value for
// `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value,
let counterparty_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let mut config = UserConfig::default();
- config.channel_options.announced_channel = false;
+ config.channel_handshake_config.announced_channel = false;
let mut chan = Channel::<InMemorySigner>::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config, 0, 42).unwrap(); // Nothing uses their network key in this test
chan.holder_dust_limit_satoshis = 546;
chan.counterparty_selected_channel_reserve_satoshis = Some(0); // Filled in in accept_channel
if route.paths.len() < 1 {
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
}
- if route.paths.len() > 10 {
- // This limit is completely arbitrary - there aren't any real fundamental path-count
- // limits. After we support retrying individual paths we should likely bump this, but
- // for now more than 10 paths likely carries too much one-path failure.
- return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Sending over more than 10 paths is not currently supported"}));
- }
if payment_secret.is_none() && route.paths.len() > 1 {
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError{err: "Payment secret is required for multi-path payments".to_string()}));
}
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.temporary_channel_id));
}
- try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration.peer_channel_config_limits, &their_features), channel_state, chan);
+ try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration.channel_handshake_limits, &their_features), channel_state, chan);
(chan.get().get_value_satoshis(), chan.get().get_funding_redeemscript().to_v0_p2wsh(), chan.get().get_user_id())
},
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.temporary_channel_id))
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
let mut config: UserConfig = Default::default();
- config.own_channel_config.minimum_depth = 1;
+ config.channel_handshake_config.minimum_depth = 1;
let logger_a = test_utils::TestLogger::with_id("node a".to_owned());
let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a);
//! supports a feature if it advertises the feature (as either required or optional) to its peers.
//! And the implementation can interpret a feature if the feature is known to it.
//!
+//! The following features are currently required in the LDK:
+//! - `VariableLengthOnion` - requires/supports variable-length routing onion payloads
+//! (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md) for more information).
+//! - `StaticRemoteKey` - requires/supports static key for remote output
+//! (see [BOLT-3](https://github.com/lightning/bolts/blob/master/03-transactions.md) for more information).
+//!
+//! The following features are currently supported in the LDK:
+//! - `DataLossProtect` - requires/supports that a node which has somehow fallen behind, e.g., has been restored from an old backup,
+//! can detect that it has fallen behind
+//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
+//! - `InitialRoutingSync` - requires/supports that the sending node needs a complete routing information dump
+//! (see [BOLT-7](https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#initial-sync) for more information).
+//! - `UpfrontShutdownScript` - commits to a shutdown scriptpubkey when opening a channel
+//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-open_channel-message) for more information).
+//! - `GossipQueries` - requires/supports more sophisticated gossip control
+//! (see [BOLT-7](https://github.com/lightning/bolts/blob/master/07-routing-gossip.md) for more information).
+//! - `PaymentSecret` - requires/supports that a node supports payment_secret field
+//! (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md) for more information).
+//! - `BasicMPP` - requires/supports that a node can receive basic multi-part payments
+//! (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md#basic-multi-part-payments) for more information).
+//! - `ShutdownAnySegwit` - requires/supports that future segwit versions are allowed in `shutdown`
+//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
+//! - `ChannelType` - node supports the channel_type field in open/accept
+//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
+//! - `SCIDPrivacy` - supply channel aliases for routing
+//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
+//! - `Keysend` - send funds to a node without an invoice
+//! (see the [`Keysend` feature assignment proposal](https://github.com/lightning/bolts/issues/605#issuecomment-606679798) for more information).
+//!
//! [BOLT #9]: https://github.com/lightning/bolts/blob/master/09-features.md
//! [messages]: crate::ln::msgs
pub fn create_unannounced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize, channel_value: u64, push_msat: u64, a_flags: InitFeatures, b_flags: InitFeatures) -> (msgs::ChannelReady, Transaction) {
let mut no_announce_cfg = test_default_channel_config();
- no_announce_cfg.channel_options.announced_channel = false;
+ no_announce_cfg.channel_handshake_config.announced_channel = false;
nodes[a].node.create_channel(nodes[b].node.get_our_node_id(), channel_value, push_msat, 42, Some(no_announce_cfg)).unwrap();
let open_channel = get_event_msg!(nodes[a], MessageSendEvent::SendOpenChannel, nodes[b].node.get_our_node_id());
nodes[b].node.handle_open_channel(&nodes[a].node.get_our_node_id(), a_flags, &open_channel);
($node: expr, $prev_node: expr, $next_node: expr, $new_msgs: expr) => {
{
$node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0);
- let fee = $node.node.channel_state.lock().unwrap().by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap().config.forwarding_fee_base_msat;
+ let fee = $node.node.channel_state.lock().unwrap()
+ .by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap()
+ .config.options.forwarding_fee_base_msat;
expect_payment_forwarded!($node, $next_node, $prev_node, Some(fee as u64), false, false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
let mut default_config = UserConfig::default();
// Set cltv_expiry_delta slightly lower to keep the final CLTV values inside one byte in our
// tests so that our script-length checks don't fail (see ACCEPTED_HTLC_SCRIPT_WEIGHT).
- default_config.channel_options.cltv_expiry_delta = MIN_CLTV_EXPIRY_DELTA;
- default_config.channel_options.announced_channel = true;
- default_config.peer_channel_config_limits.force_announced_channel_preference = false;
+ default_config.channel_config.cltv_expiry_delta = MIN_CLTV_EXPIRY_DELTA;
+ default_config.channel_handshake_config.announced_channel = true;
+ default_config.channel_handshake_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
// It now defaults to 1, so we simply set it to the expected value here.
- default_config.own_channel_config.our_htlc_minimum_msat = 1000;
+ default_config.channel_handshake_config.our_htlc_minimum_msat = 1000;
// When most of our tests were written, we didn't have the notion of a `max_dust_htlc_exposure_msat`,
// It now defaults to 5_000_000 msat; to avoid interfering with tests we bump it to 50_000_000 msat.
- default_config.channel_options.max_dust_htlc_exposure_msat = 50_000_000;
+ default_config.channel_config.max_dust_htlc_exposure_msat = 50_000_000;
default_config
}
// Stand up a network of 2 nodes
use ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
let mut cfg = UserConfig::default();
- cfg.peer_channel_config_limits.max_funding_satoshis = TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1;
+ cfg.channel_handshake_limits.max_funding_satoshis = TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1;
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(cfg)]);
// When this test was written, the default base fee floated based on the HTLC count.
// It is now fixed, so we simply set the fee to the expected value here.
let mut config = test_default_channel_config();
- config.channel_options.forwarding_fee_base_msat = 239;
+ config.channel_config.forwarding_fee_base_msat = 239;
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config.clone()), Some(config.clone()), Some(config.clone())]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 190000, 1001, InitFeatures::known(), InitFeatures::known());
fn test_justice_tx() {
// Test justice txn built on revoked HTLC-Success tx, against both sides
let mut alice_config = UserConfig::default();
- alice_config.channel_options.announced_channel = true;
- alice_config.peer_channel_config_limits.force_announced_channel_preference = false;
- alice_config.own_channel_config.our_to_self_delay = 6 * 24 * 5;
+ alice_config.channel_handshake_config.announced_channel = true;
+ alice_config.channel_handshake_limits.force_announced_channel_preference = false;
+ alice_config.channel_handshake_config.our_to_self_delay = 6 * 24 * 5;
let mut bob_config = UserConfig::default();
- bob_config.channel_options.announced_channel = true;
- bob_config.peer_channel_config_limits.force_announced_channel_preference = false;
- bob_config.own_channel_config.our_to_self_delay = 6 * 24 * 3;
+ bob_config.channel_handshake_config.announced_channel = true;
+ bob_config.channel_handshake_limits.force_announced_channel_preference = false;
+ bob_config.channel_handshake_config.our_to_self_delay = 6 * 24 * 3;
let user_cfgs = [Some(alice_config), Some(bob_config)];
let mut chanmon_cfgs = create_chanmon_cfgs(2);
chanmon_cfgs[0].keys_manager.disable_revocation_policy_check = true;
// When this test was written, the default base fee floated based on the HTLC count.
// It is now fixed, so we simply set the fee to the expected value here.
let mut config = test_default_channel_config();
- config.channel_options.forwarding_fee_base_msat = 196;
+ config.channel_config.forwarding_fee_base_msat = 196;
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs,
&[Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone())]);
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
// When this test was written, the default base fee floated based on the HTLC count.
// It is now fixed, so we simply set the fee to the expected value here.
let mut config = test_default_channel_config();
- config.channel_options.forwarding_fee_base_msat = 196;
+ config.channel_config.forwarding_fee_base_msat = 196;
let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs,
&[Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone())]);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
// When this test was written, the default base fee floated based on the HTLC count.
// It is now fixed, so we simply set the fee to the expected value here.
let mut config = test_default_channel_config();
- config.channel_options.forwarding_fee_base_msat = 196;
+ config.channel_config.forwarding_fee_base_msat = 196;
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config.clone()), Some(config.clone()), Some(config.clone())]);
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
// We test our channel constructors yield errors when we pass them absurd csv delay
let mut low_our_to_self_config = UserConfig::default();
- low_our_to_self_config.own_channel_config.our_to_self_delay = 6;
+ low_our_to_self_config.channel_handshake_config.our_to_self_delay = 6;
let mut high_their_to_self_config = UserConfig::default();
- high_their_to_self_config.peer_channel_config_limits.their_to_self_delay = 100;
+ high_their_to_self_config.channel_handshake_limits.their_to_self_delay = 100;
let user_cfgs = [Some(high_their_to_self_config.clone()), None];
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
// Node0 initiates a channel to node1 using the override config.
let mut override_config = UserConfig::default();
- override_config.own_channel_config.our_to_self_delay = 200;
+ override_config.channel_handshake_config.our_to_self_delay = 200;
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 16_000_000, 12_000_000, 42, Some(override_config)).unwrap();
#[test]
fn test_override_0msat_htlc_minimum() {
let mut zero_config = UserConfig::default();
- zero_config.own_channel_config.our_htlc_minimum_msat = 0;
+ zero_config.channel_handshake_config.our_htlc_minimum_msat = 0;
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(zero_config.clone())]);
// 2. MUST be set to less than or equal to the `max_htlc_value_in_flight_msat` received from the peer.
let mut config_30_percent = UserConfig::default();
- config_30_percent.channel_options.announced_channel = true;
- config_30_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 30;
+ config_30_percent.channel_handshake_config.announced_channel = true;
+ config_30_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 30;
let mut config_50_percent = UserConfig::default();
- config_50_percent.channel_options.announced_channel = true;
- config_50_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 50;
+ config_50_percent.channel_handshake_config.announced_channel = true;
+ config_50_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 50;
let mut config_95_percent = UserConfig::default();
- config_95_percent.channel_options.announced_channel = true;
- config_95_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 95;
+ config_95_percent.channel_handshake_config.announced_channel = true;
+ config_95_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 95;
let mut config_100_percent = UserConfig::default();
- config_100_percent.channel_options.announced_channel = true;
- config_100_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100;
+ config_100_percent.channel_handshake_config.announced_channel = true;
+ config_100_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100;
let chanmon_cfgs = create_chanmon_cfgs(4);
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
let chanmon_cfgs = create_chanmon_cfgs(2);
let mut config = test_default_channel_config();
- config.channel_options.max_dust_htlc_exposure_msat = 5_000_000; // default setting value
+ config.channel_config.max_dust_htlc_exposure_msat = 5_000_000; // default setting value
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), None]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
chan.get_dust_buffer_feerate(None) as u64
};
let dust_outbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_timeout_tx_weight(opt_anchors) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000;
- let dust_outbound_htlc_on_holder_tx: u64 = config.channel_options.max_dust_htlc_exposure_msat / dust_outbound_htlc_on_holder_tx_msat;
+ let dust_outbound_htlc_on_holder_tx: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_outbound_htlc_on_holder_tx_msat;
let dust_inbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_success_tx_weight(opt_anchors) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000;
- let dust_inbound_htlc_on_holder_tx: u64 = config.channel_options.max_dust_htlc_exposure_msat / dust_inbound_htlc_on_holder_tx_msat;
+ let dust_inbound_htlc_on_holder_tx: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_inbound_htlc_on_holder_tx_msat;
let dust_htlc_on_counterparty_tx: u64 = 25;
- let dust_htlc_on_counterparty_tx_msat: u64 = config.channel_options.max_dust_htlc_exposure_msat / dust_htlc_on_counterparty_tx;
+ let dust_htlc_on_counterparty_tx_msat: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_htlc_on_counterparty_tx;
if on_holder_tx {
if dust_outbound_balance {
if on_holder_tx {
let dust_outbound_overflow = dust_outbound_htlc_on_holder_tx_msat * (dust_outbound_htlc_on_holder_tx + 1);
let dust_inbound_overflow = dust_inbound_htlc_on_holder_tx_msat * dust_inbound_htlc_on_holder_tx + dust_outbound_htlc_on_holder_tx_msat;
- unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable { ref err }, assert_eq!(err, &format!("Cannot send value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_options.max_dust_htlc_exposure_msat)));
+ unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable { ref err }, assert_eq!(err, &format!("Cannot send value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_config.max_dust_htlc_exposure_msat)));
} else {
- unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable { ref err }, assert_eq!(err, &format!("Cannot send value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx", dust_overflow, config.channel_options.max_dust_htlc_exposure_msat)));
+ unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable { ref err }, assert_eq!(err, &format!("Cannot send value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx", dust_overflow, config.channel_config.max_dust_htlc_exposure_msat)));
}
} else if exposure_breach_event == ExposureEvent::AtHTLCReception {
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], if on_holder_tx { dust_inbound_htlc_on_holder_tx_msat } else { dust_htlc_on_counterparty_tx_msat });
// Outbound dust balance: 6399 sats
let dust_inbound_overflow = dust_inbound_htlc_on_holder_tx_msat * (dust_inbound_htlc_on_holder_tx + 1);
let dust_outbound_overflow = dust_outbound_htlc_on_holder_tx_msat * dust_outbound_htlc_on_holder_tx + dust_inbound_htlc_on_holder_tx_msat;
- nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_options.max_dust_htlc_exposure_msat), 1);
+ nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_config.max_dust_htlc_exposure_msat), 1);
} else {
// Outbound dust balance: 5200 sats
- nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx", dust_overflow, config.channel_options.max_dust_htlc_exposure_msat), 1);
+ nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx", dust_overflow, config.channel_config.max_dust_htlc_exposure_msat), 1);
}
} else if exposure_breach_event == ExposureEvent::AtUpdateFeeOutbound {
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 2_500_000);
// When this test was written, the default base fee floated based on the HTLC count.
// It is now fixed, so we simply set the fee to the expected value here.
let mut config = test_default_channel_config();
- config.channel_options.forwarding_fee_base_msat = 196;
+ config.channel_config.forwarding_fee_base_msat = 196;
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
// This exposed a previous bug because we were using the wrong value all the way down in
// Channel::get_counterparty_htlc_minimum_msat().
let mut node_2_cfg: UserConfig = Default::default();
- node_2_cfg.own_channel_config.our_htlc_minimum_msat = 2000;
- node_2_cfg.channel_options.announced_channel = true;
- node_2_cfg.peer_channel_config_limits.force_announced_channel_preference = false;
+ node_2_cfg.channel_handshake_config.our_htlc_minimum_msat = 2000;
+ node_2_cfg.channel_handshake_config.announced_channel = true;
+ node_2_cfg.channel_handshake_limits.force_announced_channel_preference = false;
// When this test was written, the default base fee floated based on the HTLC count.
// It is now fixed, so we simply set the fee to the expected value here.
let mut config = test_default_channel_config();
- config.channel_options.forwarding_fee_base_msat = 196;
+ config.channel_config.forwarding_fee_base_msat = 196;
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
// `features` for a node in the `network_graph` exists, or when the node isn't in the
// `network_graph`, and no other known `features` for the node exists.
let mut priv_channels_conf = UserConfig::default();
- priv_channels_conf.channel_options.announced_channel = false;
+ priv_channels_conf.channel_handshake_config.announced_channel = false;
let chanmon_cfgs = create_chanmon_cfgs(5);
let node_cfgs = create_node_cfgs(5, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(5, &node_cfgs, &[None, None, None, None, Some(priv_channels_conf)]);
// Set the max dust exposure to the dust limit.
let max_dust_exposure = 546;
let mut receiver_config = UserConfig::default();
- receiver_config.channel_options.max_dust_htlc_exposure_msat = max_dust_exposure;
- receiver_config.channel_options.announced_channel = true;
+ receiver_config.channel_config.max_dust_htlc_exposure_msat = max_dust_exposure;
+ receiver_config.channel_handshake_config.announced_channel = true;
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
// Update the fee on the middle hop to ensure PaymentSent events have the correct (retried) fee
// and not the original fee. We also update node[1]'s relevant config as
// do_claim_payment_along_route expects us to never overpay.
- nodes[1].node.channel_state.lock().unwrap().by_id.get_mut(&chan_id_2).unwrap().config.forwarding_fee_base_msat += 100_000;
+ nodes[1].node.channel_state.lock().unwrap().by_id.get_mut(&chan_id_2).unwrap()
+ .config.options.forwarding_fee_base_msat += 100_000;
new_route.paths[0][0].fee_msat += 100_000;
assert!(nodes[0].node.retry_payment(&new_route, payment_id_1).is_err()); // Shouldn't be allowed to retry a fulfilled payment
// Previously, if the minium_depth config was set to 1, we'd never send a channel_ready. This
// tests that we properly send one in that case.
let mut alice_config = UserConfig::default();
- alice_config.own_channel_config.minimum_depth = 1;
- alice_config.channel_options.announced_channel = true;
- alice_config.peer_channel_config_limits.force_announced_channel_preference = false;
+ alice_config.channel_handshake_config.minimum_depth = 1;
+ alice_config.channel_handshake_config.announced_channel = true;
+ alice_config.channel_handshake_limits.force_announced_channel_preference = false;
let mut bob_config = UserConfig::default();
- bob_config.own_channel_config.minimum_depth = 1;
- bob_config.channel_options.announced_channel = true;
- bob_config.peer_channel_config_limits.force_announced_channel_preference = false;
+ bob_config.channel_handshake_config.minimum_depth = 1;
+ bob_config.channel_handshake_config.announced_channel = true;
+ bob_config.channel_handshake_limits.force_announced_channel_preference = false;
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(alice_config), Some(bob_config)]);
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let mut scid_privacy_cfg = test_default_channel_config();
- scid_privacy_cfg.channel_options.announced_channel = true;
- scid_privacy_cfg.own_channel_config.negotiate_scid_privacy = true;
+ scid_privacy_cfg.channel_handshake_config.announced_channel = true;
+ scid_privacy_cfg.channel_handshake_config.negotiate_scid_privacy = true;
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(scid_privacy_cfg)).unwrap();
let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let mut scid_privacy_cfg = test_default_channel_config();
- scid_privacy_cfg.channel_options.announced_channel = false;
- scid_privacy_cfg.own_channel_config.negotiate_scid_privacy = true;
+ scid_privacy_cfg.channel_handshake_config.announced_channel = false;
+ scid_privacy_cfg.channel_handshake_config.negotiate_scid_privacy = true;
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(scid_privacy_cfg)).unwrap();
let init_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
let mut no_announce_cfg = test_default_channel_config();
- no_announce_cfg.channel_options.announced_channel = false;
- no_announce_cfg.own_channel_config.negotiate_scid_privacy = true;
+ no_announce_cfg.channel_handshake_config.announced_channel = false;
+ no_announce_cfg.channel_handshake_config.negotiate_scid_privacy = true;
nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 100_000, 10_000, 42, Some(no_announce_cfg)).unwrap();
let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[2].node.get_our_node_id());
short_channel_id: last_hop[0].inbound_scid_alias.unwrap(),
timestamp: 21,
flags: 1,
- cltv_expiry_delta: accept_forward_cfg.channel_options.cltv_expiry_delta,
+ cltv_expiry_delta: accept_forward_cfg.channel_config.cltv_expiry_delta,
htlc_minimum_msat: 1_000,
htlc_maximum_msat: OptionalField::Present(1_000_000), // Defaults to 10% of the channel value
fee_base_msat: last_hop[0].counterparty.forwarding_info.as_ref().unwrap().fee_base_msat,
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
- chan_config.channel_options.announced_channel = false;
+ chan_config.channel_handshake_config.announced_channel = false;
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(chan_config)).unwrap();
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// This is the default but we force it on anyway
- chan_config.channel_options.announced_channel = true;
+ chan_config.channel_handshake_config.announced_channel = true;
open_zero_conf_channel(&nodes[0], &nodes[1], Some(chan_config));
// We can use the channel immediately, but won't generate a channel_update until we get confs
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// This is the default but we force it on anyway
- chan_config.channel_options.announced_channel = true;
+ chan_config.channel_handshake_config.announced_channel = true;
let tx = open_zero_conf_channel(&nodes[0], &nodes[1], Some(chan_config));
// We can use the channel immediately, but we can't announce it until we get 6+ confirmations
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
// This is the default but we force it on anyway
- chan_config.channel_options.announced_channel = true;
+ chan_config.channel_handshake_config.announced_channel = true;
let tx = open_zero_conf_channel(&nodes[0], &nodes[1], Some(chan_config));
// We can use the channel immediately, but we can't announce it until we get 6+ confirmations
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
let events = nodes[1].node.get_and_clear_pending_events();
-
+
match events[0] {
Event::OpenChannelRequest { temporary_channel_id, .. } => {
// Assert we fail to accept via the non-0conf method
&open_channel_msg);
let events = nodes[1].node.get_and_clear_pending_events();
-
+
match events[0] {
Event::OpenChannelRequest { temporary_channel_id, .. } => {
// Assert we can accept via the 0conf method
// enforce it at shutdown message
let mut config = UserConfig::default();
- config.channel_options.announced_channel = true;
- config.peer_channel_config_limits.force_announced_channel_preference = false;
- config.channel_options.commit_upfront_shutdown_pubkey = false;
+ config.channel_handshake_config.announced_channel = true;
+ config.channel_handshake_limits.force_announced_channel_preference = false;
+ config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
let user_cfgs = [None, Some(config), None];
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
#[test]
fn test_segwit_v0_shutdown_script() {
let mut config = UserConfig::default();
- config.channel_options.announced_channel = true;
- config.peer_channel_config_limits.force_announced_channel_preference = false;
- config.channel_options.commit_upfront_shutdown_pubkey = false;
+ config.channel_handshake_config.announced_channel = true;
+ config.channel_handshake_limits.force_announced_channel_preference = false;
+ config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
let user_cfgs = [None, Some(config), None];
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
#[test]
fn test_anysegwit_shutdown_script() {
let mut config = UserConfig::default();
- config.channel_options.announced_channel = true;
- config.peer_channel_config_limits.force_announced_channel_preference = false;
- config.channel_options.commit_upfront_shutdown_pubkey = false;
+ config.channel_handshake_config.announced_channel = true;
+ config.channel_handshake_limits.force_announced_channel_preference = false;
+ config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
let user_cfgs = [None, Some(config), None];
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
#[test]
fn test_unsupported_anysegwit_shutdown_script() {
let mut config = UserConfig::default();
- config.channel_options.announced_channel = true;
- config.peer_channel_config_limits.force_announced_channel_preference = false;
- config.channel_options.commit_upfront_shutdown_pubkey = false;
+ config.channel_handshake_config.announced_channel = true;
+ config.channel_handshake_limits.force_announced_channel_preference = false;
+ config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
let user_cfgs = [None, Some(config), None];
let chanmon_cfgs = create_chanmon_cfgs(3);
let mut node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
#[test]
fn test_invalid_shutdown_script() {
let mut config = UserConfig::default();
- config.channel_options.announced_channel = true;
- config.peer_channel_config_limits.force_announced_channel_preference = false;
- config.channel_options.commit_upfront_shutdown_pubkey = false;
+ config.channel_handshake_config.announced_channel = true;
+ config.channel_handshake_limits.force_announced_channel_preference = false;
+ config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
let user_cfgs = [None, Some(config), None];
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
impl<L: Deref> EventHandler for NetworkGraph<L> where L::Target: Logger {
fn handle_event(&self, event: &Event) {
- if let Event::PaymentPathFailed { payment_hash: _, rejected_by_dest: _, network_update, .. } = event {
+ if let Event::PaymentPathFailed { network_update, .. } = event {
if let Some(network_update) = network_update {
match *network_update {
NetworkUpdate::ChannelUpdateMessage { ref msg } => {
UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate,
ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT};
use util::test_utils;
- use util::logger::Logger;
use util::ser::{ReadableArgs, Writeable};
use util::events::{Event, EventHandler, MessageSendEvent, MessageSendEventsProvider};
use util::scid_utils::scid_from_parts;
#[test]
fn handling_channel_announcements() {
let secp_ctx = Secp256k1::new();
- let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
+ let logger = test_utils::TestLogger::new();
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
// Test if the UTXO lookups were not supported
let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger));
- let mut gossip_sync = P2PGossipSync::new(&network_graph, None, Arc::clone(&logger));
+ let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ let mut gossip_sync = P2PGossipSync::new(&network_graph, None, &logger);
match gossip_sync.handle_channel_announcement(&valid_announcement) {
Ok(res) => assert!(res),
_ => panic!()
};
// Test if an associated transaction were not on-chain (or not confirmed).
- let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
+ let chain_source = test_utils::TestChainSource::new(Network::Testnet);
*chain_source.utxo_ret.lock().unwrap() = Err(chain::AccessError::UnknownTx);
- let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger));
- gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), Arc::clone(&logger));
+ let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
let valid_announcement = get_signed_channel_announcement(|unsigned_announcement| {
unsigned_announcement.short_channel_id += 1;
#[test]
fn handling_channel_update() {
let secp_ctx = Secp256k1::new();
- let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
- let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
+ let logger = test_utils::TestLogger::new();
+ let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger));
- let gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), Arc::clone(&logger));
+ let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
fn test_channel_timeouts() {
// Test the removal of channels with `remove_stale_channels`.
let logger = test_utils::TestLogger::new();
- let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
+ let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
let network_graph = NetworkGraph::new(genesis_hash, &logger);
- let gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), &logger);
+ let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
let secp_ctx = Secp256k1::new();
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
/// Maximum total CTLV difference we allow for a full payment path.
pub const DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA: u32 = 1008;
+/// Maximum number of paths we allow an MPP payment to have.
+// The default limit is currently set rather arbitrary - there aren't any real fundamental path-count
+// limits, but for now more than 10 paths likely carries too much one-path failure.
+pub const DEFAULT_MAX_MPP_PATH_COUNT: u8 = 10;
+
// The median hop CLTV expiry delta currently seen in the network.
const MEDIAN_HOP_CLTV_EXPIRY_DELTA: u32 = 40;
pub expiry_time: Option<u64>,
/// The maximum total CLTV delta we accept for the route.
+ /// Defaults to [`DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA`].
pub max_total_cltv_expiry_delta: u32,
+
+ /// The maximum number of paths that may be used by MPP payments.
+ /// Defaults to [`DEFAULT_MAX_MPP_PATH_COUNT`].
+ pub max_mpp_path_count: u8,
}
impl_writeable_tlv_based!(PaymentParameters, {
(0, payee_pubkey, required),
(1, max_total_cltv_expiry_delta, (default_value, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA)),
(2, features, option),
+ (3, max_mpp_path_count, (default_value, DEFAULT_MAX_MPP_PATH_COUNT)),
(4, route_hints, vec_type),
(6, expiry_time, option),
});
route_hints: vec![],
expiry_time: None,
max_total_cltv_expiry_delta: DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
+ max_mpp_path_count: DEFAULT_MAX_MPP_PATH_COUNT,
}
}
pub fn with_max_total_cltv_expiry_delta(self, max_total_cltv_expiry_delta: u32) -> Self {
Self { max_total_cltv_expiry_delta, ..self }
}
+
+ /// Includes a limit for the maximum number of payment paths that may be used by MPP.
+ ///
+ /// (C-not exported) since bindings don't support move semantics
+ pub fn with_max_mpp_path_count(self, max_mpp_path_count: u8) -> Self {
+ Self { max_mpp_path_count, ..self }
+ }
}
/// A list of hops along a payment path terminating with a channel to the recipient.
node_info.features.supports_basic_mpp()
} else { false }
} else { false };
+
+ if allow_mpp && payment_params.max_mpp_path_count == 0 {
+ return Err(LightningError{err: "Can't find an MPP route with no paths allowed.".to_owned(), action: ErrorAction::IgnoreError});
+ }
+
log_trace!(logger, "Searching for a route from payer {} to payee {} {} MPP and {} first hops {}overriding the network graph", our_node_pubkey,
payment_params.payee_pubkey, if allow_mpp { "with" } else { "without" },
first_hops.map(|hops| hops.len()).unwrap_or(0), if first_hops.is_some() { "" } else { "not " });
let recommended_value_msat = final_value_msat * ROUTE_CAPACITY_PROVISION_FACTOR as u64;
let mut path_value_msat = final_value_msat;
+ // Routing Fragmentation Mitigation heuristic:
+ //
+ // Routing fragmentation across many payment paths increases the overall routing
+ // fees as you have irreducible routing fees per-link used (`fee_base_msat`).
+ // Taking too many smaller paths also increases the chance of payment failure.
+ // Thus to avoid this effect, we require from our collected links to provide
+ // at least a minimal contribution to the recommended value yet-to-be-fulfilled.
+ // This requirement is currently set to be 1/max_mpp_path_count of the payment
+ // value to ensure we only ever return routes that do not violate this limit.
+ let minimal_value_contribution_msat: u64 = if allow_mpp {
+ (final_value_msat + (payment_params.max_mpp_path_count as u64 - 1)) / payment_params.max_mpp_path_count as u64
+ } else {
+ final_value_msat
+ };
+
// Keep track of how much liquidity has been used in selected channels. Used to determine
// if the channel can be used by additional MPP paths or to inform path finding decisions. It is
// aware of direction *only* to ensure that the correct htlc_maximum_msat value is used. Hence,
let mut used_channel_liquidities: HashMap<(u64, bool), u64> =
HashMap::with_capacity(network_nodes.len());
- // Keeping track of how much value we already collected across other paths. Helps to decide:
- // - how much a new path should be transferring (upper bound);
- // - whether a channel should be disregarded because
- // it's available liquidity is too small comparing to how much more we need to collect;
- // - when we want to stop looking for new paths.
+ // Keeping track of how much value we already collected across other paths. Helps to decide
+ // when we want to stop looking for new paths.
let mut already_collected_value_msat = 0;
for (_, channels) in first_hop_targets.iter_mut() {
*used_liquidity_msat
});
- // Routing Fragmentation Mitigation heuristic:
- //
- // Routing fragmentation across many payment paths increases the overall routing
- // fees as you have irreducible routing fees per-link used (`fee_base_msat`).
- // Taking too many smaller paths also increases the chance of payment failure.
- // Thus to avoid this effect, we require from our collected links to provide
- // at least a minimal contribution to the recommended value yet-to-be-fulfilled.
- //
- // This requirement is currently 5% of the remaining-to-be-collected value.
- // This means as we successfully advance in our collection,
- // the absolute liquidity contribution is lowered,
- // thus increasing the number of potential channels to be selected.
-
- // Derive the minimal liquidity contribution with a ratio of 20 (5%, rounded up)
- // or 100% if we're not allowed to do multipath payments.
- let minimal_value_contribution_msat: u64 = if allow_mpp {
- (recommended_value_msat - already_collected_value_msat + 19) / 20
- } else {
- final_value_msat
- };
// Verify the liquidity offered by this channel complies to the minimal contribution.
let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
// Do not consider candidate hops that would exceed the maximum path length.
*used_channel_liquidities.entry((victim_scid, true)).or_default() = exhausted;
}
- // Track the total amount all our collected paths allow to send so that we:
- // - know when to stop looking for more paths
- // - know which of the hops are useless considering how much more sats we need
- // (contributes_sufficient_value)
+ // Track the total amount all our collected paths allow to send so that we know
+ // when to stop looking for more paths
already_collected_value_msat += value_contribution_msat;
payment_paths.push(payment_path);
});
selected_paths.push(path);
}
+ // Make sure we would never create a route with more paths than we allow.
+ debug_assert!(selected_paths.len() <= payment_params.max_mpp_path_count.into());
if let Some(features) = &payment_params.features {
for path in selected_paths.iter_mut() {
let scorer = test_utils::TestScorer::with_penalty(0);
let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
+ let payment_params = PaymentParameters::from_node_id(nodes[2])
+ .with_features(InvoiceFeatures::known());
// We need a route consisting of 3 paths:
// From our node to node2 via node0, node7, node1 (three paths one hop each).
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 300_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
- assert_eq!(err, "Failed to find a sufficient route to the given destination");
+ &our_id, &payment_params, &network_graph.read_only(), None, 300_000, 42,
+ Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ assert_eq!(err, "Failed to find a sufficient route to the given destination");
+ } else { panic!(); }
+ }
+
+ {
+ // Attempt to route while setting max_mpp_path_count to 0 results in a failure.
+ let zero_payment_params = payment_params.clone().with_max_mpp_path_count(0);
+ if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
+ &our_id, &zero_payment_params, &network_graph.read_only(), None, 100, 42,
+ Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ assert_eq!(err, "Can't find an MPP route with no paths allowed.");
+ } else { panic!(); }
+ }
+
+ {
+ // Attempt to route while setting max_mpp_path_count to 3 results in a failure.
+ // This is the case because the minimal_value_contribution_msat would require each path
+ // to account for 1/3 of the total value, which is violated by 2 out of 3 paths.
+ let fail_payment_params = payment_params.clone().with_max_mpp_path_count(3);
+ if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
+ &our_id, &fail_payment_params, &network_graph.read_only(), None, 250_000, 42,
+ Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route 250 sats (just a bit below the capacity).
// Our algorithm should provide us with these 3 paths.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None,
+ 250_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 3);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
{
// Attempt to route an exact amount is also fine
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 290_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None,
+ 290_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 3);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
///
/// If this option is set, channels may be created that will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a
- /// [`DecodeError:InvalidValue`].
+ /// [`DecodeError::InvalidValue`].
///
/// Note that setting this to true does *not* prevent us from opening channels with
/// counterparties that do not support the `scid_alias` option; we will simply fall back to a
/// private channel without that option.
///
/// Ignored if the channel is negotiated to be announced, see
- /// [`ChannelConfig::announced_channel`] and
+ /// [`ChannelHandshakeConfig::announced_channel`] and
/// [`ChannelHandshakeLimits::force_announced_channel_preference`] for more.
///
/// Default value: false. This value is likely to change to true in the future.
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
- /// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
+ /// [`DecodeError::InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,
+ /// Set to announce the channel publicly and notify all nodes that they can route via this
+ /// channel.
+ ///
+ /// This should only be set to true for nodes which expect to be online reliably.
+ ///
+ /// As the node which funds a channel picks this value this will only apply for new outbound
+ /// channels unless [`ChannelHandshakeLimits::force_announced_channel_preference`] is set.
+ ///
+ /// Default value: false.
+ pub announced_channel: bool,
+ /// When set, we commit to an upfront shutdown_pubkey at channel open. If our counterparty
+ /// supports it, they will then enforce the mutual-close output to us matches what we provided
+ /// at intialization, preventing us from closing to an alternate pubkey.
+ ///
+ /// This is set to true by default to provide a slight increase in security, though ultimately
+ /// any attacker who is able to take control of a channel can just as easily send the funds via
+ /// lightning payments, so we never require that our counterparties support this option.
+ ///
+ /// The upfront key committed is provided from [`KeysInterface::get_shutdown_scriptpubkey`].
+ ///
+ /// Default value: true.
+ ///
+ /// [`KeysInterface::get_shutdown_scriptpubkey`]: crate::chain::keysinterface::KeysInterface::get_shutdown_scriptpubkey
+ pub commit_upfront_shutdown_pubkey: bool,
}
impl Default for ChannelHandshakeConfig {
our_htlc_minimum_msat: 1,
max_inbound_htlc_value_in_flight_percent_of_channel: 10,
negotiate_scid_privacy: false,
+ announced_channel: false,
+ commit_upfront_shutdown_pubkey: true,
}
}
}
/// Default value: true
pub trust_own_funding_0conf: bool,
/// Set to force an incoming channel to match our announced channel preference in
- /// [`ChannelConfig::announced_channel`].
+ /// [`ChannelHandshakeConfig::announced_channel`].
///
/// For a node which is not online reliably, this should be set to true and
- /// [`ChannelConfig::announced_channel`] set to false, ensuring that no announced (aka public)
+ /// [`ChannelHandshakeConfig::announced_channel`] set to false, ensuring that no announced (aka public)
/// channels will ever be opened.
///
/// Default value: true.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
- /// Set to announce the channel publicly and notify all nodes that they can route via this
- /// channel.
- ///
- /// This should only be set to true for nodes which expect to be online reliably.
- ///
- /// As the node which funds a channel picks this value this will only apply for new outbound
- /// channels unless [`ChannelHandshakeLimits::force_announced_channel_preference`] is set.
- ///
- /// This cannot be changed after the initial channel handshake.
- ///
- /// Default value: false.
- pub announced_channel: bool,
- /// When set, we commit to an upfront shutdown_pubkey at channel open. If our counterparty
- /// supports it, they will then enforce the mutual-close output to us matches what we provided
- /// at intialization, preventing us from closing to an alternate pubkey.
- ///
- /// This is set to true by default to provide a slight increase in security, though ultimately
- /// any attacker who is able to take control of a channel can just as easily send the funds via
- /// lightning payments, so we never require that our counterparties support this option.
- ///
- /// This cannot be changed after a channel has been initialized.
- ///
- /// Default value: true.
- pub commit_upfront_shutdown_pubkey: bool,
/// Limit our total exposure to in-flight HTLCs which are burned to fees as they are too
/// small to claim on-chain.
///
forwarding_fee_proportional_millionths: 0,
forwarding_fee_base_msat: 1000,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
- announced_channel: false,
- commit_upfront_shutdown_pubkey: true,
max_dust_htlc_exposure_msat: 5_000_000,
force_close_avoidance_max_fee_satoshis: 1000,
}
}
}
-impl_writeable_tlv_based!(ChannelConfig, {
- (0, forwarding_fee_proportional_millionths, required),
- (1, max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
- (2, cltv_expiry_delta, required),
- (3, force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
- (4, announced_channel, required),
- (6, commit_upfront_shutdown_pubkey, required),
- (8, forwarding_fee_base_msat, required),
-});
+/// Legacy version of [`ChannelConfig`] that stored the static
+/// [`ChannelHandshakeConfig::announced_channel`] and
+/// [`ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`] fields.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct LegacyChannelConfig {
+ pub(crate) options: ChannelConfig,
+ /// Deprecated but may still be read from. See [`ChannelHandshakeConfig::announced_channel`] to
+ /// set this when opening/accepting a channel.
+ pub(crate) announced_channel: bool,
+ /// Deprecated but may still be read from. See
+ /// [`ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`] to set this when
+ /// opening/accepting a channel.
+ pub(crate) commit_upfront_shutdown_pubkey: bool,
+}
+
+impl Default for LegacyChannelConfig {
+ fn default() -> Self {
+ Self {
+ options: ChannelConfig::default(),
+ announced_channel: false,
+ commit_upfront_shutdown_pubkey: true,
+ }
+ }
+}
+
+impl ::util::ser::Writeable for LegacyChannelConfig {
+ fn write<W: ::util::ser::Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
+ write_tlv_fields!(writer, {
+ (0, self.options.forwarding_fee_proportional_millionths, required),
+ (1, self.options.max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
+ (2, self.options.cltv_expiry_delta, required),
+ (3, self.options.force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
+ (4, self.announced_channel, required),
+ (6, self.commit_upfront_shutdown_pubkey, required),
+ (8, self.options.forwarding_fee_base_msat, required),
+ });
+ Ok(())
+ }
+}
+
+impl ::util::ser::Readable for LegacyChannelConfig {
+ fn read<R: ::io::Read>(reader: &mut R) -> Result<Self, ::ln::msgs::DecodeError> {
+ let mut forwarding_fee_proportional_millionths = 0;
+ let mut max_dust_htlc_exposure_msat = 5_000_000;
+ let mut cltv_expiry_delta = 0;
+ let mut force_close_avoidance_max_fee_satoshis = 1000;
+ let mut announced_channel = false;
+ let mut commit_upfront_shutdown_pubkey = false;
+ let mut forwarding_fee_base_msat = 0;
+ read_tlv_fields!(reader, {
+ (0, forwarding_fee_proportional_millionths, required),
+ (1, max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
+ (2, cltv_expiry_delta, required),
+ (3, force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
+ (4, announced_channel, required),
+ (6, commit_upfront_shutdown_pubkey, required),
+ (8, forwarding_fee_base_msat, required),
+ });
+ Ok(Self {
+ options: ChannelConfig {
+ forwarding_fee_proportional_millionths,
+ max_dust_htlc_exposure_msat,
+ cltv_expiry_delta,
+ force_close_avoidance_max_fee_satoshis,
+ forwarding_fee_base_msat,
+ },
+ announced_channel,
+ commit_upfront_shutdown_pubkey,
+ })
+ }
+}
/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
///
/// (but currently with 0 relay fees!)
#[derive(Copy, Clone, Debug)]
pub struct UserConfig {
- /// Channel config that we propose to our counterparty.
- pub own_channel_config: ChannelHandshakeConfig,
- /// Limits applied to our counterparty's proposed channel config settings.
- pub peer_channel_config_limits: ChannelHandshakeLimits,
+ /// Channel handshake config that we propose to our counterparty.
+ pub channel_handshake_config: ChannelHandshakeConfig,
+ /// Limits applied to our counterparty's proposed channel handshake config settings.
+ pub channel_handshake_limits: ChannelHandshakeLimits,
/// Channel config which affects behavior during channel lifetime.
- pub channel_options: ChannelConfig,
+ pub channel_config: ChannelConfig,
/// If this is set to false, we will reject any HTLCs which were to be forwarded over private
/// channels. This prevents us from taking on HTLC-forwarding risk when we intend to run as a
/// node which is not online reliably.
///
/// For nodes which are not online reliably, you should set all channels to *not* be announced
- /// (using [`ChannelConfig::announced_channel`] and
+ /// (using [`ChannelHandshakeConfig::announced_channel`] and
/// [`ChannelHandshakeLimits::force_announced_channel_preference`]) and set this to false to
/// ensure you are not exposed to any forwarding risk.
///
impl Default for UserConfig {
fn default() -> Self {
UserConfig {
- own_channel_config: ChannelHandshakeConfig::default(),
- peer_channel_config_limits: ChannelHandshakeLimits::default(),
- channel_options: ChannelConfig::default(),
+ channel_handshake_config: ChannelHandshakeConfig::default(),
+ channel_handshake_limits: ChannelHandshakeLimits::default(),
+ channel_config: ChannelConfig::default(),
accept_forwards_to_priv_channels: false,
accept_inbound_channels: true,
manually_accept_inbound_channels: false,