Skip to content

Commit 5b15ad4

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 1a4065f commit 5b15ad4

File tree

4 files changed

+191
-13
lines changed

4 files changed

+191
-13
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,15 +1520,23 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
15201520
// short_channel_id is non-0 in any ::Forward.
15211521
if let &PendingHTLCRouting::Forward { ref short_channel_id, .. } = routing {
15221522
let id_option = channel_state.as_ref().unwrap().short_to_id.get(&short_channel_id).cloned();
1523-
let forwarding_id = match id_option {
1524-
None => { // unknown_next_peer
1525-
return_err!("Don't have available channel for forwarding as requested.", 0x4000 | 10, &[0;0]);
1526-
},
1527-
Some(id) => id.clone(),
1528-
};
15291523
if let Some((err, code, chan_update)) = loop {
1524+
let forwarding_id = match id_option {
1525+
None => { // unknown_next_peer
1526+
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
1527+
},
1528+
Some(id) => id.clone(),
1529+
};
1530+
15301531
let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap();
15311532

1533+
if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
1534+
// Note that the behavior here should be identical to the above block - we
1535+
// should NOT reveal the existence or non-existence of a private channel if
1536+
// we don't allow forwards outbound over them.
1537+
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
1538+
}
1539+
15321540
// Note that we could technically not return an error yet here and just hope
15331541
// that the connection is reestablished or monitor updated by the time we get
15341542
// 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: 147 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};
@@ -7913,6 +7914,151 @@ fn test_announce_disable_channels() {
79137914
}
79147915
}
79157916

