Skip to content

Commit abdcef3

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 abdcef3

File tree

6 files changed

+113
-13
lines changed

6 files changed

+113
-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_hash(&self) -> Option<ChainHash> {
562+
Some(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_hash(&self) -> Option<ChainHash> {
6991+
Some(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 hash for this `ChannelMessageHandler`.
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_hash(&self) -> Option<ChainHash>;
13031309
}
13041310

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

lightning/src/ln/peer_handler.rs

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
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::Network;
19+
use bitcoin::blockdata::constants::ChainHash;
1820
use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey};
1921

2022
use crate::sign::{KeysManager, NodeSigner, Recipient};
@@ -273,6 +275,13 @@ impl ChannelMessageHandler for ErroringMessageHandler {
273275
features
274276
}
275277

278+
fn get_genesis_hash(&self) -> Option<ChainHash> {
279+
// We don't enforce any chains upon peer connection for `ErroringMessageHandler` and leave it up
280+
// to users of `ErroringMessageHandler` to make decisions on network compatiblility.
281+
// There's not really any way to pull in specific networks here, and hardcoding can cause breakages.
282+
None
283+
}
284+
276285
fn handle_open_channel_v2(&self, their_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
277286
ErroringMessageHandler::push_error(self, their_node_id, msg.temporary_channel_id);
278287
}
@@ -1333,7 +1342,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
13331342
peer.set_their_node_id(their_node_id);
13341343
insert_node_id!();
13351344
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()) };
1345+
let networks = self.message_handler.chan_handler.get_genesis_hash().map(|chain| vec![chain]);
1346+
let resp = msgs::Init { features, networks, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
13371347
self.enqueue_message(peer, &resp);
13381348
peer.awaiting_pong_timer_tick_intervals = 0;
13391349
},
@@ -1345,7 +1355,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
13451355
peer.set_their_node_id(their_node_id);
13461356
insert_node_id!();
13471357
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()) };
1358+
let networks = self.message_handler.chan_handler.get_genesis_hash().map(|chain| vec![chain]);
1359+
let resp = msgs::Init { features, networks, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
13491360
self.enqueue_message(peer, &resp);
13501361
peer.awaiting_pong_timer_tick_intervals = 0;
13511362
},
@@ -1460,6 +1471,15 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
14601471

