mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-03-10 05:33:40 +01:00
Merge pull request #2204 from jkczyz/2023-04-custom-feature-bits
Support for custom feature bits
This commit is contained in:
commit
498f233145
5 changed files with 326 additions and 34 deletions
File diff suppressed because one or more lines are too long
|
@ -20,6 +20,7 @@
|
|||
//! # use bitcoin::secp256k1::PublicKey;
|
||||
//! # use lightning::io;
|
||||
//! # use lightning::ln::msgs::{DecodeError, LightningError};
|
||||
//! # use lightning::ln::features::{InitFeatures, NodeFeatures};
|
||||
//! use lightning::ln::peer_handler::CustomMessageHandler;
|
||||
//! use lightning::ln::wire::{CustomMessageReader, self};
|
||||
//! use lightning::util::ser::Writeable;
|
||||
|
@ -66,6 +67,12 @@
|
|||
//! # fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! # fn provided_node_features(&self) -> NodeFeatures {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! # fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(Debug)]
|
||||
|
@ -106,6 +113,12 @@
|
|||
//! # fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! # fn provided_node_features(&self) -> NodeFeatures {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! # fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(Debug)]
|
||||
|
@ -146,6 +159,12 @@
|
|||
//! # fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! # fn provided_node_features(&self) -> NodeFeatures {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! # fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! }
|
||||
//!
|
||||
//! # fn main() {
|
||||
|
@ -268,6 +287,22 @@ macro_rules! composite_custom_message_handler {
|
|||
)*
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn provided_node_features(&self) -> $crate::lightning::ln::features::NodeFeatures {
|
||||
$crate::lightning::ln::features::NodeFeatures::empty()
|
||||
$(
|
||||
| self.$field.provided_node_features()
|
||||
)*
|
||||
}
|
||||
|
||||
fn provided_init_features(
|
||||
&self, their_node_id: &$crate::bitcoin::secp256k1::PublicKey
|
||||
) -> $crate::lightning::ln::features::InitFeatures {
|
||||
$crate::lightning::ln::features::InitFeatures::empty()
|
||||
$(
|
||||
| self.$field.provided_init_features(their_node_id)
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::lightning::ln::wire::CustomMessageReader for $handler {
|
||||
|
|
|
@ -422,8 +422,10 @@ pub struct Features<T: sealed::Context> {
|
|||
mark: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl <T: sealed::Context> Features<T> {
|
||||
pub(crate) fn or(mut self, o: Self) -> Self {
|
||||
impl<T: sealed::Context> core::ops::BitOr for Features<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(mut self, o: Self) -> Self {
|
||||
let total_feature_len = cmp::max(self.flags.len(), o.flags.len());
|
||||
self.flags.resize(total_feature_len, 0u8);
|
||||
for (byte, o_byte) in self.flags.iter_mut().zip(o.flags.iter()) {
|
||||
|
@ -695,6 +697,25 @@ impl<T: sealed::Context> Features<T> {
|
|||
self.flags.iter().any(|&byte| (byte & 0b10_10_10_10) != 0)
|
||||
}
|
||||
|
||||
/// Returns true if this `Features` object contains required features unknown by `other`.
|
||||
pub fn requires_unknown_bits_from(&self, other: &Features<T>) -> bool {
|
||||
// Bitwise AND-ing with all even bits set except for known features will select required
|
||||
// unknown features.
|
||||
self.flags.iter().enumerate().any(|(i, &byte)| {
|
||||
const REQUIRED_FEATURES: u8 = 0b01_01_01_01;
|
||||
const OPTIONAL_FEATURES: u8 = 0b10_10_10_10;
|
||||
let unknown_features = if i < other.flags.len() {
|
||||
// Form a mask similar to !T::KNOWN_FEATURE_MASK only for `other`
|
||||
!(other.flags[i]
|
||||
| ((other.flags[i] >> 1) & REQUIRED_FEATURES)
|
||||
| ((other.flags[i] << 1) & OPTIONAL_FEATURES))
|
||||
} else {
|
||||
0b11_11_11_11
|
||||
};
|
||||
(byte & (REQUIRED_FEATURES & unknown_features)) != 0
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns true if this `Features` object contains unknown feature flags which are set as
|
||||
/// "required".
|
||||
pub fn requires_unknown_bits(&self) -> bool {
|
||||
|
@ -743,6 +764,50 @@ impl<T: sealed::Context> Features<T> {
|
|||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Sets a required custom feature bit. Errors if `bit` is outside the custom range as defined
|
||||
/// by [bLIP 2] or if it is a known `T` feature.
|
||||
///
|
||||
/// Note: Required bits are even. If an odd bit is given, then the corresponding even bit will
|
||||
/// be set instead (i.e., `bit - 1`).
|
||||
///
|
||||
/// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits
|
||||
pub fn set_required_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
|
||||
self.set_custom_bit(bit - (bit % 2))
|
||||
}
|
||||
|
||||
/// Sets an optional custom feature bit. Errors if `bit` is outside the custom range as defined
|
||||
/// by [bLIP 2] or if it is a known `T` feature.
|
||||
///
|
||||
/// Note: Optional bits are odd. If an even bit is given, then the corresponding odd bit will be
|
||||
/// set instead (i.e., `bit + 1`).
|
||||
///
|
||||
/// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits
|
||||
pub fn set_optional_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
|
||||
self.set_custom_bit(bit + (1 - (bit % 2)))
|
||||
}
|
||||
|
||||
fn set_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
|
||||
if bit < 256 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let byte_offset = bit / 8;
|
||||
let mask = 1 << (bit - 8 * byte_offset);
|
||||
if byte_offset < T::KNOWN_FEATURE_MASK.len() {
|
||||
if (T::KNOWN_FEATURE_MASK[byte_offset] & mask) != 0 {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
if self.flags.len() <= byte_offset {
|
||||
self.flags.resize(byte_offset + 1, 0u8);
|
||||
}
|
||||
|
||||
self.flags[byte_offset] |= mask;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: sealed::UpfrontShutdownScript> Features<T> {
|
||||
|
@ -869,6 +934,43 @@ mod tests {
|
|||
assert!(features.supports_unknown_bits());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requires_unknown_bits_from() {
|
||||
let mut features1 = InitFeatures::empty();
|
||||
let mut features2 = InitFeatures::empty();
|
||||
assert!(!features1.requires_unknown_bits_from(&features2));
|
||||
assert!(!features2.requires_unknown_bits_from(&features1));
|
||||
|
||||
features1.set_data_loss_protect_required();
|
||||
assert!(features1.requires_unknown_bits_from(&features2));
|
||||
assert!(!features2.requires_unknown_bits_from(&features1));
|
||||
|
||||
features2.set_data_loss_protect_optional();
|
||||
assert!(!features1.requires_unknown_bits_from(&features2));
|
||||
assert!(!features2.requires_unknown_bits_from(&features1));
|
||||
|
||||
features2.set_gossip_queries_required();
|
||||
assert!(!features1.requires_unknown_bits_from(&features2));
|
||||
assert!(features2.requires_unknown_bits_from(&features1));
|
||||
|
||||
features1.set_gossip_queries_optional();
|
||||
assert!(!features1.requires_unknown_bits_from(&features2));
|
||||
assert!(!features2.requires_unknown_bits_from(&features1));
|
||||
|
||||
features1.set_variable_length_onion_required();
|
||||
assert!(features1.requires_unknown_bits_from(&features2));
|
||||
assert!(!features2.requires_unknown_bits_from(&features1));
|
||||
|
||||
features2.set_variable_length_onion_optional();
|
||||
assert!(!features1.requires_unknown_bits_from(&features2));
|
||||
assert!(!features2.requires_unknown_bits_from(&features1));
|
||||
|
||||
features1.set_basic_mpp_required();
|
||||
features2.set_wumbo_required();
|
||||
assert!(features1.requires_unknown_bits_from(&features2));
|
||||
assert!(features2.requires_unknown_bits_from(&features1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_to_context_with_relevant_flags() {
|
||||
let mut init_features = InitFeatures::empty();
|
||||
|
@ -881,12 +983,12 @@ mod tests {
|
|||
init_features.set_payment_secret_required();
|
||||
init_features.set_basic_mpp_optional();
|
||||
init_features.set_wumbo_optional();
|
||||
init_features.set_anchors_zero_fee_htlc_tx_optional();
|
||||
init_features.set_shutdown_any_segwit_optional();
|
||||
init_features.set_onion_messages_optional();
|
||||
init_features.set_channel_type_optional();
|
||||
init_features.set_scid_privacy_optional();
|
||||
init_features.set_zero_conf_optional();
|
||||
init_features.set_anchors_zero_fee_htlc_tx_optional();
|
||||
|
||||
assert!(init_features.initial_routing_sync());
|
||||
assert!(!init_features.supports_upfront_shutdown_script());
|
||||
|
@ -897,7 +999,7 @@ mod tests {
|
|||
// Check that the flags are as expected:
|
||||
// - option_data_loss_protect (req)
|
||||
// - var_onion_optin (req) | static_remote_key (req) | payment_secret(req)
|
||||
// - basic_mpp | wumbo
|
||||
// - basic_mpp | wumbo | anchors_zero_fee_htlc_tx
|
||||
// - opt_shutdown_anysegwit
|
||||
// - onion_messages
|
||||
// - option_channel_type | option_scid_alias
|
||||
|
@ -945,6 +1047,36 @@ mod tests {
|
|||
assert!(features.supports_payment_secret());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_custom_bits() {
|
||||
let mut features = InvoiceFeatures::empty();
|
||||
features.set_variable_length_onion_optional();
|
||||
assert_eq!(features.flags[1], 0b00000010);
|
||||
|
||||
assert!(features.set_optional_custom_bit(255).is_err());
|
||||
assert!(features.set_required_custom_bit(256).is_ok());
|
||||
assert!(features.set_required_custom_bit(258).is_ok());
|
||||
assert_eq!(features.flags[31], 0b00000000);
|
||||
assert_eq!(features.flags[32], 0b00000101);
|
||||
|
||||
let known_bit = <sealed::InvoiceContext as sealed::PaymentSecret>::EVEN_BIT;
|
||||
let byte_offset = <sealed::InvoiceContext as sealed::PaymentSecret>::BYTE_OFFSET;
|
||||
assert_eq!(byte_offset, 1);
|
||||
assert_eq!(features.flags[byte_offset], 0b00000010);
|
||||
assert!(features.set_required_custom_bit(known_bit).is_err());
|
||||
assert_eq!(features.flags[byte_offset], 0b00000010);
|
||||
|
||||
let mut features = InvoiceFeatures::empty();
|
||||
assert!(features.set_optional_custom_bit(256).is_ok());
|
||||
assert!(features.set_optional_custom_bit(259).is_ok());
|
||||
assert_eq!(features.flags[32], 0b00001010);
|
||||
|
||||
let mut features = InvoiceFeatures::empty();
|
||||
assert!(features.set_required_custom_bit(257).is_ok());
|
||||
assert!(features.set_required_custom_bit(258).is_ok());
|
||||
assert_eq!(features.flags[32], 0b00000101);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encodes_features_without_length() {
|
||||
let features = OfferFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]);
|
||||
|
|
|
@ -1738,7 +1738,7 @@ impl Readable for Init {
|
|||
(3, remote_network_address, option)
|
||||
});
|
||||
Ok(Init {
|
||||
features: features.or(global_features),
|
||||
features: features | global_features,
|
||||
remote_network_address,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -64,6 +64,20 @@ pub trait CustomMessageHandler: wire::CustomMessageReader {
|
|||
/// in the process. Each message is paired with the node id of the intended recipient. If no
|
||||
/// connection to the node exists, then the message is simply not sent.
|
||||
fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)>;
|
||||
|
||||
/// Gets the node feature flags which this handler itself supports. All available handlers are
|
||||
/// queried similarly and their feature flags are OR'd together to form the [`NodeFeatures`]
|
||||
/// which are broadcasted in our [`NodeAnnouncement`] message.
|
||||
///
|
||||
/// [`NodeAnnouncement`]: crate::ln::msgs::NodeAnnouncement
|
||||
fn provided_node_features(&self) -> NodeFeatures;
|
||||
|
||||
/// Gets the init feature flags which should be sent to the given peer. All available handlers
|
||||
/// are queried similarly and their feature flags are OR'd together to form the [`InitFeatures`]
|
||||
/// which are sent in our [`Init`] message.
|
||||
///
|
||||
/// [`Init`]: crate::ln::msgs::Init
|
||||
fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures;
|
||||
}
|
||||
|
||||
/// A dummy struct which implements `RoutingMessageHandler` without storing any routing information
|
||||
|
@ -149,6 +163,12 @@ impl CustomMessageHandler for IgnoringMessageHandler {
|
|||
}
|
||||
|
||||
fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> { Vec::new() }
|
||||
|
||||
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
|
||||
|
||||
fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
|
||||
InitFeatures::empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// A dummy struct which implements `ChannelMessageHandler` without having any channels.
|
||||
|
@ -895,6 +915,13 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
|
|||
SecretKey::from_slice(&Sha256::from_engine(ephemeral_hash).into_inner()).expect("You broke SHA-256!")
|
||||
}
|
||||
|
||||
fn init_features(&self, their_node_id: &PublicKey) -> InitFeatures {
|
||||
self.message_handler.chan_handler.provided_init_features(their_node_id)
|
||||
| self.message_handler.route_handler.provided_init_features(their_node_id)
|
||||
| self.message_handler.onion_message_handler.provided_init_features(their_node_id)
|
||||
| self.message_handler.custom_message_handler.provided_init_features(their_node_id)
|
||||
}
|
||||
|
||||
/// Indicates a new outbound connection has been established to a node with the given `node_id`
|
||||
/// and an optional remote network address.
|
||||
///
|
||||
|
@ -1290,9 +1317,7 @@ 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.message_handler.chan_handler.provided_init_features(&their_node_id)
|
||||
.or(self.message_handler.route_handler.provided_init_features(&their_node_id))
|
||||
.or(self.message_handler.onion_message_handler.provided_init_features(&their_node_id));
|
||||
let features = self.init_features(&their_node_id);
|
||||
let resp = msgs::Init { features, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
|
||||
self.enqueue_message(peer, &resp);
|
||||
peer.awaiting_pong_timer_tick_intervals = 0;
|
||||
|
@ -1304,9 +1329,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
|
|||
peer.pending_read_is_header = true;
|
||||
peer.set_their_node_id(their_node_id);
|
||||
insert_node_id!();
|
||||
let features = self.message_handler.chan_handler.provided_init_features(&their_node_id)
|
||||
.or(self.message_handler.route_handler.provided_init_features(&their_node_id))
|
||||
.or(self.message_handler.onion_message_handler.provided_init_features(&their_node_id));
|
||||
let features = self.init_features(&their_node_id);
|
||||
let resp = msgs::Init { features, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
|
||||
self.enqueue_message(peer, &resp);
|
||||
peer.awaiting_pong_timer_tick_intervals = 0;
|
||||
|
@ -1423,10 +1446,17 @@ 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 {
|
||||
if msg.features.requires_unknown_bits() {
|
||||
log_debug!(self.logger, "Peer features required unknown version bits");
|
||||
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");
|
||||
return Err(PeerHandleError { }.into());
|
||||
}
|
||||
|
||||
if our_features.requires_unknown_bits_from(&msg.features) {
|
||||
log_debug!(self.logger, "We require features unknown to our peer");
|
||||
return Err(PeerHandleError { }.into());
|
||||
}
|
||||
|
||||
if peer_lock.their_features.is_some() {
|
||||
return Err(PeerHandleError { }.into());
|
||||
}
|
||||
|
@ -2348,8 +2378,9 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
|
|||
addresses.sort_by_key(|addr| addr.get_id());
|
||||
|
||||
let features = self.message_handler.chan_handler.provided_node_features()
|
||||
.or(self.message_handler.route_handler.provided_node_features())
|
||||
.or(self.message_handler.onion_message_handler.provided_node_features());
|
||||
| self.message_handler.route_handler.provided_node_features()
|
||||
| self.message_handler.onion_message_handler.provided_node_features()
|
||||
| self.message_handler.custom_message_handler.provided_node_features();
|
||||
let announcement = msgs::UnsignedNodeAnnouncement {
|
||||
features,
|
||||
timestamp: self.last_node_announcement_serial.fetch_add(1, Ordering::AcqRel),
|
||||
|
@ -2398,16 +2429,19 @@ fn is_gossip_msg(type_id: u16) -> bool {
|
|||
mod tests {
|
||||
use crate::sign::{NodeSigner, Recipient};
|
||||
use crate::events;
|
||||
use crate::io;
|
||||
use crate::ln::features::{InitFeatures, NodeFeatures};
|
||||
use crate::ln::peer_channel_encryptor::PeerChannelEncryptor;
|
||||
use crate::ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor, IgnoringMessageHandler, filter_addresses};
|
||||
use crate::ln::peer_handler::{CustomMessageHandler, PeerManager, MessageHandler, SocketDescriptor, IgnoringMessageHandler, filter_addresses};
|
||||
use crate::ln::{msgs, wire};
|
||||
use crate::ln::msgs::NetAddress;
|
||||
use crate::ln::msgs::{LightningError, NetAddress};
|
||||
use crate::util::test_utils;
|
||||
|
||||
use bitcoin::secp256k1::SecretKey;
|
||||
use bitcoin::secp256k1::{PublicKey, SecretKey};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::sync::{Arc, Mutex};
|
||||
use core::convert::Infallible;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -2440,19 +2474,51 @@ mod tests {
|
|||
struct PeerManagerCfg {
|
||||
chan_handler: test_utils::TestChannelMessageHandler,
|
||||
routing_handler: test_utils::TestRoutingMessageHandler,
|
||||
custom_handler: TestCustomMessageHandler,
|
||||
logger: test_utils::TestLogger,
|
||||
node_signer: test_utils::TestNodeSigner,
|
||||
}
|
||||
|
||||
struct TestCustomMessageHandler {
|
||||
features: InitFeatures,
|
||||
}
|
||||
|
||||
impl wire::CustomMessageReader for TestCustomMessageHandler {
|
||||
type CustomMessage = Infallible;
|
||||
fn read<R: io::Read>(&self, _: u16, _: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomMessageHandler for TestCustomMessageHandler {
|
||||
fn handle_custom_message(&self, _: Infallible, _: &PublicKey) -> Result<(), LightningError> {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> { Vec::new() }
|
||||
|
||||
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
|
||||
|
||||
fn provided_init_features(&self, _: &PublicKey) -> InitFeatures {
|
||||
self.features.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn create_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 = {
|
||||
let mut feature_bits = vec![0u8; 33];
|
||||
feature_bits[32] = 0b00000001;
|
||||
InitFeatures::from_le_bytes(feature_bits)
|
||||
};
|
||||
cfgs.push(
|
||||
PeerManagerCfg{
|
||||
chan_handler: test_utils::TestChannelMessageHandler::new(),
|
||||
logger: test_utils::TestLogger::new(),
|
||||
routing_handler: test_utils::TestRoutingMessageHandler::new(),
|
||||
custom_handler: TestCustomMessageHandler { features },
|
||||
node_signer: test_utils::TestNodeSigner::new(node_secret),
|
||||
}
|
||||
);
|
||||
|
@ -2461,13 +2527,36 @@ mod tests {
|
|||
cfgs
|
||||
}
|
||||
|
||||
fn create_network<'a>(peer_count: usize, cfgs: &'a Vec<PeerManagerCfg>) -> Vec<PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, IgnoringMessageHandler, &'a test_utils::TestNodeSigner>> {
|
||||
fn create_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 = {
|
||||
let mut feature_bits = vec![0u8; 33 + i + 1];
|
||||
feature_bits[33 + i] = 0b00000001;
|
||||
InitFeatures::from_le_bytes(feature_bits)
|
||||
};
|
||||
cfgs.push(
|
||||
PeerManagerCfg{
|
||||
chan_handler: test_utils::TestChannelMessageHandler::new(),
|
||||
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_network<'a>(peer_count: usize, cfgs: &'a Vec<PeerManagerCfg>) -> Vec<PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, &'a TestCustomMessageHandler, &'a test_utils::TestNodeSigner>> {
|
||||
let mut peers = Vec::new();
|
||||
for i in 0..peer_count {
|
||||
let ephemeral_bytes = [i as u8; 32];
|
||||
let msg_handler = MessageHandler {
|
||||
chan_handler: &cfgs[i].chan_handler, route_handler: &cfgs[i].routing_handler,
|
||||
onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: IgnoringMessageHandler {}
|
||||
onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: &cfgs[i].custom_handler
|
||||
};
|
||||
let peer = PeerManager::new(msg_handler, 0, &ephemeral_bytes, &cfgs[i].logger, &cfgs[i].node_signer);
|
||||
peers.push(peer);
|
||||
|
@ -2476,7 +2565,7 @@ mod tests {
|
|||
peers
|
||||
}
|
||||
|
||||
fn establish_connection<'a>(peer_a: &PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, IgnoringMessageHandler, &'a test_utils::TestNodeSigner>, peer_b: &PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, IgnoringMessageHandler, &'a test_utils::TestNodeSigner>) -> (FileDescriptor, FileDescriptor) {
|
||||
fn establish_connection<'a>(peer_a: &PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, &'a TestCustomMessageHandler, &'a test_utils::TestNodeSigner>, peer_b: &PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, &'a TestCustomMessageHandler, &'a test_utils::TestNodeSigner>) -> (FileDescriptor, FileDescriptor) {
|
||||
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())),
|
||||
|
@ -2591,6 +2680,42 @@ mod tests {
|
|||
thrd_b.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_incompatible_peers() {
|
||||
let cfgs = create_peermgr_cfgs(2);
|
||||
let incompatible_cfgs = create_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 unknown required features
|
||||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue