Skip to content

Commit 8856112

Browse files
committed
Optionally reject HTLC forwards over priv chans with a new config
Private nodes should never wish to forward HTLCs at all, which we support here by disabling forwards out over private channels by default. As private nodes should not have any public channels, this suffices, without allowing users to disable forwarding over channels announced in the routing graph already. Closes #969
1 parent 704a16f commit 8856112

File tree

4 files changed

+198
-13
lines changed

4 files changed

+198
-13
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,15 +1546,23 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
15461546
// short_channel_id is non-0 in any ::Forward.
15471547
if let &PendingHTLCRouting::Forward { ref short_channel_id, .. } = routing {
15481548
let id_option = channel_state.as_ref().unwrap().short_to_id.get(&short_channel_id).cloned();
1549-
let forwarding_id = match id_option {
1550-
None => { // unknown_next_peer
1551-
return_err!("Don't have available channel for forwarding as requested.", 0x4000 | 10, &[0;0]);
1552-
},
1553-
Some(id) => id.clone(),
1554-
};
15551549
if let Some((err, code, chan_update)) = loop {
1550+
let forwarding_id = match id_option {
1551+
None => { // unknown_next_peer
1552+
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
1553+
},
1554+
Some(id) => id.clone(),
1555+
};
1556+
15561557
let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap();
15571558

1559+
if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
1560+
// Note that the behavior here should be identical to the above block - we
1561+
// should NOT reveal the existence or non-existence of a private channel if
1562+
// we don't allow forwards outbound over them.
1563+
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
1564+
}
1565+
15581566
// Note that we could technically not return an error yet here and just hope
15591567
// that the connection is reestablished or monitor updated by the time we get
15601568
// around to doing the actual forward, but better to fail early if we can and

lightning/src/ln/functional_test_utils.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,10 @@ pub const TEST_FINAL_CLTV: u32 = 70;
12061206
pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) -> (PaymentPreimage, PaymentHash, PaymentSecret) {
12071207
let net_graph_msg_handler = &origin_node.net_graph_msg_handler;
12081208
let logger = test_utils::TestLogger::new();
1209-
let route = get_route(&origin_node.node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &expected_route.last().unwrap().node.get_our_node_id(), Some(InvoiceFeatures::known()), None, &Vec::new(), recv_value, TEST_FINAL_CLTV, &logger).unwrap();
1209+
let route = get_route(&origin_node.node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(),
1210+
&expected_route.last().unwrap().node.get_our_node_id(), Some(InvoiceFeatures::known()),
1211+
Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()), &[],
1212+
recv_value, TEST_FINAL_CLTV, &logger).unwrap();
12101213
assert_eq!(route.paths.len(), 1);
12111214
assert_eq!(route.paths[0].len(), expected_route.len());
12121215
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {

lightning/src/ln/functional_tests.rs

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
2222
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA};
2323
use ln::channel::{Channel, ChannelError};
2424
use ln::{chan_utils, onion_utils};
25-
use routing::router::{Route, RouteHop, get_route};
25+
use routing::router::{Route, RouteHop, RouteHint, RouteHintHop, get_route};
26+
use routing::network_graph::RoutingFees;
2627
use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
2728
use ln::msgs;
2829
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
@@ -7914,6 +7915,158 @@ fn test_announce_disable_channels() {
79147915
}
79157916
}
79167917

