Skip to content

Commit fdacec8

Browse files
authored
Merge pull request #4340 from Thrishalmadasu/issue-1672-dont-forward-bit
Set dont_forward on private channel updates and add tests
2 parents 8679d8d + 5e32d69 commit fdacec8

File tree

3 files changed

+201
-1
lines changed

3 files changed

+201
-1
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5088,7 +5088,7 @@ impl<
50885088
chain_hash: self.chain_hash,
50895089
short_channel_id,
50905090
timestamp: chan.context.get_update_time_counter(),
5091-
message_flags: 1, // Only must_be_one
5091+
message_flags: 1 | if !chan.context.should_announce() { 1 << 1 } else { 0 }, // must_be_one + dont_forward
50925092
channel_flags: (!were_node_one) as u8 | ((!enabled as u8) << 1),
50935093
cltv_expiry_delta: chan.context.get_cltv_expiry_delta(),
50945094
htlc_minimum_msat: chan.context.get_counterparty_htlc_minimum_msat(),
@@ -12274,6 +12274,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1227412274
Some((cp_id, chan_id)) => (cp_id.clone(), chan_id.clone()),
1227512275
None => {
1227612276
// It's not a local channel
12277+
if msg.contents.message_flags & (1 << 1) != 0 {
12278+
log_debug!(self.logger, "Received channel_update for unknown channel {} with dont_forward set. You may wish to check if an incorrect tx_index was passed to chain::Confirm::transactions_confirmed.", msg.contents.short_channel_id);
12279+
}
1227712280
return Ok(NotifyOption::SkipPersistNoEvents)
1227812281
}
1227912282
};

lightning/src/ln/priv_short_conf_tests.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,3 +1520,133 @@ fn test_0conf_ann_sigs_racing_conf() {
15201520
let as_announcement = nodes[0].node.get_and_clear_pending_msg_events();
15211521
assert_eq!(as_announcement.len(), 1);
15221522
}
1523+
1524+
#[test]
1525+
fn test_channel_update_dont_forward_flag() {
1526+
// Test that the `dont_forward` bit (bit 1 of message_flags) is set correctly:
1527+
// - For private channels: message_flags should have bit 1 set (value 3 = must_be_one + dont_forward)
1528+
// - For public channels: message_flags should NOT have bit 1 set (value 1 = must_be_one only)
1529+
let chanmon_cfgs = create_chanmon_cfgs(3);
1530+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
1531+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
1532+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
1533+
let node_b_id = nodes[1].node.get_our_node_id();
1534+
let node_c_id = nodes[2].node.get_our_node_id();
1535+
1536+
// Create a public (announced) channel between nodes[0] and nodes[1]
1537+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000);
1538+
1539+
// Create a private (unannounced) channel between nodes[1] and nodes[2]
1540+
create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000);
1541+
1542+
// Get the channel details for both channels
1543+
let public_channel = nodes[0]
1544+
.node
1545+
.list_channels()
1546+
.into_iter()
1547+
.find(|c| c.counterparty.node_id == node_b_id)
1548+
.unwrap();
1549+
let private_channel = nodes[1]
1550+
.node
1551+
.list_channels()
1552+
.into_iter()
1553+
.find(|c| c.counterparty.node_id == node_c_id)
1554+
.unwrap();
1555+
1556+
// Verify is_announced correctly reflects the channel type
1557+
assert!(public_channel.is_announced, "Public channel should have is_announced = true");
1558+
assert!(!private_channel.is_announced, "Private channel should have is_announced = false");
1559+
1560+
// Trigger channel_update by changing config on the public channel
1561+
let mut new_config = public_channel.config.unwrap();
1562+
new_config.forwarding_fee_base_msat += 10;
1563+
nodes[0]
1564+
.node
1565+
.update_channel_config(&node_b_id, &[public_channel.channel_id], &new_config)
1566+
.unwrap();
1567+
1568+
// Get the channel_update for the public channel and verify dont_forward is NOT set
1569+
let events = nodes[0].node.get_and_clear_pending_msg_events();
1570+
let public_channel_update = events
1571+
.iter()
1572+
.find_map(|e| {
1573+
if let MessageSendEvent::BroadcastChannelUpdate { ref msg, .. } = e {
1574+
Some(msg.clone())
1575+
} else {
1576+
None
1577+
}
1578+
})
1579+
.expect("Expected BroadcastChannelUpdate for public channel");
1580+
// message_flags should be 1 (only must_be_one bit set, dont_forward NOT set)
1581+
assert_eq!(
1582+
public_channel_update.contents.message_flags & (1 << 1),
1583+
0,
1584+
"Public channel update should NOT have dont_forward bit set"
1585+
);
1586+
assert_eq!(
1587+
public_channel_update.contents.message_flags & 1,
1588+
1,
1589+
"Public channel update should have must_be_one bit set"
1590+
);
1591+
1592+
// Trigger channel_update by changing config on the private channel
1593+
let mut new_config = private_channel.config.unwrap();
1594+
new_config.forwarding_fee_base_msat += 10;
1595+
nodes[1]
1596+
.node
1597+
.update_channel_config(&node_c_id, &[private_channel.channel_id], &new_config)
1598+
.unwrap();
1599+
1600+
// Get the channel_update for the private channel and verify dont_forward IS set
1601+
let private_channel_update =
1602+
get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, node_c_id);
1603+
// message_flags should have dont_forward bit set
1604+
assert_ne!(
1605+
private_channel_update.contents.message_flags & (1 << 1),
1606+
0,
1607+
"Private channel update should have dont_forward bit set"
1608+
);
1609+
assert_eq!(
1610+
private_channel_update.contents.message_flags & 1,
1611+
1,
1612+
"Private channel update should have must_be_one bit set"
1613+
);
1614+
}
1615+
1616+
#[test]
1617+
fn test_unknown_channel_update_with_dont_forward_logs_debug() {
1618+
use bitcoin::constants::ChainHash;
1619+
use bitcoin::secp256k1::ecdsa::Signature;
1620+
use bitcoin::secp256k1::ffi::Signature as FFISignature;
1621+
use bitcoin::Network;
1622+
1623+
let chanmon_cfgs = create_chanmon_cfgs(2);
1624+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1625+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
1626+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1627+
1628+
let unknown_scid = 42;
1629+
let msg = msgs::ChannelUpdate {
1630+
signature: Signature::from(unsafe { FFISignature::new() }),
1631+
contents: msgs::UnsignedChannelUpdate {
1632+
chain_hash: ChainHash::using_genesis_block(Network::Testnet),
1633+
short_channel_id: unknown_scid,
1634+
timestamp: 0,
1635+
message_flags: 1 | (1 << 1), // must_be_one + dont_forward
1636+
channel_flags: 0,
1637+
cltv_expiry_delta: 0,
1638+
htlc_minimum_msat: 0,
1639+
htlc_maximum_msat: msgs::MAX_VALUE_MSAT,
1640+
fee_base_msat: 0,
1641+
fee_proportional_millionths: 0,
1642+
excess_data: Vec::new(),
1643+
},
1644+
};
1645+
1646+
nodes[0].node.handle_channel_update(nodes[1].node.get_our_node_id(), &msg);
1647+
nodes[0].logger.assert_log_contains(
1648+
"lightning::ln::channelmanager",
1649+
"Received channel_update for unknown channel",
1650+
1,
1651+
);
1652+
}

