Closed
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
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand All@@ -374,7 +374,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;

let mut monitors = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,7 +379,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {

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.own_channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand Down
42 changes: 32 additions & 10 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
use util::config::{UserConfig,ChannelConfig,ChannelHandshakeConfig};
use util::scid_utils::scid_from_parts;

use io;
Expand DownExpand Up@@ -426,6 +426,13 @@ pub(super) struct Channel<Signer: Sign> {
#[cfg(not(any(test, feature = "_test_utils")))]
config: ChannelConfig,

#[cfg(any(test, feature = "_test_utils"))]
pub(crate) forwarding_fee_base_msat: u32,
#[cfg(not(any(test, feature = "_test_utils")))]
forwarding_fee_base_msat: u32,
forwarding_fee_proportional_millionths: u32,
cltv_expiry_delta: u16,

user_id: u64,

channel_id: [u8; 32],
Expand DownExpand Up@@ -760,11 +767,16 @@ impl<Signer: Sign> Channel<Signer> {
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
}
}
let handshake_config = config.own_channel_config.clone();

Ok(Channel {
user_id,
config: config.channel_options.clone(),

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
secp_ctx,
Expand DownExpand Up@@ -929,6 +941,7 @@ impl<Signer: Sign> Channel<Signer> {
htlc_basepoint: msg.htlc_basepoint
};
let mut local_config = (*config).channel_options.clone();
let handshake_config = (*config).own_channel_config.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)));
Expand DownExpand Up@@ -1063,6 +1076,10 @@ impl<Signer: Sign> Channel<Signer> {
user_id,
config: local_config,

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
secp_ctx,
Expand DownExpand Up@@ -4052,11 +4069,11 @@ impl<Signer: Sign> Channel<Signer> {
}

pub fn get_fee_proportional_millionths(&self) -> u32 {
self.config.forwarding_fee_proportional_millionths
self.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.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}

pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
Expand DownExpand Up@@ -4147,7 +4164,7 @@ impl<Signer: Sign> Channel<Signer> {
/// 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.forwarding_fee_base_msat
}

/// Returns true if we've ever received a message from the remote end for this Channel
Expand DownExpand Up@@ -5188,8 +5205,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {

// Write out the old serialization for the config object. This is read by version-1
// deserializers, but we will read the version in the TLV at the end instead.
self.config.forwarding_fee_proportional_millionths.write(writer)?;
self.config.cltv_expiry_delta.write(writer)?;
self.forwarding_fee_proportional_millionths.write(writer)?;
self.cltv_expiry_delta.write(writer)?;
self.config.announced_channel.write(writer)?;
self.config.commit_upfront_shutdown_pubkey.write(writer)?;

Expand DownExpand Up@@ -5450,17 +5467,18 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
let user_id = Readable::read(reader)?;

let mut config = Some(ChannelConfig::default());
let handshake_config = Some(ChannelHandshakeConfig::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)?;
// Read the old serialization of the ChannelConfig from version 0.0.98.handshake_config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
// Read the 8 bytes of backwards-compatibility ChannelConfig data.
let mut _val: u64 = Readable::read(reader)?;
}


let cltv_expiry_delta = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;
Expand DownExpand Up@@ -5708,6 +5726,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
user_id,

config: config.unwrap(),
forwarding_fee_base_msat: handshake_config.unwrap().forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.unwrap().forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.unwrap().cltv_expiry_delta,

channel_id,
channel_state,
secp_ctx,
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1468,7 +1468,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
($node: expr, $prev_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().forwarding_fee_base_msat;
expect_payment_forwarded!($node, Some(fee as u64), false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
Expand DownExpand Up@@ -1731,7 +1731,7 @@ pub fn test_default_channel_config() -> UserConfig {
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 = 6*6;
default_config.own_channel_config.cltv_expiry_delta = 6*6;
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1787,7 +1787,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// 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.own_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());
Expand DownExpand Up@@ -5135,7 +5135,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// 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.own_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);
Expand DownExpand Up@@ -5332,7 +5332,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 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.own_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);
Expand DownExpand Up@@ -6208,7 +6208,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
// 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.own_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());
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -258,7 +258,7 @@ fn test_fee_failures() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand DownExpand Up@@ -310,7 +310,7 @@ fn test_onion_failure() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/payment_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -448,7 +448,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
// 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().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
Expand Down
89 changes: 43 additions & 46 deletions lightning/src/util/config.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,46 @@ pub struct ChannelHandshakeConfig {
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
/// by the protocol.
pub our_htlc_minimum_msat: u64,
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelHandshakeConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
}

impl Default for ChannelHandshakeConfig {
Expand All@@ -55,6 +95,9 @@ impl Default for ChannelHandshakeConfig {
minimum_depth: 6,
our_to_self_delay: BREAKDOWN_TIMEOUT,
our_htlc_minimum_msat: 1,
forwarding_fee_base_msat: 1000,
forwarding_fee_proportional_millionths: 0,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
}
}
}
Expand DownExpand Up@@ -143,46 +186,6 @@ impl Default for ChannelHandshakeLimits {
/// with our counterparty.
#[derive(Copy, Clone, Debug)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`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.
///
Expand DownExpand Up@@ -252,9 +255,6 @@ impl Default for ChannelConfig {
/// Provides sane defaults for most configurations (but with zero relay fees!).
fn default() -> Self {
ChannelConfig {
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,
Expand All@@ -264,13 +264,10 @@ impl Default for ChannelConfig {
}

impl_writeable_tlv_based!(ChannelConfig, {
(0, forwarding_fee_proportional_millionths, required),

@TheBlueMattTheBlueMattJan 18, 2022

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we cannot remove required elements, as old clients will refuse to load data serialized by new clients (which we guarantee won't happen at least across a few releases). We instead need to write the default value with something like (0, Some(DEFAULT_VALUE as u64), option)

(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),
});

/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
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
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand All@@ -374,7 +374,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;

let mut monitors = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,7 +379,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {

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.own_channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand Down
42 changes: 32 additions & 10 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
use util::config::{UserConfig,ChannelConfig,ChannelHandshakeConfig};
use util::scid_utils::scid_from_parts;

use io;
Expand DownExpand Up@@ -426,6 +426,13 @@ pub(super) struct Channel<Signer: Sign> {
#[cfg(not(any(test, feature = "_test_utils")))]
config: ChannelConfig,

#[cfg(any(test, feature = "_test_utils"))]
pub(crate) forwarding_fee_base_msat: u32,
#[cfg(not(any(test, feature = "_test_utils")))]
forwarding_fee_base_msat: u32,
forwarding_fee_proportional_millionths: u32,
cltv_expiry_delta: u16,

user_id: u64,

channel_id: [u8; 32],
Expand DownExpand Up@@ -760,11 +767,16 @@ impl<Signer: Sign> Channel<Signer> {
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
}
}
let handshake_config = config.own_channel_config.clone();

Ok(Channel {
user_id,
config: config.channel_options.clone(),

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
secp_ctx,
Expand DownExpand Up@@ -929,6 +941,7 @@ impl<Signer: Sign> Channel<Signer> {
htlc_basepoint: msg.htlc_basepoint
};
let mut local_config = (*config).channel_options.clone();
let handshake_config = (*config).own_channel_config.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)));
Expand DownExpand Up@@ -1063,6 +1076,10 @@ impl<Signer: Sign> Channel<Signer> {
user_id,
config: local_config,

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
secp_ctx,
Expand DownExpand Up@@ -4052,11 +4069,11 @@ impl<Signer: Sign> Channel<Signer> {
}

pub fn get_fee_proportional_millionths(&self) -> u32 {
self.config.forwarding_fee_proportional_millionths
self.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.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}

pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
Expand DownExpand Up@@ -4147,7 +4164,7 @@ impl<Signer: Sign> Channel<Signer> {
/// 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.forwarding_fee_base_msat
}

/// Returns true if we've ever received a message from the remote end for this Channel
Expand DownExpand Up@@ -5188,8 +5205,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {

// Write out the old serialization for the config object. This is read by version-1
// deserializers, but we will read the version in the TLV at the end instead.
self.config.forwarding_fee_proportional_millionths.write(writer)?;
self.config.cltv_expiry_delta.write(writer)?;
self.forwarding_fee_proportional_millionths.write(writer)?;
self.cltv_expiry_delta.write(writer)?;
self.config.announced_channel.write(writer)?;
self.config.commit_upfront_shutdown_pubkey.write(writer)?;

Expand DownExpand Up@@ -5450,17 +5467,18 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
let user_id = Readable::read(reader)?;

let mut config = Some(ChannelConfig::default());
let handshake_config = Some(ChannelHandshakeConfig::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)?;
// Read the old serialization of the ChannelConfig from version 0.0.98.handshake_config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
// Read the 8 bytes of backwards-compatibility ChannelConfig data.
let mut _val: u64 = Readable::read(reader)?;
}


let cltv_expiry_delta = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;
Expand DownExpand Up@@ -5708,6 +5726,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
user_id,

config: config.unwrap(),
forwarding_fee_base_msat: handshake_config.unwrap().forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.unwrap().forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.unwrap().cltv_expiry_delta,

channel_id,
channel_state,
secp_ctx,
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1468,7 +1468,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
($node: expr, $prev_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().forwarding_fee_base_msat;
expect_payment_forwarded!($node, Some(fee as u64), false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
Expand DownExpand Up@@ -1731,7 +1731,7 @@ pub fn test_default_channel_config() -> UserConfig {
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 = 6*6;
default_config.own_channel_config.cltv_expiry_delta = 6*6;
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1787,7 +1787,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// 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.own_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());
Expand DownExpand Up@@ -5135,7 +5135,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// 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.own_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);
Expand DownExpand Up@@ -5332,7 +5332,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 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.own_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);
Expand DownExpand Up@@ -6208,7 +6208,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
// 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.own_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());
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -258,7 +258,7 @@ fn test_fee_failures() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand DownExpand Up@@ -310,7 +310,7 @@ fn test_onion_failure() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/payment_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -448,7 +448,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
// 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().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
Expand Down
89 changes: 43 additions & 46 deletions lightning/src/util/config.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,46 @@ pub struct ChannelHandshakeConfig {
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
/// by the protocol.
pub our_htlc_minimum_msat: u64,
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelHandshakeConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
}

impl Default for ChannelHandshakeConfig {
Expand All@@ -55,6 +95,9 @@ impl Default for ChannelHandshakeConfig {
minimum_depth: 6,
our_to_self_delay: BREAKDOWN_TIMEOUT,
our_htlc_minimum_msat: 1,
forwarding_fee_base_msat: 1000,
forwarding_fee_proportional_millionths: 0,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
}
}
}
Expand DownExpand Up@@ -143,46 +186,6 @@ impl Default for ChannelHandshakeLimits {
/// with our counterparty.
#[derive(Copy, Clone, Debug)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`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.
///
Expand DownExpand Up@@ -252,9 +255,6 @@ impl Default for ChannelConfig {
/// Provides sane defaults for most configurations (but with zero relay fees!).
fn default() -> Self {
ChannelConfig {
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,
Expand All@@ -264,13 +264,10 @@ impl Default for ChannelConfig {
}

impl_writeable_tlv_based!(ChannelConfig, {
(0, forwarding_fee_proportional_millionths, required),

@TheBlueMattTheBlueMattJan 18, 2022

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we cannot remove required elements, as old clients will refuse to load data serialized by new clients (which we guarantee won't happen at least across a few releases). We instead need to write the default value with something like (0, Some(DEFAULT_VALUE as u64), option)

(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),
});

/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand All@@ -374,7 +374,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;

let mut monitors = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,7 +379,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {

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.own_channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand Down
42 changes: 32 additions & 10 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
use util::config::{UserConfig,ChannelConfig,ChannelHandshakeConfig};
use util::scid_utils::scid_from_parts;

use io;
Expand DownExpand Up@@ -426,6 +426,13 @@ pub(super) struct Channel<Signer: Sign> {
#[cfg(not(any(test, feature = "_test_utils")))]
config: ChannelConfig,

#[cfg(any(test, feature = "_test_utils"))]
pub(crate) forwarding_fee_base_msat: u32,
#[cfg(not(any(test, feature = "_test_utils")))]
forwarding_fee_base_msat: u32,
forwarding_fee_proportional_millionths: u32,
cltv_expiry_delta: u16,

user_id: u64,

channel_id: [u8; 32],
Expand DownExpand Up@@ -760,11 +767,16 @@ impl<Signer: Sign> Channel<Signer> {
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
}
}
let handshake_config = config.own_channel_config.clone();

Ok(Channel {
user_id,
config: config.channel_options.clone(),

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
secp_ctx,
Expand DownExpand Up@@ -929,6 +941,7 @@ impl<Signer: Sign> Channel<Signer> {
htlc_basepoint: msg.htlc_basepoint
};
let mut local_config = (*config).channel_options.clone();
let handshake_config = (*config).own_channel_config.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)));
Expand DownExpand Up@@ -1063,6 +1076,10 @@ impl<Signer: Sign> Channel<Signer> {
user_id,
config: local_config,

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
secp_ctx,
Expand DownExpand Up@@ -4052,11 +4069,11 @@ impl<Signer: Sign> Channel<Signer> {
}

pub fn get_fee_proportional_millionths(&self) -> u32 {
self.config.forwarding_fee_proportional_millionths
self.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.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}

pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
Expand DownExpand Up@@ -4147,7 +4164,7 @@ impl<Signer: Sign> Channel<Signer> {
/// 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.forwarding_fee_base_msat
}

/// Returns true if we've ever received a message from the remote end for this Channel
Expand DownExpand Up@@ -5188,8 +5205,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {

// Write out the old serialization for the config object. This is read by version-1
// deserializers, but we will read the version in the TLV at the end instead.
self.config.forwarding_fee_proportional_millionths.write(writer)?;
self.config.cltv_expiry_delta.write(writer)?;
self.forwarding_fee_proportional_millionths.write(writer)?;
self.cltv_expiry_delta.write(writer)?;
self.config.announced_channel.write(writer)?;
self.config.commit_upfront_shutdown_pubkey.write(writer)?;

Expand DownExpand Up@@ -5450,17 +5467,18 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
let user_id = Readable::read(reader)?;

let mut config = Some(ChannelConfig::default());
let handshake_config = Some(ChannelHandshakeConfig::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)?;
// Read the old serialization of the ChannelConfig from version 0.0.98.handshake_config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
// Read the 8 bytes of backwards-compatibility ChannelConfig data.
let mut _val: u64 = Readable::read(reader)?;
}


let cltv_expiry_delta = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;
Expand DownExpand Up@@ -5708,6 +5726,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
user_id,

config: config.unwrap(),
forwarding_fee_base_msat: handshake_config.unwrap().forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.unwrap().forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.unwrap().cltv_expiry_delta,

channel_id,
channel_state,
secp_ctx,
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1468,7 +1468,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
($node: expr, $prev_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().forwarding_fee_base_msat;
expect_payment_forwarded!($node, Some(fee as u64), false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
Expand DownExpand Up@@ -1731,7 +1731,7 @@ pub fn test_default_channel_config() -> UserConfig {
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 = 6*6;
default_config.own_channel_config.cltv_expiry_delta = 6*6;
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1787,7 +1787,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// 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.own_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());
Expand DownExpand Up@@ -5135,7 +5135,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// 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.own_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);
Expand DownExpand Up@@ -5332,7 +5332,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 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.own_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);
Expand DownExpand Up@@ -6208,7 +6208,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
// 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.own_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());
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -258,7 +258,7 @@ fn test_fee_failures() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand DownExpand Up@@ -310,7 +310,7 @@ fn test_onion_failure() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/payment_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -448,7 +448,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
// 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().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
Expand Down
89 changes: 43 additions & 46 deletions lightning/src/util/config.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,46 @@ pub struct ChannelHandshakeConfig {
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
/// by the protocol.
pub our_htlc_minimum_msat: u64,
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelHandshakeConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
}

impl Default for ChannelHandshakeConfig {
Expand All@@ -55,6 +95,9 @@ impl Default for ChannelHandshakeConfig {
minimum_depth: 6,
our_to_self_delay: BREAKDOWN_TIMEOUT,
our_htlc_minimum_msat: 1,
forwarding_fee_base_msat: 1000,
forwarding_fee_proportional_millionths: 0,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
}
}
}
Expand DownExpand Up@@ -143,46 +186,6 @@ impl Default for ChannelHandshakeLimits {
/// with our counterparty.
#[derive(Copy, Clone, Debug)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`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.
///
Expand DownExpand Up@@ -252,9 +255,6 @@ impl Default for ChannelConfig {
/// Provides sane defaults for most configurations (but with zero relay fees!).
fn default() -> Self {
ChannelConfig {
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,
Expand All@@ -264,13 +264,10 @@ impl Default for ChannelConfig {
}

impl_writeable_tlv_based!(ChannelConfig, {
(0, forwarding_fee_proportional_millionths, required),

@TheBlueMattTheBlueMattJan 18, 2022

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we cannot remove required elements, as old clients will refuse to load data serialized by new clients (which we guarantee won't happen at least across a few releases). We instead need to write the default value with something like (0, Some(DEFAULT_VALUE as u64), option)

(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),
});

/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand All@@ -374,7 +374,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;

let mut monitors = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,7 +379,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {

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.own_channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand Down
42 changes: 32 additions & 10 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
use util::config::{UserConfig,ChannelConfig,ChannelHandshakeConfig};
use util::scid_utils::scid_from_parts;

use io;
Expand DownExpand Up@@ -426,6 +426,13 @@ pub(super) struct Channel<Signer: Sign> {
#[cfg(not(any(test, feature = "_test_utils")))]
config: ChannelConfig,

#[cfg(any(test, feature = "_test_utils"))]
pub(crate) forwarding_fee_base_msat: u32,
#[cfg(not(any(test, feature = "_test_utils")))]
forwarding_fee_base_msat: u32,
forwarding_fee_proportional_millionths: u32,
cltv_expiry_delta: u16,

user_id: u64,

channel_id: [u8; 32],
Expand DownExpand Up@@ -760,11 +767,16 @@ impl<Signer: Sign> Channel<Signer> {
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
}
}
let handshake_config = config.own_channel_config.clone();

Ok(Channel {
user_id,
config: config.channel_options.clone(),

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
secp_ctx,
Expand DownExpand Up@@ -929,6 +941,7 @@ impl<Signer: Sign> Channel<Signer> {
htlc_basepoint: msg.htlc_basepoint
};
let mut local_config = (*config).channel_options.clone();
let handshake_config = (*config).own_channel_config.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)));
Expand DownExpand Up@@ -1063,6 +1076,10 @@ impl<Signer: Sign> Channel<Signer> {
user_id,
config: local_config,

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
secp_ctx,
Expand DownExpand Up@@ -4052,11 +4069,11 @@ impl<Signer: Sign> Channel<Signer> {
}

pub fn get_fee_proportional_millionths(&self) -> u32 {
self.config.forwarding_fee_proportional_millionths
self.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.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}

pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
Expand DownExpand Up@@ -4147,7 +4164,7 @@ impl<Signer: Sign> Channel<Signer> {
/// 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.forwarding_fee_base_msat
}

/// Returns true if we've ever received a message from the remote end for this Channel
Expand DownExpand Up@@ -5188,8 +5205,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {

// Write out the old serialization for the config object. This is read by version-1
// deserializers, but we will read the version in the TLV at the end instead.
self.config.forwarding_fee_proportional_millionths.write(writer)?;
self.config.cltv_expiry_delta.write(writer)?;
self.forwarding_fee_proportional_millionths.write(writer)?;
self.cltv_expiry_delta.write(writer)?;
self.config.announced_channel.write(writer)?;
self.config.commit_upfront_shutdown_pubkey.write(writer)?;

Expand DownExpand Up@@ -5450,17 +5467,18 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
let user_id = Readable::read(reader)?;

let mut config = Some(ChannelConfig::default());
let handshake_config = Some(ChannelHandshakeConfig::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)?;
// Read the old serialization of the ChannelConfig from version 0.0.98.handshake_config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
// Read the 8 bytes of backwards-compatibility ChannelConfig data.
let mut _val: u64 = Readable::read(reader)?;
}


let cltv_expiry_delta = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;
Expand DownExpand Up@@ -5708,6 +5726,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
user_id,

config: config.unwrap(),
forwarding_fee_base_msat: handshake_config.unwrap().forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.unwrap().forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.unwrap().cltv_expiry_delta,

channel_id,
channel_state,
secp_ctx,
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1468,7 +1468,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
($node: expr, $prev_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().forwarding_fee_base_msat;
expect_payment_forwarded!($node, Some(fee as u64), false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
Expand DownExpand Up@@ -1731,7 +1731,7 @@ pub fn test_default_channel_config() -> UserConfig {
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 = 6*6;
default_config.own_channel_config.cltv_expiry_delta = 6*6;
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1787,7 +1787,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// 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.own_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());
Expand DownExpand Up@@ -5135,7 +5135,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// 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.own_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);
Expand DownExpand Up@@ -5332,7 +5332,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 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.own_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);
Expand DownExpand Up@@ -6208,7 +6208,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
// 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.own_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());
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -258,7 +258,7 @@ fn test_fee_failures() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand DownExpand Up@@ -310,7 +310,7 @@ fn test_onion_failure() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/payment_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -448,7 +448,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
// 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().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
Expand Down
89 changes: 43 additions & 46 deletions lightning/src/util/config.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,46 @@ pub struct ChannelHandshakeConfig {
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
/// by the protocol.
pub our_htlc_minimum_msat: u64,
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelHandshakeConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
}

impl Default for ChannelHandshakeConfig {
Expand All@@ -55,6 +95,9 @@ impl Default for ChannelHandshakeConfig {
minimum_depth: 6,
our_to_self_delay: BREAKDOWN_TIMEOUT,
our_htlc_minimum_msat: 1,
forwarding_fee_base_msat: 1000,
forwarding_fee_proportional_millionths: 0,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
}
}
}
Expand DownExpand Up@@ -143,46 +186,6 @@ impl Default for ChannelHandshakeLimits {
/// with our counterparty.
#[derive(Copy, Clone, Debug)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`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.
///
Expand DownExpand Up@@ -252,9 +255,6 @@ impl Default for ChannelConfig {
/// Provides sane defaults for most configurations (but with zero relay fees!).
fn default() -> Self {
ChannelConfig {
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,
Expand All@@ -264,13 +264,10 @@ impl Default for ChannelConfig {
}

impl_writeable_tlv_based!(ChannelConfig, {
(0, forwarding_fee_proportional_millionths, required),

@TheBlueMattTheBlueMattJan 18, 2022

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we cannot remove required elements, as old clients will refuse to load data serialized by new clients (which we guarantee won't happen at least across a few releases). We instead need to write the default value with something like (0, Some(DEFAULT_VALUE as u64), option)

(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),
});

/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
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
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand All@@ -374,7 +374,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;

let mut monitors = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,7 +379,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {

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.own_channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand Down
42 changes: 32 additions & 10 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
use util::config::{UserConfig,ChannelConfig,ChannelHandshakeConfig};
use util::scid_utils::scid_from_parts;

use io;
Expand DownExpand Up@@ -426,6 +426,13 @@ pub(super) struct Channel<Signer: Sign> {
#[cfg(not(any(test, feature = "_test_utils")))]
config: ChannelConfig,

#[cfg(any(test, feature = "_test_utils"))]
pub(crate) forwarding_fee_base_msat: u32,
#[cfg(not(any(test, feature = "_test_utils")))]
forwarding_fee_base_msat: u32,
forwarding_fee_proportional_millionths: u32,
cltv_expiry_delta: u16,

user_id: u64,

channel_id: [u8; 32],
Expand DownExpand Up@@ -760,11 +767,16 @@ impl<Signer: Sign> Channel<Signer> {
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
}
}
let handshake_config = config.own_channel_config.clone();

Ok(Channel {
user_id,
config: config.channel_options.clone(),

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
secp_ctx,
Expand DownExpand Up@@ -929,6 +941,7 @@ impl<Signer: Sign> Channel<Signer> {
htlc_basepoint: msg.htlc_basepoint
};
let mut local_config = (*config).channel_options.clone();
let handshake_config = (*config).own_channel_config.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)));
Expand DownExpand Up@@ -1063,6 +1076,10 @@ impl<Signer: Sign> Channel<Signer> {
user_id,
config: local_config,

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
secp_ctx,
Expand DownExpand Up@@ -4052,11 +4069,11 @@ impl<Signer: Sign> Channel<Signer> {
}

pub fn get_fee_proportional_millionths(&self) -> u32 {
self.config.forwarding_fee_proportional_millionths
self.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.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}

pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
Expand DownExpand Up@@ -4147,7 +4164,7 @@ impl<Signer: Sign> Channel<Signer> {
/// 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.forwarding_fee_base_msat
}

/// Returns true if we've ever received a message from the remote end for this Channel
Expand DownExpand Up@@ -5188,8 +5205,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {

// Write out the old serialization for the config object. This is read by version-1
// deserializers, but we will read the version in the TLV at the end instead.
self.config.forwarding_fee_proportional_millionths.write(writer)?;
self.config.cltv_expiry_delta.write(writer)?;
self.forwarding_fee_proportional_millionths.write(writer)?;
self.cltv_expiry_delta.write(writer)?;
self.config.announced_channel.write(writer)?;
self.config.commit_upfront_shutdown_pubkey.write(writer)?;

Expand DownExpand Up@@ -5450,17 +5467,18 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
let user_id = Readable::read(reader)?;

let mut config = Some(ChannelConfig::default());
let handshake_config = Some(ChannelHandshakeConfig::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)?;
// Read the old serialization of the ChannelConfig from version 0.0.98.handshake_config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
// Read the 8 bytes of backwards-compatibility ChannelConfig data.
let mut _val: u64 = Readable::read(reader)?;
}


let cltv_expiry_delta = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;
Expand DownExpand Up@@ -5708,6 +5726,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
user_id,

config: config.unwrap(),
forwarding_fee_base_msat: handshake_config.unwrap().forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.unwrap().forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.unwrap().cltv_expiry_delta,

channel_id,
channel_state,
secp_ctx,
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1468,7 +1468,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
($node: expr, $prev_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().forwarding_fee_base_msat;
expect_payment_forwarded!($node, Some(fee as u64), false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
Expand DownExpand Up@@ -1731,7 +1731,7 @@ pub fn test_default_channel_config() -> UserConfig {
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 = 6*6;
default_config.own_channel_config.cltv_expiry_delta = 6*6;
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1787,7 +1787,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// 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.own_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());
Expand DownExpand Up@@ -5135,7 +5135,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// 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.own_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);
Expand DownExpand Up@@ -5332,7 +5332,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 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.own_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);
Expand DownExpand Up@@ -6208,7 +6208,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
// 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.own_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());
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -258,7 +258,7 @@ fn test_fee_failures() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand DownExpand Up@@ -310,7 +310,7 @@ fn test_onion_failure() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/payment_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -448,7 +448,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
// 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().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
Expand Down
89 changes: 43 additions & 46 deletions lightning/src/util/config.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,46 @@ pub struct ChannelHandshakeConfig {
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
/// by the protocol.
pub our_htlc_minimum_msat: u64,
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelHandshakeConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
}

impl Default for ChannelHandshakeConfig {
Expand All@@ -55,6 +95,9 @@ impl Default for ChannelHandshakeConfig {
minimum_depth: 6,
our_to_self_delay: BREAKDOWN_TIMEOUT,
our_htlc_minimum_msat: 1,
forwarding_fee_base_msat: 1000,
forwarding_fee_proportional_millionths: 0,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
}
}
}
Expand DownExpand Up@@ -143,46 +186,6 @@ impl Default for ChannelHandshakeLimits {
/// with our counterparty.
#[derive(Copy, Clone, Debug)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`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.
///
Expand DownExpand Up@@ -252,9 +255,6 @@ impl Default for ChannelConfig {
/// Provides sane defaults for most configurations (but with zero relay fees!).
fn default() -> Self {
ChannelConfig {
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,
Expand All@@ -264,13 +264,10 @@ impl Default for ChannelConfig {
}

impl_writeable_tlv_based!(ChannelConfig, {
(0, forwarding_fee_proportional_millionths, required),

@TheBlueMattTheBlueMattJan 18, 2022

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we cannot remove required elements, as old clients will refuse to load data serialized by new clients (which we guarantee won't happen at least across a few releases). We instead need to write the default value with something like (0, Some(DEFAULT_VALUE as u64), option)

(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),
});

/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand All@@ -374,7 +374,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;

let mut monitors = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,7 +379,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {

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.own_channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand Down
42 changes: 32 additions & 10 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
use util::config::{UserConfig,ChannelConfig,ChannelHandshakeConfig};
use util::scid_utils::scid_from_parts;

use io;
Expand DownExpand Up@@ -426,6 +426,13 @@ pub(super) struct Channel<Signer: Sign> {
#[cfg(not(any(test, feature = "_test_utils")))]
config: ChannelConfig,

#[cfg(any(test, feature = "_test_utils"))]
pub(crate) forwarding_fee_base_msat: u32,
#[cfg(not(any(test, feature = "_test_utils")))]
forwarding_fee_base_msat: u32,
forwarding_fee_proportional_millionths: u32,
cltv_expiry_delta: u16,

user_id: u64,

channel_id: [u8; 32],
Expand DownExpand Up@@ -760,11 +767,16 @@ impl<Signer: Sign> Channel<Signer> {
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
}
}
let handshake_config = config.own_channel_config.clone();

Ok(Channel {
user_id,
config: config.channel_options.clone(),

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
secp_ctx,
Expand DownExpand Up@@ -929,6 +941,7 @@ impl<Signer: Sign> Channel<Signer> {
htlc_basepoint: msg.htlc_basepoint
};
let mut local_config = (*config).channel_options.clone();
let handshake_config = (*config).own_channel_config.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)));
Expand DownExpand Up@@ -1063,6 +1076,10 @@ impl<Signer: Sign> Channel<Signer> {
user_id,
config: local_config,

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
secp_ctx,
Expand DownExpand Up@@ -4052,11 +4069,11 @@ impl<Signer: Sign> Channel<Signer> {
}

pub fn get_fee_proportional_millionths(&self) -> u32 {
self.config.forwarding_fee_proportional_millionths
self.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.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}

pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
Expand DownExpand Up@@ -4147,7 +4164,7 @@ impl<Signer: Sign> Channel<Signer> {
/// 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.forwarding_fee_base_msat
}

/// Returns true if we've ever received a message from the remote end for this Channel
Expand DownExpand Up@@ -5188,8 +5205,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {

// Write out the old serialization for the config object. This is read by version-1
// deserializers, but we will read the version in the TLV at the end instead.
self.config.forwarding_fee_proportional_millionths.write(writer)?;
self.config.cltv_expiry_delta.write(writer)?;
self.forwarding_fee_proportional_millionths.write(writer)?;
self.cltv_expiry_delta.write(writer)?;
self.config.announced_channel.write(writer)?;
self.config.commit_upfront_shutdown_pubkey.write(writer)?;

Expand DownExpand Up@@ -5450,17 +5467,18 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
let user_id = Readable::read(reader)?;

let mut config = Some(ChannelConfig::default());
let handshake_config = Some(ChannelHandshakeConfig::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)?;
// Read the old serialization of the ChannelConfig from version 0.0.98.handshake_config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
// Read the 8 bytes of backwards-compatibility ChannelConfig data.
let mut _val: u64 = Readable::read(reader)?;
}


let cltv_expiry_delta = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;
Expand DownExpand Up@@ -5708,6 +5726,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
user_id,

config: config.unwrap(),
forwarding_fee_base_msat: handshake_config.unwrap().forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.unwrap().forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.unwrap().cltv_expiry_delta,

channel_id,
channel_state,
secp_ctx,
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1468,7 +1468,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
($node: expr, $prev_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().forwarding_fee_base_msat;
expect_payment_forwarded!($node, Some(fee as u64), false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
Expand DownExpand Up@@ -1731,7 +1731,7 @@ pub fn test_default_channel_config() -> UserConfig {
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 = 6*6;
default_config.own_channel_config.cltv_expiry_delta = 6*6;
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1787,7 +1787,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// 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.own_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());
Expand DownExpand Up@@ -5135,7 +5135,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// 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.own_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);
Expand DownExpand Up@@ -5332,7 +5332,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 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.own_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);
Expand DownExpand Up@@ -6208,7 +6208,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
// 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.own_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());
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -258,7 +258,7 @@ fn test_fee_failures() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand DownExpand Up@@ -310,7 +310,7 @@ fn test_onion_failure() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/payment_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -448,7 +448,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
// 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().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
Expand Down
89 changes: 43 additions & 46 deletions lightning/src/util/config.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,46 @@ pub struct ChannelHandshakeConfig {
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
/// by the protocol.
pub our_htlc_minimum_msat: u64,
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelHandshakeConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
}

impl Default for ChannelHandshakeConfig {
Expand All@@ -55,6 +95,9 @@ impl Default for ChannelHandshakeConfig {
minimum_depth: 6,
our_to_self_delay: BREAKDOWN_TIMEOUT,
our_htlc_minimum_msat: 1,
forwarding_fee_base_msat: 1000,
forwarding_fee_proportional_millionths: 0,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
}
}
}
Expand DownExpand Up@@ -143,46 +186,6 @@ impl Default for ChannelHandshakeLimits {
/// with our counterparty.
#[derive(Copy, Clone, Debug)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`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.
///
Expand DownExpand Up@@ -252,9 +255,6 @@ impl Default for ChannelConfig {
/// Provides sane defaults for most configurations (but with zero relay fees!).
fn default() -> Self {
ChannelConfig {
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,
Expand All@@ -264,13 +264,10 @@ impl Default for ChannelConfig {
}

impl_writeable_tlv_based!(ChannelConfig, {
(0, forwarding_fee_proportional_millionths, required),

@TheBlueMattTheBlueMattJan 18, 2022

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we cannot remove required elements, as old clients will refuse to load data serialized by new clients (which we guarantee won't happen at least across a few releases). We instead need to write the default value with something like (0, Some(DEFAULT_VALUE as u64), option)

(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),
});

/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand All@@ -374,7 +374,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;

let mut monitors = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,7 +379,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {

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.own_channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand Down
42 changes: 32 additions & 10 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
use util::config::{UserConfig,ChannelConfig,ChannelHandshakeConfig};
use util::scid_utils::scid_from_parts;

use io;
Expand DownExpand Up@@ -426,6 +426,13 @@ pub(super) struct Channel<Signer: Sign> {
#[cfg(not(any(test, feature = "_test_utils")))]
config: ChannelConfig,

#[cfg(any(test, feature = "_test_utils"))]
pub(crate) forwarding_fee_base_msat: u32,
#[cfg(not(any(test, feature = "_test_utils")))]
forwarding_fee_base_msat: u32,
forwarding_fee_proportional_millionths: u32,
cltv_expiry_delta: u16,

user_id: u64,

channel_id: [u8; 32],
Expand DownExpand Up@@ -760,11 +767,16 @@ impl<Signer: Sign> Channel<Signer> {
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
}
}
let handshake_config = config.own_channel_config.clone();

Ok(Channel {
user_id,
config: config.channel_options.clone(),

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
secp_ctx,
Expand DownExpand Up@@ -929,6 +941,7 @@ impl<Signer: Sign> Channel<Signer> {
htlc_basepoint: msg.htlc_basepoint
};
let mut local_config = (*config).channel_options.clone();
let handshake_config = (*config).own_channel_config.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)));
Expand DownExpand Up@@ -1063,6 +1076,10 @@ impl<Signer: Sign> Channel<Signer> {
user_id,
config: local_config,

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
secp_ctx,
Expand DownExpand Up@@ -4052,11 +4069,11 @@ impl<Signer: Sign> Channel<Signer> {
}

pub fn get_fee_proportional_millionths(&self) -> u32 {
self.config.forwarding_fee_proportional_millionths
self.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.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}

pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
Expand DownExpand Up@@ -4147,7 +4164,7 @@ impl<Signer: Sign> Channel<Signer> {
/// 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.forwarding_fee_base_msat
}

/// Returns true if we've ever received a message from the remote end for this Channel
Expand DownExpand Up@@ -5188,8 +5205,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {

// Write out the old serialization for the config object. This is read by version-1
// deserializers, but we will read the version in the TLV at the end instead.
self.config.forwarding_fee_proportional_millionths.write(writer)?;
self.config.cltv_expiry_delta.write(writer)?;
self.forwarding_fee_proportional_millionths.write(writer)?;
self.cltv_expiry_delta.write(writer)?;
self.config.announced_channel.write(writer)?;
self.config.commit_upfront_shutdown_pubkey.write(writer)?;

Expand DownExpand Up@@ -5450,17 +5467,18 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
let user_id = Readable::read(reader)?;

let mut config = Some(ChannelConfig::default());
let handshake_config = Some(ChannelHandshakeConfig::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)?;
// Read the old serialization of the ChannelConfig from version 0.0.98.handshake_config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
// Read the 8 bytes of backwards-compatibility ChannelConfig data.
let mut _val: u64 = Readable::read(reader)?;
}


let cltv_expiry_delta = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;
Expand DownExpand Up@@ -5708,6 +5726,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
user_id,

config: config.unwrap(),
forwarding_fee_base_msat: handshake_config.unwrap().forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.unwrap().forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.unwrap().cltv_expiry_delta,

channel_id,
channel_state,
secp_ctx,
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1468,7 +1468,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
($node: expr, $prev_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().forwarding_fee_base_msat;
expect_payment_forwarded!($node, Some(fee as u64), false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
Expand DownExpand Up@@ -1731,7 +1731,7 @@ pub fn test_default_channel_config() -> UserConfig {
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 = 6*6;
default_config.own_channel_config.cltv_expiry_delta = 6*6;
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1787,7 +1787,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// 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.own_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());
Expand DownExpand Up@@ -5135,7 +5135,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// 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.own_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);
Expand DownExpand Up@@ -5332,7 +5332,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 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.own_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);
Expand DownExpand Up@@ -6208,7 +6208,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
// 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.own_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());
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -258,7 +258,7 @@ fn test_fee_failures() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand DownExpand Up@@ -310,7 +310,7 @@ fn test_onion_failure() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/payment_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -448,7 +448,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
// 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().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
Expand Down
89 changes: 43 additions & 46 deletions lightning/src/util/config.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,46 @@ pub struct ChannelHandshakeConfig {
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
/// by the protocol.
pub our_htlc_minimum_msat: u64,
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelHandshakeConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
}

impl Default for ChannelHandshakeConfig {
Expand All@@ -55,6 +95,9 @@ impl Default for ChannelHandshakeConfig {
minimum_depth: 6,
our_to_self_delay: BREAKDOWN_TIMEOUT,
our_htlc_minimum_msat: 1,
forwarding_fee_base_msat: 1000,
forwarding_fee_proportional_millionths: 0,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
}
}
}
Expand DownExpand Up@@ -143,46 +186,6 @@ impl Default for ChannelHandshakeLimits {
/// with our counterparty.
#[derive(Copy, Clone, Debug)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`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.
///
Expand DownExpand Up@@ -252,9 +255,6 @@ impl Default for ChannelConfig {
/// Provides sane defaults for most configurations (but with zero relay fees!).
fn default() -> Self {
ChannelConfig {
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,
Expand All@@ -264,13 +264,10 @@ impl Default for ChannelConfig {
}

impl_writeable_tlv_based!(ChannelConfig, {
(0, forwarding_fee_proportional_millionths, required),

@TheBlueMattTheBlueMattJan 18, 2022

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we cannot remove required elements, as old clients will refuse to load data serialized by new clients (which we guarantee won't happen at least across a few releases). We instead need to write the default value with something like (0, Some(DEFAULT_VALUE as u64), option)

(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),
});

/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
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
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand All@@ -374,7 +374,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
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.own_channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;

let mut monitors = HashMap::new();
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -379,7 +379,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {

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.own_channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_options.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
let params = ChainParameters {
Expand Down
42 changes: 32 additions & 10 deletions lightning/src/ln/channel.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,7 @@ use util::events::ClosureReason;
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
use util::config::{UserConfig,ChannelConfig,ChannelHandshakeConfig};
use util::scid_utils::scid_from_parts;

use io;
Expand DownExpand Up@@ -426,6 +426,13 @@ pub(super) struct Channel<Signer: Sign> {
#[cfg(not(any(test, feature = "_test_utils")))]
config: ChannelConfig,

#[cfg(any(test, feature = "_test_utils"))]
pub(crate) forwarding_fee_base_msat: u32,
#[cfg(not(any(test, feature = "_test_utils")))]
forwarding_fee_base_msat: u32,
forwarding_fee_proportional_millionths: u32,
cltv_expiry_delta: u16,

user_id: u64,

channel_id: [u8; 32],
Expand DownExpand Up@@ -760,11 +767,16 @@ impl<Signer: Sign> Channel<Signer> {
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
}
}
let handshake_config = config.own_channel_config.clone();

Ok(Channel {
user_id,
config: config.channel_options.clone(),

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: keys_provider.get_secure_random_bytes(),
channel_state: ChannelState::OurInitSent as u32,
secp_ctx,
Expand DownExpand Up@@ -929,6 +941,7 @@ impl<Signer: Sign> Channel<Signer> {
htlc_basepoint: msg.htlc_basepoint
};
let mut local_config = (*config).channel_options.clone();
let handshake_config = (*config).own_channel_config.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)));
Expand DownExpand Up@@ -1063,6 +1076,10 @@ impl<Signer: Sign> Channel<Signer> {
user_id,
config: local_config,

forwarding_fee_base_msat: handshake_config.forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.cltv_expiry_delta,

channel_id: msg.temporary_channel_id,
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
secp_ctx,
Expand DownExpand Up@@ -4052,11 +4069,11 @@ impl<Signer: Sign> Channel<Signer> {
}

pub fn get_fee_proportional_millionths(&self) -> u32 {
self.config.forwarding_fee_proportional_millionths
self.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.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}

pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
Expand DownExpand Up@@ -4147,7 +4164,7 @@ impl<Signer: Sign> Channel<Signer> {
/// 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.forwarding_fee_base_msat
}

/// Returns true if we've ever received a message from the remote end for this Channel
Expand DownExpand Up@@ -5188,8 +5205,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {

// Write out the old serialization for the config object. This is read by version-1
// deserializers, but we will read the version in the TLV at the end instead.
self.config.forwarding_fee_proportional_millionths.write(writer)?;
self.config.cltv_expiry_delta.write(writer)?;
self.forwarding_fee_proportional_millionths.write(writer)?;
self.cltv_expiry_delta.write(writer)?;
self.config.announced_channel.write(writer)?;
self.config.commit_upfront_shutdown_pubkey.write(writer)?;

Expand DownExpand Up@@ -5450,17 +5467,18 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
let user_id = Readable::read(reader)?;

let mut config = Some(ChannelConfig::default());
let handshake_config = Some(ChannelHandshakeConfig::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)?;
// Read the old serialization of the ChannelConfig from version 0.0.98.handshake_config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
} else {
// Read the 8 bytes of backwards-compatibility ChannelConfig data.
let mut _val: u64 = Readable::read(reader)?;
}


let cltv_expiry_delta = Readable::read(reader)?;
let channel_id = Readable::read(reader)?;
let channel_state = Readable::read(reader)?;
let channel_value_satoshis = Readable::read(reader)?;
Expand DownExpand Up@@ -5708,6 +5726,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
user_id,

config: config.unwrap(),
forwarding_fee_base_msat: handshake_config.unwrap().forwarding_fee_base_msat,
forwarding_fee_proportional_millionths: handshake_config.unwrap().forwarding_fee_proportional_millionths,
cltv_expiry_delta: handshake_config.unwrap().cltv_expiry_delta,

channel_id,
channel_state,
secp_ctx,
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1468,7 +1468,7 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
($node: expr, $prev_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().forwarding_fee_base_msat;
expect_payment_forwarded!($node, Some(fee as u64), false);
expected_total_fee_msat += fee as u64;
check_added_monitors!($node, 1);
Expand DownExpand Up@@ -1731,7 +1731,7 @@ pub fn test_default_channel_config() -> UserConfig {
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 = 6*6;
default_config.own_channel_config.cltv_expiry_delta = 6*6;
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
// When most of our tests were written, the default HTLC minimum was fixed at 1000.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/functional_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1787,7 +1787,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// 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.own_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());
Expand DownExpand Up@@ -5135,7 +5135,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// 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.own_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);
Expand DownExpand Up@@ -5332,7 +5332,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 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.own_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);
Expand DownExpand Up@@ -6208,7 +6208,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
// 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.own_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());
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/onion_route_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -258,7 +258,7 @@ fn test_fee_failures() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand DownExpand Up@@ -310,7 +310,7 @@ fn test_onion_failure() {
// 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.own_channel_config.forwarding_fee_base_msat = 196;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/payment_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -448,7 +448,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
// 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().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
Expand Down
89 changes: 43 additions & 46 deletions lightning/src/util/config.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,46 @@ pub struct ChannelHandshakeConfig {
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
/// by the protocol.
pub our_htlc_minimum_msat: u64,
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelHandshakeConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
pub cltv_expiry_delta: u16,
}

impl Default for ChannelHandshakeConfig {
Expand All@@ -55,6 +95,9 @@ impl Default for ChannelHandshakeConfig {
minimum_depth: 6,
our_to_self_delay: BREAKDOWN_TIMEOUT,
our_htlc_minimum_msat: 1,
forwarding_fee_base_msat: 1000,
forwarding_fee_proportional_millionths: 0,
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
}
}
}
Expand DownExpand Up@@ -143,46 +186,6 @@ impl Default for ChannelHandshakeLimits {
/// with our counterparty.
#[derive(Copy, Clone, Debug)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Default value: 0.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// The default value of a single satoshi roughly matches the market rate on many routing nodes
/// as of July 2021. Adjusting it upwards or downwards may change whether nodes route through
/// this node.
///
/// Default value: 1000.
///
/// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// This is analogous to [`ChannelHandshakeConfig::our_to_self_delay`] but applies to in-flight
/// HTLC balance when a channel appears on-chain whereas
/// [`ChannelHandshakeConfig::our_to_self_delay`] applies to the remaining
/// (non-HTLC-encumbered) balance.
///
/// Thus, for HTLC-encumbered balances to be enforced on-chain when a channel is force-closed,
/// we (or one of our watchtowers) MUST be online to check for broadcast of the current
/// commitment transaction at least once per this many blocks (minus some margin to allow us
/// enough time to broadcast and confirm a transaction, possibly with time in between to RBF
/// the spending transaction).
///
/// Default value: 72 (12 hours at an average of 6 blocks/hour).
/// Minimum value: [`MIN_CLTV_EXPIRY_DELTA`], any values less than this will be treated as
/// [`MIN_CLTV_EXPIRY_DELTA`] instead.
///
/// [`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.
///
Expand DownExpand Up@@ -252,9 +255,6 @@ impl Default for ChannelConfig {
/// Provides sane defaults for most configurations (but with zero relay fees!).
fn default() -> Self {
ChannelConfig {
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,
Expand All@@ -264,13 +264,10 @@ impl Default for ChannelConfig {
}

impl_writeable_tlv_based!(ChannelConfig, {
(0, forwarding_fee_proportional_millionths, required),

@TheBlueMattTheBlueMattJan 18, 2022

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we cannot remove required elements, as old clients will refuse to load data serialized by new clients (which we guarantee won't happen at least across a few releases). We instead need to write the default value with something like (0, Some(DEFAULT_VALUE as u64), option)

(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),
});

/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
Expand Down