mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-01-18 13:24:36 +01:00
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.
This commit is contained in:
parent
e23102f565
commit
b52b936bdd
@ -838,7 +838,7 @@ impl Drop for BackgroundProcessor {
|
||||
|
||||
#[cfg(all(feature = "std", test))]
|
||||
mod tests {
|
||||
use bitcoin::blockdata::constants::genesis_block;
|
||||
use bitcoin::blockdata::constants::{genesis_block, ChainHash};
|
||||
use bitcoin::blockdata::locktime::PackedLockTime;
|
||||
use bitcoin::blockdata::transaction::{Transaction, TxOut};
|
||||
use bitcoin::network::constants::Network;
|
||||
@ -1146,7 +1146,7 @@ mod tests {
|
||||
let p2p_gossip_sync = Arc::new(P2PGossipSync::new(network_graph.clone(), Some(chain_source.clone()), logger.clone()));
|
||||
let rapid_gossip_sync = Arc::new(RapidGossipSync::new(network_graph.clone(), logger.clone()));
|
||||
let msg_handler = MessageHandler {
|
||||
chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new()),
|
||||
chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet))),
|
||||
route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new()),
|
||||
onion_message_handler: IgnoringMessageHandler{}, custom_message_handler: IgnoringMessageHandler{}
|
||||
};
|
||||
|
@ -474,6 +474,8 @@ mod tests {
|
||||
use lightning::routing::gossip::NodeId;
|
||||
use lightning::events::*;
|
||||
use lightning::util::test_utils::TestNodeSigner;
|
||||
use bitcoin::Network;
|
||||
use bitcoin::blockdata::constants::ChainHash;
|
||||
use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey};
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
@ -556,6 +558,9 @@ mod tests {
|
||||
fn handle_error(&self, _their_node_id: &PublicKey, _msg: &ErrorMessage) {}
|
||||
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
|
||||
fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::empty() }
|
||||
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
|
||||
Some(vec![ChainHash::using_genesis_block(Network::Testnet)])
|
||||
}
|
||||
}
|
||||
impl MessageSendEventsProvider for MsgHandler {
|
||||
fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent> {
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
use bitcoin::blockdata::block::BlockHeader;
|
||||
use bitcoin::blockdata::transaction::Transaction;
|
||||
use bitcoin::blockdata::constants::genesis_block;
|
||||
use bitcoin::blockdata::constants::{genesis_block, ChainHash};
|
||||
use bitcoin::network::constants::Network;
|
||||
|
||||
use bitcoin::hashes::Hash;
|
||||
@ -6987,6 +6987,10 @@ where
|
||||
provided_init_features(&self.default_configuration)
|
||||
}
|
||||
|
||||
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
|
||||
Some(vec![ChainHash::from(&self.genesis_hash[..])])
|
||||
}
|
||||
|
||||
fn handle_tx_add_input(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAddInput) {
|
||||
let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
|
||||
"Dual-funded channels not supported".to_owned(),
|
||||
|
@ -1300,6 +1300,12 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
|
||||
///
|
||||
/// Note that this method is called before [`Self::peer_connected`].
|
||||
fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures;
|
||||
|
||||
/// Gets the genesis hashes for this `ChannelMessageHandler` indicating which chains it supports.
|
||||
///
|
||||
/// If it's `None`, then no particular network chain hash compatibility will be enforced when
|
||||
/// connecting to peers.
|
||||
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>>;
|
||||
}
|
||||
|
||||
/// A trait to describe an object which can receive routing messages.
|
||||
|
@ -15,6 +15,7 @@
|
||||
//! call into the provided message handlers (probably a ChannelManager and P2PGossipSync) with
|
||||
//! messages they should handle, and encoding/sending response messages.
|
||||
|
||||
use bitcoin::blockdata::constants::ChainHash;
|
||||
use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey};
|
||||
|
||||
use crate::sign::{KeysManager, NodeSigner, Recipient};
|
||||
@ -273,6 +274,13 @@ impl ChannelMessageHandler for ErroringMessageHandler {
|
||||
features
|
||||
}
|
||||
|
||||
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
|
||||
// We don't enforce any chains upon peer connection for `ErroringMessageHandler` and leave it up
|
||||
// to users of `ErroringMessageHandler` to make decisions on network compatiblility.
|
||||
// There's not really any way to pull in specific networks here, and hardcoding can cause breakages.
|
||||
None
|
||||
}
|
||||
|
||||
fn handle_open_channel_v2(&self, their_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
|
||||
ErroringMessageHandler::push_error(self, their_node_id, msg.temporary_channel_id);
|
||||
}
|
||||
@ -1333,7 +1341,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
|
||||
peer.set_their_node_id(their_node_id);
|
||||
insert_node_id!();
|
||||
let features = self.init_features(&their_node_id);
|
||||
let resp = msgs::Init { features, networks: None, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
|
||||
let networks = self.message_handler.chan_handler.get_genesis_hashes();
|
||||
let resp = msgs::Init { features, networks, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
|
||||
self.enqueue_message(peer, &resp);
|
||||
peer.awaiting_pong_timer_tick_intervals = 0;
|
||||
},
|
||||
@ -1345,7 +1354,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
|
||||
peer.set_their_node_id(their_node_id);
|
||||
insert_node_id!();
|
||||
let features = self.init_features(&their_node_id);
|
||||
let resp = msgs::Init { features, networks: None, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
|
||||
let networks = self.message_handler.chan_handler.get_genesis_hashes();
|
||||
let resp = msgs::Init { features, networks, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
|
||||
self.enqueue_message(peer, &resp);
|
||||
peer.awaiting_pong_timer_tick_intervals = 0;
|
||||
},
|
||||
@ -1460,6 +1470,25 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
|
||||
|
||||
// Need an Init as first message
|
||||
if let wire::Message::Init(msg) = message {
|
||||
// Check if we have any compatible chains if the `networks` field is specified.
|
||||
if let Some(networks) = &msg.networks {
|
||||
if let Some(our_chains) = self.message_handler.chan_handler.get_genesis_hashes() {
|
||||
let mut have_compatible_chains = false;
|
||||
'our_chains: for our_chain in our_chains.iter() {
|
||||
for their_chain in networks {
|
||||
if our_chain == their_chain {
|
||||
have_compatible_chains = true;
|
||||
break 'our_chains;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !have_compatible_chains {
|
||||
log_debug!(self.logger, "Peer does not support any of our supported chains");
|
||||
return Err(PeerHandleError { }.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let our_features = self.init_features(&their_node_id);
|
||||
if msg.features.requires_unknown_bits_from(&our_features) {
|
||||
log_debug!(self.logger, "Peer requires features unknown to us");
|
||||
@ -2459,6 +2488,8 @@ mod tests {
|
||||
use crate::ln::msgs::{LightningError, NetAddress};
|
||||
use crate::util::test_utils;
|
||||
|
||||
use bitcoin::Network;
|
||||
use bitcoin::blockdata::constants::ChainHash;
|
||||
use bitcoin::secp256k1::{PublicKey, SecretKey};
|
||||
|
||||
use crate::prelude::*;
|
||||
@ -2537,7 +2568,7 @@ mod tests {
|
||||
};
|
||||
cfgs.push(
|
||||
PeerManagerCfg{
|
||||
chan_handler: test_utils::TestChannelMessageHandler::new(),
|
||||
chan_handler: test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet)),
|
||||
logger: test_utils::TestLogger::new(),
|
||||
routing_handler: test_utils::TestRoutingMessageHandler::new(),
|
||||
custom_handler: TestCustomMessageHandler { features },
|
||||
@ -2549,7 +2580,7 @@ mod tests {
|
||||
cfgs
|
||||
}
|
||||
|
||||
fn create_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
|
||||
fn create_feature_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
|
||||
let mut cfgs = Vec::new();
|
||||
for i in 0..peer_count {
|
||||
let node_secret = SecretKey::from_slice(&[42 + i as u8; 32]).unwrap();
|
||||
@ -2560,7 +2591,27 @@ mod tests {
|
||||
};
|
||||
cfgs.push(
|
||||
PeerManagerCfg{
|
||||
chan_handler: test_utils::TestChannelMessageHandler::new(),
|
||||
chan_handler: test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet)),
|
||||
logger: test_utils::TestLogger::new(),
|
||||
routing_handler: test_utils::TestRoutingMessageHandler::new(),
|
||||
custom_handler: TestCustomMessageHandler { features },
|
||||
node_signer: test_utils::TestNodeSigner::new(node_secret),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
cfgs
|
||||
}
|
||||
|
||||
fn create_chain_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
|
||||
let mut cfgs = Vec::new();
|
||||
for i in 0..peer_count {
|
||||
let node_secret = SecretKey::from_slice(&[42 + i as u8; 32]).unwrap();
|
||||
let features = InitFeatures::from_le_bytes(vec![0u8; 33]);
|
||||
let network = ChainHash::from(&[i as u8; 32][..]);
|
||||
cfgs.push(
|
||||
PeerManagerCfg{
|
||||
chan_handler: test_utils::TestChannelMessageHandler::new(network),
|
||||
logger: test_utils::TestLogger::new(),
|
||||
routing_handler: test_utils::TestRoutingMessageHandler::new(),
|
||||
custom_handler: TestCustomMessageHandler { features },
|
||||
@ -2703,9 +2754,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_incompatible_peers() {
|
||||
fn test_feature_incompatible_peers() {
|
||||
let cfgs = create_peermgr_cfgs(2);
|
||||
let incompatible_cfgs = create_incompatible_peermgr_cfgs(2);
|
||||
let incompatible_cfgs = create_feature_incompatible_peermgr_cfgs(2);
|
||||
|
||||
let peers = create_network(2, &cfgs);
|
||||
let incompatible_peers = create_network(2, &incompatible_cfgs);
|
||||
@ -2738,6 +2789,42 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_incompatible_peers() {
|
||||
let cfgs = create_peermgr_cfgs(2);
|
||||
let incompatible_cfgs = create_chain_incompatible_peermgr_cfgs(2);
|
||||
|
||||
let peers = create_network(2, &cfgs);
|
||||
let incompatible_peers = create_network(2, &incompatible_cfgs);
|
||||
let peer_pairs = [(&peers[0], &incompatible_peers[0]), (&incompatible_peers[1], &peers[1])];
|
||||
for (peer_a, peer_b) in peer_pairs.iter() {
|
||||
let id_a = peer_a.node_signer.get_node_id(Recipient::Node).unwrap();
|
||||
let mut fd_a = FileDescriptor {
|
||||
fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
|
||||
disconnect: Arc::new(AtomicBool::new(false)),
|
||||
};
|
||||
let addr_a = NetAddress::IPv4{addr: [127, 0, 0, 1], port: 1000};
|
||||
let mut fd_b = FileDescriptor {
|
||||
fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
|
||||
disconnect: Arc::new(AtomicBool::new(false)),
|
||||
};
|
||||
let addr_b = NetAddress::IPv4{addr: [127, 0, 0, 1], port: 1001};
|
||||
let initial_data = peer_b.new_outbound_connection(id_a, fd_b.clone(), Some(addr_a.clone())).unwrap();
|
||||
peer_a.new_inbound_connection(fd_a.clone(), Some(addr_b.clone())).unwrap();
|
||||
assert_eq!(peer_a.read_event(&mut fd_a, &initial_data).unwrap(), false);
|
||||
peer_a.process_events();
|
||||
|
||||
let a_data = fd_a.outbound_data.lock().unwrap().split_off(0);
|
||||
assert_eq!(peer_b.read_event(&mut fd_b, &a_data).unwrap(), false);
|
||||
|
||||
peer_b.process_events();
|
||||
let b_data = fd_b.outbound_data.lock().unwrap().split_off(0);
|
||||
|
||||
// Should fail because of incompatible chains
|
||||
assert!(peer_a.read_event(&mut fd_a, &b_data).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_disconnect_peer() {
|
||||
// Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and
|
||||
@ -2762,8 +2849,8 @@ mod tests {
|
||||
// Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and
|
||||
// push a message from one peer to another.
|
||||
let cfgs = create_peermgr_cfgs(2);
|
||||
let a_chan_handler = test_utils::TestChannelMessageHandler::new();
|
||||
let b_chan_handler = test_utils::TestChannelMessageHandler::new();
|
||||
let a_chan_handler = test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet));
|
||||
let b_chan_handler = test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet));
|
||||
let mut peers = create_network(2, &cfgs);
|
||||
let (fd_a, mut fd_b) = establish_connection(&peers[0], &peers[1]);
|
||||
assert_eq!(peers[0].peers.read().unwrap().len(), 1);
|
||||
|
@ -32,6 +32,7 @@ use crate::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
|
||||
use crate::util::logger::{Logger, Level, Record};
|
||||
use crate::util::ser::{Readable, ReadableArgs, Writer, Writeable};
|
||||
|
||||
use bitcoin::blockdata::constants::ChainHash;
|
||||
use bitcoin::blockdata::constants::genesis_block;
|
||||
use bitcoin::blockdata::transaction::{Transaction, TxOut};
|
||||
use bitcoin::blockdata::script::{Builder, Script};
|
||||
@ -363,15 +364,17 @@ pub struct TestChannelMessageHandler {
|
||||
expected_recv_msgs: Mutex<Option<Vec<wire::Message<()>>>>,
|
||||
connected_peers: Mutex<HashSet<PublicKey>>,
|
||||
pub message_fetch_counter: AtomicUsize,
|
||||
genesis_hash: ChainHash,
|
||||
}
|
||||
|
||||
impl TestChannelMessageHandler {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(genesis_hash: ChainHash) -> Self {
|
||||
TestChannelMessageHandler {
|
||||
pending_events: Mutex::new(Vec::new()),
|
||||
expected_recv_msgs: Mutex::new(None),
|
||||
connected_peers: Mutex::new(HashSet::new()),
|
||||
message_fetch_counter: AtomicUsize::new(0),
|
||||
genesis_hash,
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,6 +478,10 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
|
||||
channelmanager::provided_init_features(&UserConfig::default())
|
||||
}
|
||||
|
||||
fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
|
||||
Some(vec![self.genesis_hash])
|
||||
}
|
||||
|
||||
fn handle_open_channel_v2(&self, _their_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
|
||||
self.received_msg(wire::Message::OpenChannelV2(msg.clone()));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user