lightning/src/routing/gossip.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,14 @@ impl<G: Deref<Target = NetworkGraph<L>>, U: UtxoLookup, L: Logger> RoutingMessag
551551
fn handle_channel_update(
552552
&self, _their_node_id: Option<PublicKey>, msg: &msgs::ChannelUpdate,
553553
) -> Result<Option<(NodeId, NodeId)>, LightningError> {
554+
// Ignore channel updates with dont_forward bit set - these are for private channels
555+
// and shouldn't be gossiped or stored in the network graph
556+
if msg.contents.message_flags & (1 << 1) != 0 {
557+
return Err(LightningError {
558+
err: "Ignoring channel_update with dont_forward bit set".to_owned(),
559+
action: ErrorAction::IgnoreAndLog(Level::Debug),
560+
});
561+
}
554562
match self.network_graph.update_channel(msg) {
555563
Ok(nodes) if msg.contents.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY => Ok(nodes),
556564
Ok(_) => Ok(None),
@@ -3294,6 +3302,65 @@ pub(crate) mod tests {
32943302
};
32953303
}
32963304

3305+
#[test]
3306+
fn handling_channel_update_with_dont_forward_flag() {
3307+
// Test that channel updates with the dont_forward bit set are rejected
3308+
let secp_ctx = Secp256k1::new();
3309+
let logger = test_utils::TestLogger::new();
3310+
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
3311+
let network_graph = NetworkGraph::new(Network::Testnet, &logger);
3312+
let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
3313+
3314+
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
3315+
let node_1_pubkey = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
3316+
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
3317+
3318+
// First announce a channel so we have something to update
3319+
let good_script = get_channel_script(&secp_ctx);
3320+
*chain_source.utxo_ret.lock().unwrap() = UtxoResult::Sync(Ok(TxOut {
3321+
value: Amount::from_sat(1000_000),
3322+
script_pubkey: good_script.clone(),
3323+
}));
3324+
3325+
let valid_channel_announcement =
3326+
get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
3327+
gossip_sync
3328+
.handle_channel_announcement(Some(node_1_pubkey), &valid_channel_announcement)
3329+
.unwrap();
3330+
3331+
// Create a channel update with dont_forward bit set (bit 1 of message_flags)
3332+
let dont_forward_update = get_signed_channel_update(
3333+
|unsigned_channel_update| {
3334+
unsigned_channel_update.message_flags = 1 | (1 << 1); // must_be_one + dont_forward
3335+
},
3336+
node_1_privkey,
3337+
&secp_ctx,
3338+
);
3339+
3340+
// The update should be rejected because dont_forward is set
3341+
match gossip_sync.handle_channel_update(Some(node_1_pubkey), &dont_forward_update) {
3342+
Ok(_) => panic!("Expected channel update with dont_forward to be rejected"),
3343+
Err(e) => {
3344+
assert_eq!(e.err, "Ignoring channel_update with dont_forward bit set");
3345+
match e.action {
3346+
crate::ln::msgs::ErrorAction::IgnoreAndLog(level) => {
3347+
assert_eq!(level, crate::util::logger::Level::Debug)
3348+
},
3349+
_ => panic!("Expected IgnoreAndLog action"),
3350+
}
3351+
},
3352+
};
3353+
3354+
// Verify the update was not applied to the network graph
3355+
let channels = network_graph.read_only();
3356+
let channel =
3357+
channels.channels().get(&valid_channel_announcement.contents.short_channel_id).unwrap();
3358+
assert!(
3359+
channel.one_to_two.is_none(),
3360+
"Channel update with dont_forward should not be stored in network graph"
3361+
);
3362+
}
3363+
32973364
#[test]
32983365
fn handling_network_update() {
32993366
let logger = test_utils::TestLogger::new();

0 commit comments

Comments
 (0)