7917+
#[test]
7918+
fn test_priv_forwarding_rejection() {
7919+
// If we have a private channel with outbound liquidity, and
7920+
// UserConfig::accept_forwards_to_priv_channels is set to false, we should reject any attempts
7921+
// to forward through that channel.
7922+
let chanmon_cfgs = create_chanmon_cfgs(3);
7923+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
7924+
let mut no_announce_cfg = test_default_channel_config();
7925+
no_announce_cfg.channel_options.announced_channel = false;
7926+
no_announce_cfg.accept_forwards_to_priv_channels = false;
7927+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(no_announce_cfg), None]);
7928+
let persister: test_utils::TestPersister;
7929+
let new_chain_monitor: test_utils::TestChainMonitor;
7930+
let nodes_1_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
7931+
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
7932+
7933+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
7934+
7935+
nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
7936+
let open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[2].node.get_our_node_id());
7937+
nodes[2].node.handle_open_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel);
7938+
let accept_channel = get_event_msg!(nodes[2], MessageSendEvent::SendAcceptChannel, nodes[1].node.get_our_node_id());
7939+
nodes[1].node.handle_accept_channel(&nodes[2].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
7940+
7941+
let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[1], 1_000_000, 42);
7942+
nodes[1].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
7943+
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()));
7944+
check_added_monitors!(nodes[2], 1);
7945+
7946+
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()));
7947+
check_added_monitors!(nodes[1], 1);
7948+
7949+
let conf_height = core::cmp::max(nodes[1].best_block_info().1 + 1, nodes[2].best_block_info().1 + 1);
7950+
confirm_transaction_at(&nodes[1], &tx, conf_height);
7951+
connect_blocks(&nodes[1], CHAN_CONFIRM_DEPTH - 1);
7952+
confirm_transaction_at(&nodes[2], &tx, conf_height);
7953+
connect_blocks(&nodes[2], CHAN_CONFIRM_DEPTH - 1);
7954+
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()));
7955+
let funding_locked = get_event_msg!(nodes[1], MessageSendEvent::SendFundingLocked, nodes[2].node.get_our_node_id());
7956+
nodes[2].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &funding_locked);
7957+
7958+
assert!(nodes[0].node.list_usable_channels()[0].is_public);
7959+
assert_eq!(nodes[1].node.list_usable_channels().len(), 2);
7960+
assert!(!nodes[2].node.list_usable_channels()[0].is_public);
7961+
7962+
// We should always be able to forward through nodes[1] as long as its out through a public
7963+
// channel:
7964+
send_payment(&nodes[2], &[&nodes[1], &nodes[0]], 10_000);
7965+
7966+
let (our_payment_preimage, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(nodes[2]);
7967+
let route = get_route(&nodes[0].node.get_our_node_id(),
7968+
&nodes[0].net_graph_msg_handler.network_graph.read().unwrap(),
7969+
&nodes[2].node.get_our_node_id(), Some(InvoiceFeatures::known()), None,
7970+
&[&RouteHint(vec![RouteHintHop {
7971+
src_node_id: nodes[1].node.get_our_node_id(),
7972+
short_channel_id: nodes[2].node.list_channels()[0].short_channel_id.unwrap(),
7973+
fees: RoutingFees { base_msat: 1000, proportional_millionths: 0 },
7974+
cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
7975+
htlc_minimum_msat: None,
7976+
htlc_maximum_msat: None,
7977+
}])], 10_000, TEST_FINAL_CLTV, nodes[0].logger).unwrap();
7978+
7979+
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
7980+
check_added_monitors!(nodes[0], 1);
7981+
let payment_event = SendEvent::from_event(nodes[0].node.get_and_clear_pending_msg_events().remove(0));
7982+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
7983+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false, true);
7984+
7985+
let htlc_fail_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
7986+
assert!(htlc_fail_updates.update_add_htlcs.is_empty());
7987+
assert_eq!(htlc_fail_updates.update_fail_htlcs.len(), 1);
7988+
assert!(htlc_fail_updates.update_fail_malformed_htlcs.is_empty());
7989+
assert!(htlc_fail_updates.update_fee.is_none());
7990+
7991+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_fail_updates.update_fail_htlcs[0]);
7992+
commitment_signed_dance!(nodes[0], nodes[1], htlc_fail_updates.commitment_signed, true, true);
7993+
expect_payment_failed!(nodes[0], our_payment_hash, false);
7994+
expect_payment_failure_chan_update!(nodes[0], nodes[2].node.list_channels()[0].short_channel_id.unwrap(), true);
7995+
7996+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
7997+
nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
7998+
7999+
let nodes_1_serialized = nodes[1].node.encode();
8000+
let mut monitor_a_serialized = test_utils::TestVecWriter(Vec::new());
8001+
let mut monitor_b_serialized = test_utils::TestVecWriter(Vec::new());
8002+
{
8003+
let mons = nodes[1].chain_monitor.chain_monitor.monitors.read().unwrap();
8004+
let mut mon_iter = mons.iter();
8005+
mon_iter.next().unwrap().1.write(&mut monitor_a_serialized).unwrap();
8006+
mon_iter.next().unwrap().1.write(&mut monitor_b_serialized).unwrap();
8007+
}
8008+
8009+
persister = test_utils::TestPersister::new();
8010+
let keys_manager = &chanmon_cfgs[1].keys_manager;
8011+
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);
8012+
nodes[1].chain_monitor = &new_chain_monitor;
8013+
8014+
let mut monitor_a_read = &monitor_a_serialized.0[..];
8015+
let mut monitor_b_read = &monitor_b_serialized.0[..];
8016+
let (_, mut monitor_a) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut monitor_a_read, keys_manager).unwrap();
8017+
let (_, mut monitor_b) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut monitor_b_read, keys_manager).unwrap();
8018+
assert!(monitor_a_read.is_empty());
8019+
assert!(monitor_b_read.is_empty());
8020+
8021+
no_announce_cfg.accept_forwards_to_priv_channels = true;
8022+
8023+
let mut nodes_1_read = &nodes_1_serialized[..];
8024+
let (_, nodes_1_deserialized_tmp) = {
8025+
let mut channel_monitors = HashMap::new();
8026+
channel_monitors.insert(monitor_a.get_funding_txo().0, &mut monitor_a);
8027+
channel_monitors.insert(monitor_b.get_funding_txo().0, &mut monitor_b);
8028+
<(BlockHash, ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut nodes_1_read, ChannelManagerReadArgs {
8029+
default_config: no_announce_cfg,
8030+
keys_manager,
8031+
fee_estimator: node_cfgs[1].fee_estimator,
8032+
chain_monitor: nodes[1].chain_monitor,
8033+
tx_broadcaster: nodes[1].tx_broadcaster.clone(),
8034+
logger: nodes[1].logger,
8035+
channel_monitors,
8036+
}).unwrap()
8037+
};
8038+
assert!(nodes_1_read.is_empty());
8039+
nodes_1_deserialized = nodes_1_deserialized_tmp;
8040+
8041+
assert!(nodes[1].chain_monitor.watch_channel(monitor_a.get_funding_txo().0, monitor_a).is_ok());
8042+
assert!(nodes[1].chain_monitor.watch_channel(monitor_b.get_funding_txo().0, monitor_b).is_ok());
8043+
check_added_monitors!(nodes[1], 2);
8044+
nodes[1].node = &nodes_1_deserialized;
8045+
8046+
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() });
8047+
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
8048+
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()));
8049+
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()));
8050+
8051+
nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() });
8052+
nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
8053+
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()));
8054+
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()));
8055+
8056+
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
8057+
check_added_monitors!(nodes[0], 1);
8058+
pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], 10_000, our_payment_hash, our_payment_secret);
8059+
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], our_payment_preimage);
8060+
}
8061+
79168062
#[test]
79178063
fn test_bump_penalty_txn_on_revoked_commitment() {
79188064
// 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
///
@@ -183,7 +186,7 @@ pub struct ChannelConfig {
183186
/// This should only be set to true for nodes which expect to be online reliably.
184187
///
185188
/// As the node which funds a channel picks this value this will only apply for new outbound
186-
/// channels unless ChannelHandshakeLimits::force_announced_channel_preferences is set.
189+
/// channels unless [`ChannelHandshakeLimits::force_announced_channel_preference`] is set.
187190
///
188191
/// This cannot be changed after the initial channel handshake.
189192
///
@@ -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 a channel is not set to be publicly announced, we reject HTLCs which were set to be
244+
/// forwarded over the channel if this is set to false. This prevents use from taking on
245+
/// HTLC-forwarding risk when we intend to run as a 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)