Skip to content

Commit a114dd3

Browse files
committed
Send and handle networks field in Init messages
If the `networks` field is present in a received `Init` message, then we need to make sure our genesis chain hash matches one of those, otherwise we should disconnect the peer. We now also always send our genesis chain hash in `Init` messages to our peers.
1 parent 4fcdb95 commit a114dd3

File tree

6 files changed

+122
-13
lines changed

6 files changed

+122
-13
lines changed

lightning-background-processor/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ impl Drop for BackgroundProcessor {
838838

839839
#[cfg(all(feature = "std", test))]
840840
mod tests {
841-
use bitcoin::blockdata::constants::genesis_block;
841+
use bitcoin::blockdata::constants::{genesis_block, ChainHash};
842842
use bitcoin::blockdata::locktime::PackedLockTime;
843843
use bitcoin::blockdata::transaction::{Transaction, TxOut};
844844
use bitcoin::network::constants::Network;
@@ -1146,7 +1146,7 @@ mod tests {
11461146
let p2p_gossip_sync = Arc::new(P2PGossipSync::new(network_graph.clone(), Some(chain_source.clone()), logger.clone()));
11471147
let rapid_gossip_sync = Arc::new(RapidGossipSync::new(network_graph.clone(), logger.clone()));
11481148
let msg_handler = MessageHandler {
1149-
chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new()),
1149+
chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet))),
11501150
route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new()),
11511151
onion_message_handler: IgnoringMessageHandler{}, custom_message_handler: IgnoringMessageHandler{}
11521152
};

lightning-net-tokio/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,8 @@ mod tests {
474474
use lightning::routing::gossip::NodeId;
475475
use lightning::events::*;
476476
use lightning::util::test_utils::TestNodeSigner;
477+
use bitcoin::Network;
478+
use bitcoin::blockdata::constants::ChainHash;
477479
use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey};
478480

479481
use tokio::sync::mpsc;
@@ -556,6 +558,9 @@ mod tests {
556558
fn handle_error(&self, _their_node_id: &PublicKey, _msg: &ErrorMessage) {}
557559
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
558560
fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::empty() }
561+
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
562+
Some(vec![ChainHash::using_genesis_block(Network::Testnet)])
563+
}
559564
}
560565
impl MessageSendEventsProvider for MsgHandler {
561566
fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent> {

lightning/src/ln/channelmanager.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
2020
use bitcoin::blockdata::block::BlockHeader;
2121
use bitcoin::blockdata::transaction::Transaction;
22-
use bitcoin::blockdata::constants::genesis_block;
22+
use bitcoin::blockdata::constants::{genesis_block, ChainHash};
2323
use bitcoin::network::constants::Network;
2424

2525
use bitcoin::hashes::Hash;
@@ -6987,6 +6987,10 @@ where
69876987
provided_init_features(&self.default_configuration)
69886988
}
69896989

6990+
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
6991+
Some(vec![ChainHash::from(&self.genesis_hash[..])])
6992+
}
6993+
69906994
fn handle_tx_add_input(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAddInput) {
69916995
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
69926996
"Dual-funded channels not supported".to_owned(),

lightning/src/ln/msgs.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,12 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
13001300
///
13011301
/// Note that this method is called before [`Self::peer_connected`].
13021302
fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures;
1303+
1304+
/// Gets the genesis hashes for this `ChannelMessageHandler` indicating which chains it supports.
1305+
///
1306+
/// If it's `None`, then no particular network chain hash compatibility will be enforced when
1307+
/// connecting to peers.
1308+
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>>;
13031309
}
13041310

13051311
/// A trait to describe an object which can receive routing messages.

lightning/src/ln/peer_handler.rs

Lines changed: 96 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//! call into the provided message handlers (probably a ChannelManager and P2PGossipSync) with
1616
//! messages they should handle, and encoding/sending response messages.
1717
18+
use bitcoin::blockdata::constants::ChainHash;
1819
use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey};
1920

2021
use crate::sign::{KeysManager, NodeSigner, Recipient};
@@ -273,6 +274,13 @@ impl ChannelMessageHandler for ErroringMessageHandler {
273274
features
274275
}
275276

277+
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
278+
// We don't enforce any chains upon peer connection for `ErroringMessageHandler` and leave it up
279+
// to users of `ErroringMessageHandler` to make decisions on network compatiblility.
280+
// There's not really any way to pull in specific networks here, and hardcoding can cause breakages.
281+
None
282+
}
283+
276284
fn handle_open_channel_v2(&self, their_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
277285
ErroringMessageHandler::push_error(self, their_node_id, msg.temporary_channel_id);
278286
}
@@ -1333,7 +1341,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
13331341
peer.set_their_node_id(their_node_id);
13341342
insert_node_id!();
13351343
let features = self.init_features(&their_node_id);
1336-
let resp = msgs::Init { features, networks: None, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
1344+
let networks = self.message_handler.chan_handler.get_genesis_hashes();
1345+
let resp = msgs::Init { features, networks, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
13371346
self.enqueue_message(peer, &resp);
13381347
peer.awaiting_pong_timer_tick_intervals = 0;
13391348
},
@@ -1345,7 +1354,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
13451354
peer.set_their_node_id(their_node_id);
13461355
insert_node_id!();
13471356
let features = self.init_features(&their_node_id);
1348-
let resp = msgs::Init { features, networks: None, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
1357+
let networks = self.message_handler.chan_handler.get_genesis_hashes();
1358+
let resp = msgs::Init { features, networks, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
13491359
self.enqueue_message(peer, &resp);
13501360
peer.awaiting_pong_timer_tick_intervals = 0;
13511361
},
@@ -1460,6 +1470,25 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
14601470

14611471
// Need an Init as first message
14621472
if let wire::Message::Init(msg) = message {
1473+
// Check if we have any compatible chains if the `networks` field is specified.
1474+
if let Some(networks) = &msg.networks {
1475+
if let Some(our_chains) = self.message_handler.chan_handler.get_genesis_hashes() {
1476+
let mut have_compatible_chains = false;
1477+
'our_chains: for our_chain in our_chains.iter() {
1478+
for their_chain in networks {
1479+
if our_chain == their_chain {
1480+
have_compatible_chains = true;
1481+
break 'our_chains;
1482+
}
1483+
}
1484+
}
1485+
if !have_compatible_chains {
1486+
log_debug!(self.logger, "Peer does not support any of our supported chains");
1487+
return Err(PeerHandleError { }.into());
1488+
}
1489+
}
1490+
}
1491+
14631492
let our_features = self.init_features(&their_node_id);
14641493
if msg.features.requires_unknown_bits_from(&our_features) {
14651494
log_debug!(self.logger, "Peer requires features unknown to us");
@@ -2459,6 +2488,8 @@ mod tests {
24592488
use crate::ln::msgs::{LightningError, NetAddress};
24602489
use crate::util::test_utils;
24612490

2491+
use bitcoin::Network;
2492+
use bitcoin::blockdata::constants::ChainHash;
24622493
use bitcoin::secp256k1::{PublicKey, SecretKey};
24632494

24642495
use crate::prelude::*;
@@ -2537,7 +2568,7 @@ mod tests {
25372568
};
25382569
cfgs.push(
25392570
PeerManagerCfg{
2540-
chan_handler: test_utils::TestChannelMessageHandler::new(),
2571+
chan_handler: test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet)),
25412572
logger: test_utils::TestLogger::new(),
25422573
routing_handler: test_utils::TestRoutingMessageHandler::new(),
25432574
custom_handler: TestCustomMessageHandler { features },
@@ -2549,7 +2580,7 @@ mod tests {
25492580
cfgs
25502581
}
25512582

2552-
fn create_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
2583+
fn create_feature_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
25532584
let mut cfgs = Vec::new();
25542585
for i in 0..peer_count {
25552586
let node_secret = SecretKey::from_slice(&[42 + i as u8; 32]).unwrap();
@@ -2560,7 +2591,27 @@ mod tests {
25602591
};
25612592
cfgs.push(
25622593
PeerManagerCfg{
2563-
chan_handler: test_utils::TestChannelMessageHandler::new(),
2594+
chan_handler: test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet)),
2595+
logger: test_utils::TestLogger::new(),
2596+
routing_handler: test_utils::TestRoutingMessageHandler::new(),
2597+
custom_handler: TestCustomMessageHandler { features },
2598+
node_signer: test_utils::TestNodeSigner::new(node_secret),
2599+
}
2600+
);
2601+
}
2602+
2603+
cfgs
2604+
}
2605+
2606+
fn create_chain_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
2607+
let mut cfgs = Vec::new();
2608+
for i in 0..peer_count {
2609+
let node_secret = SecretKey::from_slice(&[42 + i as u8; 32]).unwrap();
2610+
let features = InitFeatures::from_le_bytes(vec![0u8; 33]);
2611+
let network = ChainHash::from(&[i as u8; 32][..]);
2612+
cfgs.push(
2613+
PeerManagerCfg{
2614+
chan_handler: test_utils::TestChannelMessageHandler::new(network),
25642615
logger: test_utils::TestLogger::new(),
25652616
routing_handler: test_utils::TestRoutingMessageHandler::new(),
25662617
custom_handler: TestCustomMessageHandler { features },
@@ -2703,9 +2754,9 @@ mod tests {
27032754
}
27042755

27052756
#[test]
2706-
fn test_incompatible_peers() {
2757+
fn test_feature_incompatible_peers() {
27072758
let cfgs = create_peermgr_cfgs(2);
2708-
let incompatible_cfgs = create_incompatible_peermgr_cfgs(2);
2759+
let incompatible_cfgs = create_feature_incompatible_peermgr_cfgs(2);
27092760

27102761
let peers = create_network(2, &cfgs);
27112762
let incompatible_peers = create_network(2, &incompatible_cfgs);
@@ -2738,6 +2789,42 @@ mod tests {
27382789
}
27392790
}
27402791

2792+
#[test]
2793+
fn test_chain_incompatible_peers() {
2794+
let cfgs = create_peermgr_cfgs(2);
2795+
let incompatible_cfgs = create_chain_incompatible_peermgr_cfgs(2);
2796+
2797+
let peers = create_network(2, &cfgs);
2798+
let incompatible_peers = create_network(2, &incompatible_cfgs);
2799+
let peer_pairs = [(&peers[0], &incompatible_peers[0]), (&incompatible_peers[1], &peers[1])];
2800+
for (peer_a, peer_b) in peer_pairs.iter() {
2801+
let id_a = peer_a.node_signer.get_node_id(Recipient::Node).unwrap();
2802+
let mut fd_a = FileDescriptor {
2803+
fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
2804+
disconnect: Arc::new(AtomicBool::new(false)),
2805+
};
2806+
let addr_a = NetAddress::IPv4{addr: [127, 0, 0, 1], port: 1000};
2807+
let mut fd_b = FileDescriptor {
2808+
fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
2809+
disconnect: Arc::new(AtomicBool::new(false)),
2810+
};
2811+
let addr_b = NetAddress::IPv4{addr: [127, 0, 0, 1], port: 1001};
2812+
let initial_data = peer_b.new_outbound_connection(id_a, fd_b.clone(), Some(addr_a.clone())).unwrap();
2813+
peer_a.new_inbound_connection(fd_a.clone(), Some(addr_b.clone())).unwrap();
2814+
assert_eq!(peer_a.read_event(&mut fd_a, &initial_data).unwrap(), false);
2815+
peer_a.process_events();
2816+
2817+
let a_data = fd_a.outbound_data.lock().unwrap().split_off(0);
2818+
assert_eq!(peer_b.read_event(&mut fd_b, &a_data).unwrap(), false);
2819+
2820+
peer_b.process_events();
2821+
let b_data = fd_b.outbound_data.lock().unwrap().split_off(0);
2822+
2823+
// Should fail because of incompatible chains
2824+
assert!(peer_a.read_event(&mut fd_a, &b_data).is_err());
2825+
}
2826+
}
2827+
27412828
#[test]
27422829
fn test_disconnect_peer() {
27432830
// Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and
@@ -2762,8 +2849,8 @@ mod tests {
27622849
// Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and
27632850
// push a message from one peer to another.
27642851
let cfgs = create_peermgr_cfgs(2);
2765-
let a_chan_handler = test_utils::TestChannelMessageHandler::new();
2766-
let b_chan_handler = test_utils::TestChannelMessageHandler::new();
2852+
let a_chan_handler = test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet));
2853+
let b_chan_handler = test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet));
27672854
let mut peers = create_network(2, &cfgs);
27682855
let (fd_a, mut fd_b) = establish_connection(&peers[0], &peers[1]);
27692856
assert_eq!(peers[0].peers.read().unwrap().len(), 1);

lightning/src/util/test_utils.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use crate::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
3232
use crate::util::logger::{Logger, Level, Record};
3333
use crate::util::ser::{Readable, ReadableArgs, Writer, Writeable};
3434

35+
use bitcoin::blockdata::constants::ChainHash;
3536
use bitcoin::blockdata::constants::genesis_block;
3637
use bitcoin::blockdata::transaction::{Transaction, TxOut};
3738
use bitcoin::blockdata::script::{Builder, Script};
@@ -363,15 +364,17 @@ pub struct TestChannelMessageHandler {
363364
expected_recv_msgs: Mutex<Option<Vec<wire::Message<()>>>>,
364365
connected_peers: Mutex<HashSet<PublicKey>>,
365366
pub message_fetch_counter: AtomicUsize,
367+
genesis_hash: ChainHash,
366368
}
367369

368370
impl TestChannelMessageHandler {
369-
pub fn new() -> Self {
371+
pub fn new(genesis_hash: ChainHash) -> Self {
370372
TestChannelMessageHandler {
371373
pending_events: Mutex::new(Vec::new()),
372374
expected_recv_msgs: Mutex::new(None),
373375
connected_peers: Mutex::new(HashSet::new()),
374376
message_fetch_counter: AtomicUsize::new(0),
377+
genesis_hash,
375378
}
376379
}
377380

@@ -475,6 +478,10 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
475478
channelmanager::provided_init_features(&UserConfig::default())
476479
}
477480

481+
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
482+
Some(vec![self.genesis_hash])
483+
}
484+
478485
fn handle_open_channel_v2(&self, _their_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
479486
self.received_msg(wire::Message::OpenChannelV2(msg.clone()));
480487
}

0 commit comments

Comments
 (0)