14611472
// Need an Init as first message
14621473
if let wire::Message::Init(msg) = message {
1474+
if let Some(networks) = &msg.networks {
1475+
if let Some(our_chain) = self.message_handler.chan_handler.get_genesis_hash() {
1476+
if !networks.contains(&our_chain) {
1477+
log_debug!(self.logger, "Peer does not support our chain ({})", our_chain);
1478+
return Err(PeerHandleError { }.into());
1479+
}
1480+
}
1481+
}
1482+
14631483
let our_features = self.init_features(&their_node_id);
14641484
if msg.features.requires_unknown_bits_from(&our_features) {
14651485
log_debug!(self.logger, "Peer requires features unknown to us");
@@ -2459,6 +2479,8 @@ mod tests {
24592479
use crate::ln::msgs::{LightningError, NetAddress};
24602480
use crate::util::test_utils;
24612481

2482+
use bitcoin::Network;
2483+
use bitcoin::blockdata::constants::ChainHash;
24622484
use bitcoin::secp256k1::{PublicKey, SecretKey};
24632485

24642486
use crate::prelude::*;
@@ -2537,7 +2559,7 @@ mod tests {
25372559
};
25382560
cfgs.push(
25392561
PeerManagerCfg{
2540-
chan_handler: test_utils::TestChannelMessageHandler::new(),
2562+
chan_handler: test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet)),
25412563
logger: test_utils::TestLogger::new(),
25422564
routing_handler: test_utils::TestRoutingMessageHandler::new(),
25432565
custom_handler: TestCustomMessageHandler { features },
@@ -2549,7 +2571,7 @@ mod tests {
25492571
cfgs
25502572
}
25512573

2552-
fn create_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
2574+
fn create_feature_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
25532575
let mut cfgs = Vec::new();
25542576
for i in 0..peer_count {
25552577
let node_secret = SecretKey::from_slice(&[42 + i as u8; 32]).unwrap();
@@ -2560,7 +2582,27 @@ mod tests {
25602582
};
25612583
cfgs.push(
25622584
PeerManagerCfg{
2563-
chan_handler: test_utils::TestChannelMessageHandler::new(),
2585+
chan_handler: test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet)),
2586+
logger: test_utils::TestLogger::new(),
2587+
routing_handler: test_utils::TestRoutingMessageHandler::new(),
2588+
custom_handler: TestCustomMessageHandler { features },
2589+
node_signer: test_utils::TestNodeSigner::new(node_secret),
2590+
}
2591+
);
2592+
}
2593+
2594+
cfgs
2595+
}
2596+
2597+
fn create_chain_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
2598+
let mut cfgs = Vec::new();
2599+
for i in 0..peer_count {
2600+
let node_secret = SecretKey::from_slice(&[42 + i as u8; 32]).unwrap();
2601+
let features = InitFeatures::from_le_bytes(vec![0u8; 33]);
2602+
let network = ChainHash::from(&[i as u8; 32][..]);
2603+
cfgs.push(
2604+
PeerManagerCfg{
2605+
chan_handler: test_utils::TestChannelMessageHandler::new(network),
25642606
logger: test_utils::TestLogger::new(),
25652607
routing_handler: test_utils::TestRoutingMessageHandler::new(),
25662608
custom_handler: TestCustomMessageHandler { features },
@@ -2703,9 +2745,9 @@ mod tests {
27032745
}
27042746

27052747
#[test]
2706-
fn test_incompatible_peers() {
2748+
fn test_feature_incompatible_peers() {
27072749
let cfgs = create_peermgr_cfgs(2);
2708-
let incompatible_cfgs = create_incompatible_peermgr_cfgs(2);
2750+
let incompatible_cfgs = create_feature_incompatible_peermgr_cfgs(2);
27092751

27102752
let peers = create_network(2, &cfgs);
27112753
let incompatible_peers = create_network(2, &incompatible_cfgs);
@@ -2738,6 +2780,42 @@ mod tests {
27382780
}
27392781
}
27402782

2783+
#[test]
2784+
fn test_chain_incompatible_peers() {
2785+
let cfgs = create_peermgr_cfgs(2);
2786+
let incompatible_cfgs = create_chain_incompatible_peermgr_cfgs(2);
2787+
2788+
let peers = create_network(2, &cfgs);
2789+
let incompatible_peers = create_network(2, &incompatible_cfgs);
2790+
let peer_pairs = [(&peers[0], &incompatible_peers[0]), (&incompatible_peers[1], &peers[1])];
2791+
for (peer_a, peer_b) in peer_pairs.iter() {
2792+
let id_a = peer_a.node_signer.get_node_id(Recipient::Node).unwrap();
2793+
let mut fd_a = FileDescriptor {
2794+
fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
2795+
disconnect: Arc::new(AtomicBool::new(false)),
2796+
};
2797+
let addr_a = NetAddress::IPv4{addr: [127, 0, 0, 1], port: 1000};
2798+
let mut fd_b = FileDescriptor {
2799+
fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
2800+
disconnect: Arc::new(AtomicBool::new(false)),
2801+
};
2802+
let addr_b = NetAddress::IPv4{addr: [127, 0, 0, 1], port: 1001};
2803+
let initial_data = peer_b.new_outbound_connection(id_a, fd_b.clone(), Some(addr_a.clone())).unwrap();
2804+
peer_a.new_inbound_connection(fd_a.clone(), Some(addr_b.clone())).unwrap();
2805+
assert_eq!(peer_a.read_event(&mut fd_a, &initial_data).unwrap(), false);
2806+
peer_a.process_events();
2807+
2808+
let a_data = fd_a.outbound_data.lock().unwrap().split_off(0);
2809+
assert_eq!(peer_b.read_event(&mut fd_b, &a_data).unwrap(), false);
2810+
2811+
peer_b.process_events();
2812+
let b_data = fd_b.outbound_data.lock().unwrap().split_off(0);
2813+
2814+
// Should fail because of incompatible chains
2815+
assert!(peer_a.read_event(&mut fd_a, &b_data).is_err());
2816+
}
2817+
}
2818+
27412819
#[test]
27422820
fn test_disconnect_peer() {
27432821
// Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and
@@ -2762,8 +2840,8 @@ mod tests {
27622840
// Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and
27632841
// push a message from one peer to another.
27642842
let cfgs = create_peermgr_cfgs(2);
2765-
let a_chan_handler = test_utils::TestChannelMessageHandler::new();
2766-
let b_chan_handler = test_utils::TestChannelMessageHandler::new();
2843+
let a_chan_handler = test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet));
2844+
let b_chan_handler = test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet));
27672845
let mut peers = create_network(2, &cfgs);
27682846
let (fd_a, mut fd_b) = establish_connection(&peers[0], &peers[1]);
27692847
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_hash(&self) -> Option<ChainHash> {
482+
Some(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)