7918+
#[test]
7919+
fn test_priv_forwarding_rejection() {
7920+
// If we have a private channel with outbound liquidity, and
7921+
// UserConfig::accept_forwards_to_priv_channels is set to false, we should reject any attempts
7922+
// to forward through that channel.
7923+
let chanmon_cfgs = create_chanmon_cfgs(3);
7924+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
7925+
let mut no_announce_cfg = test_default_channel_config();
7926+
no_announce_cfg.channel_options.announced_channel = false;
7927+
no_announce_cfg.accept_forwards_to_priv_channels = false;
7928+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(no_announce_cfg), None]);
7929+
let persister: test_utils::TestPersister;
7930+
let new_chain_monitor: test_utils::TestChainMonitor;
7931+
let nodes_1_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
7932+
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
7933+
7934+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
7935+
7936+
// Note that the create_*_chan functions in utils requires announcement_signatures, which we do
7937+
// not send for private channels.
7938+
nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
7939+
let open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[2].node.get_our_node_id());
7940+
nodes[2].node.handle_open_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel);
7941+
let accept_channel = get_event_msg!(nodes[2], MessageSendEvent::SendAcceptChannel, nodes[1].node.get_our_node_id());
7942+
nodes[1].node.handle_accept_channel(&nodes[2].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
7943+
7944+
let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[1], 1_000_000, 42);
7945+
nodes[1].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
7946+
nodes[2].node.handle_funding_created(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingCreated, nodes[2].node.get_our_node_id()));
7947+
check_added_monitors!(nodes[2], 1);
7948+
7949+
nodes[1].node.handle_funding_signed(&nodes[2].node.get_our_node_id(), &get_event_msg!(nodes[2], MessageSendEvent::SendFundingSigned, nodes[1].node.get_our_node_id()));
7950+
check_added_monitors!(nodes[1], 1);
7951+
7952+
let conf_height = core::cmp::max(nodes[1].best_block_info().1 + 1, nodes[2].best_block_info().1 + 1);
7953+
confirm_transaction_at(&nodes[1], &tx, conf_height);
7954+
connect_blocks(&nodes[1], CHAN_CONFIRM_DEPTH - 1);
7955+
confirm_transaction_at(&nodes[2], &tx, conf_height);
7956+
connect_blocks(&nodes[2], CHAN_CONFIRM_DEPTH - 1);
7957+
nodes[1].node.handle_funding_locked(&nodes[2].node.get_our_node_id(), &get_event_msg!(nodes[2], MessageSendEvent::SendFundingLocked, nodes[1].node.get_our_node_id()));
7958+
let funding_locked = get_event_msg!(nodes[1], MessageSendEvent::SendFundingLocked, nodes[2].node.get_our_node_id());
7959+
nodes[2].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &funding_locked);
7960+
7961+
assert!(nodes[0].node.list_usable_channels()[0].is_public);
7962+
assert_eq!(nodes[1].node.list_usable_channels().len(), 2);
7963+
assert!(!nodes[2].node.list_usable_channels()[0].is_public);
7964+
7965+
// We should always be able to forward through nodes[1] as long as its out through a public
7966+
// channel:
7967+
send_payment(&nodes[2], &[&nodes[1], &nodes[0]], 10_000);
7968+
7969+
// ... however, if we send to nodes[2], we will have to pass the private channel from nodes[1]
7970+
// to nodes[2], which should be rejected:
7971+
let (our_payment_preimage, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(nodes[2]);
7972+
let route = get_route(&nodes[0].node.get_our_node_id(),
7973+
&nodes[0].net_graph_msg_handler.network_graph.read().unwrap(),
7974+
&nodes[2].node.get_our_node_id(), Some(InvoiceFeatures::known()), None,
7975+
&[&RouteHint(vec![RouteHintHop {
7976+
src_node_id: nodes[1].node.get_our_node_id(),
7977+
short_channel_id: nodes[2].node.list_channels()[0].short_channel_id.unwrap(),
7978+
fees: RoutingFees { base_msat: 1000, proportional_millionths: 0 },
7979+
cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
7980+
htlc_minimum_msat: None,
7981+
htlc_maximum_msat: None,
7982+
}])], 10_000, TEST_FINAL_CLTV, nodes[0].logger).unwrap();
7983+
7984+
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
7985+
check_added_monitors!(nodes[0], 1);
7986+
let payment_event = SendEvent::from_event(nodes[0].node.get_and_clear_pending_msg_events().remove(0));
7987+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
7988+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false, true);
7989+
7990+
let htlc_fail_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
7991+
assert!(htlc_fail_updates.update_add_htlcs.is_empty());
7992+
assert_eq!(htlc_fail_updates.update_fail_htlcs.len(), 1);
7993+
assert!(htlc_fail_updates.update_fail_malformed_htlcs.is_empty());
7994+
assert!(htlc_fail_updates.update_fee.is_none());
7995+
7996+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_fail_updates.update_fail_htlcs[0]);
7997+
commitment_signed_dance!(nodes[0], nodes[1], htlc_fail_updates.commitment_signed, true, true);
7998+
expect_payment_failed!(nodes[0], our_payment_hash, false);
7999+
expect_payment_failure_chan_update!(nodes[0], nodes[2].node.list_channels()[0].short_channel_id.unwrap(), true);
8000+
8001+
// Now disconnect nodes[1] from its peers and restart with accept_forwards_to_priv_channels set
8002+
// to true. Sadly there is currently no way to change it at runtime.
8003+
8004+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
8005+
nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
8006+
8007+
let nodes_1_serialized = nodes[1].node.encode();
8008+
let mut monitor_a_serialized = test_utils::TestVecWriter(Vec::new());
8009+
let mut monitor_b_serialized = test_utils::TestVecWriter(Vec::new());
8010+
{
8011+
let mons = nodes[1].chain_monitor.chain_monitor.monitors.read().unwrap();
8012+
let mut mon_iter = mons.iter();
8013+
mon_iter.next().unwrap().1.write(&mut monitor_a_serialized).unwrap();
8014+
mon_iter.next().unwrap().1.write(&mut monitor_b_serialized).unwrap();
8015+
}
8016+
8017+
persister = test_utils::TestPersister::new();
8018+
let keys_manager = &chanmon_cfgs[1].keys_manager;
8019+
new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[1].chain_source), nodes[1].tx_broadcaster.clone(), nodes[1].logger, node_cfgs[1].fee_estimator, &persister, keys_manager);
8020+
nodes[1].chain_monitor = &new_chain_monitor;
8021+
8022+
let mut monitor_a_read = &monitor_a_serialized.0[..];
8023+
let mut monitor_b_read = &monitor_b_serialized.0[..];
8024+
let (_, mut monitor_a) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut monitor_a_read, keys_manager).unwrap();
8025+
let (_, mut monitor_b) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut monitor_b_read, keys_manager).unwrap();
8026+
assert!(monitor_a_read.is_empty());
8027+
assert!(monitor_b_read.is_empty());
8028+
8029+
no_announce_cfg.accept_forwards_to_priv_channels = true;
8030+
8031+
let mut nodes_1_read = &nodes_1_serialized[..];
8032+
let (_, nodes_1_deserialized_tmp) = {
8033+
let mut channel_monitors = HashMap::new();
8034+
channel_monitors.insert(monitor_a.get_funding_txo().0, &mut monitor_a);
8035+
channel_monitors.insert(monitor_b.get_funding_txo().0, &mut monitor_b);
8036+
<(BlockHash, ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut nodes_1_read, ChannelManagerReadArgs {
8037+
default_config: no_announce_cfg,
8038+
keys_manager,
8039+
fee_estimator: node_cfgs[1].fee_estimator,
8040+
chain_monitor: nodes[1].chain_monitor,
8041+
tx_broadcaster: nodes[1].tx_broadcaster.clone(),
8042+
logger: nodes[1].logger,
8043+
channel_monitors,
8044+
}).unwrap()
8045+
};
8046+
assert!(nodes_1_read.is_empty());
8047+
nodes_1_deserialized = nodes_1_deserialized_tmp;
8048+
8049+
assert!(nodes[1].chain_monitor.watch_channel(monitor_a.get_funding_txo().0, monitor_a).is_ok());
8050+
assert!(nodes[1].chain_monitor.watch_channel(monitor_b.get_funding_txo().0, monitor_b).is_ok());
8051+
check_added_monitors!(nodes[1], 2);
8052+
nodes[1].node = &nodes_1_deserialized;
8053+
8054+
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() });
8055+
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
8056+
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()));
8057+
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()));
8058+
8059+
nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() });
8060+
nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
8061+
nodes[2].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[2].node.get_our_node_id()));
8062+
nodes[1].node.handle_channel_reestablish(&nodes[2].node.get_our_node_id(), &get_event_msg!(nodes[2], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()));
8063+
8064+
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
8065+
check_added_monitors!(nodes[0], 1);
8066+
pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], 10_000, our_payment_hash, our_payment_secret);
8067+
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], our_payment_preimage);
8068+
}
8069+
79178070
#[test]
79188071
fn test_bump_penalty_txn_on_revoked_commitment() {
79198072
// In case of penalty txn with too low feerates for getting into mempools, RBF-bump them to be sure

lightning/src/util/config.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,14 @@ pub struct ChannelHandshakeLimits {
105105
///
106106
/// Default value: 144, or roughly one day and only applies to outbound channels.
107107
pub max_minimum_depth: u32,
108-
/// Set to force the incoming channel to match our announced channel preference in
109-
/// ChannelConfig.
108+
/// Set to force an incoming channel to match our announced channel preference in
109+
/// [`ChannelConfig::announced_channel`].
110110
///
111-
/// Default value: true, to make the default that no announced channels are possible (which is
112-
/// appropriate for any nodes which are not online very reliably).
111+
/// For a node which is not online reliably, this should be set to true and
112+
/// [`ChannelConfig::announced_channel`] set to false, ensuring that no announced (aka public)
113+
/// channels will ever be opened.
114+
///
115+
/// Default value: true.
113116
pub force_announced_channel_preference: bool,
114117
/// Set to the amount of time we're willing to wait to claim money back to us.
115118
///
@@ -184,7 +187,7 @@ pub struct ChannelConfig {
184187
/// This should only be set to true for nodes which expect to be online reliably.
185188
///
186189
/// As the node which funds a channel picks this value this will only apply for new outbound
187-
/// channels unless ChannelHandshakeLimits::force_announced_channel_preferences is set.
190+
/// channels unless [`ChannelHandshakeLimits::force_announced_channel_preference`] is set.
188191
///
189192
/// This cannot be changed after the initial channel handshake.
190193
///
@@ -237,6 +240,23 @@ pub struct UserConfig {
237240
pub peer_channel_config_limits: ChannelHandshakeLimits,
238241
/// Channel config which affects behavior during channel lifetime.
239242
pub channel_options: ChannelConfig,
243+
/// If this is set to false, we will reject any HTLCs which were to be forwarded over private
244+
/// channels. This prevents us from taking on HTLC-forwarding risk when we intend to run as a
245+
/// node which is not online reliably.
246+
///
247+
/// For nodes which are not online reliably, you should set all channels to *not* be announced
248+
/// (using [`ChannelConfig::announced_channel`] and
249+
/// [`ChannelHandshakeLimits::force_announced_channel_preference`]) and set this to false to
250+
/// ensure you are not exposed to any forwarding risk.
251+
///
252+
/// Note that because you cannot change a channel's announced state after creation, there is no
253+
/// way to disable forwarding on public channels retroactively. Thus, in order to change a node
254+
/// from a publicly-announced forwarding node to a private non-forwarding node you must close
255+
/// all your channels and open new ones. For privacy, you should also change your node_id
256+
/// (swapping all private and public key material for new ones) at that time.
257+
///
258+
/// Default value: false.
259+
pub accept_forwards_to_priv_channels: bool,
240260
}
241261

242262
impl Default for UserConfig {
@@ -245,6 +265,7 @@ impl Default for UserConfig {
245265
own_channel_config: ChannelHandshakeConfig::default(),
246266
peer_channel_config_limits: ChannelHandshakeLimits::default(),
247267
channel_options: ChannelConfig::default(),
268+
accept_forwards_to_priv_channels: false,
248269
}
249270
}
250271
}

0 commit comments

Comments
 (0)