Merge pull request #433 from TheBlueMatt/2019-12-features-in-routes

Plumb Features through into Routes
This commit is contained in:
Matt Corallo 2020-01-22 20:18:30 +00:00 committed by GitHub
commit c991643746
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 332 additions and 108 deletions

View file

@ -29,8 +29,8 @@ use lightning::ln::channelmonitor;
use lightning::ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, HTLCUpdate};
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, ChannelManagerReadArgs};
use lightning::ln::router::{Route, RouteHop};
use lightning::ln::features::InitFeatures;
use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, ErrorAction, UpdateAddHTLC};
use lightning::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, ErrorAction, UpdateAddHTLC, Init};
use lightning::util::enforcing_trait_impls::EnforcingChannelKeys;
use lightning::util::events;
use lightning::util::logger::Logger;
@ -414,7 +414,9 @@ pub fn do_test(data: &[u8]) {
if let Err(_) = $source.send_payment(Route {
hops: vec![RouteHop {
pubkey: $dest.0.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: $dest.1,
channel_features: ChannelFeatures::empty(),
fee_msat: 5000000,
cltv_expiry_delta: 200,
}],
@ -429,12 +431,16 @@ pub fn do_test(data: &[u8]) {
if let Err(_) = $source.send_payment(Route {
hops: vec![RouteHop {
pubkey: $middle.0.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: $middle.1,
channel_features: ChannelFeatures::empty(),
fee_msat: 50000,
cltv_expiry_delta: 100,
},RouteHop {
pubkey: $dest.0.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: $dest.1,
channel_features: ChannelFeatures::empty(),
fee_msat: 5000000,
cltv_expiry_delta: 200,
}],
@ -650,15 +656,15 @@ pub fn do_test(data: &[u8]) {
},
0x11 => {
if chan_a_disconnected {
nodes[0].peer_connected(&nodes[1].get_our_node_id());
nodes[1].peer_connected(&nodes[0].get_our_node_id());
nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::empty() });
nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::empty() });
chan_a_disconnected = false;
}
},
0x12 => {
if chan_b_disconnected {
nodes[1].peer_connected(&nodes[2].get_our_node_id());
nodes[2].peer_connected(&nodes[1].get_our_node_id());
nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::empty() });
nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::empty() });
chan_b_disconnected = false;
}
},

View file

@ -5,8 +5,9 @@ use bitcoin::blockdata::transaction::Transaction;
use lightning::chain::chaininterface::{ChainError,ChainWatchInterface};
use lightning::ln::channelmanager::ChannelDetails;
use lightning::ln::features::InitFeatures;
use lightning::ln::msgs;
use lightning::ln::msgs::{RoutingMessageHandler};
use lightning::ln::msgs::RoutingMessageHandler;
use lightning::ln::router::{Router, RouteHint};
use lightning::util::logger::Logger;
use lightning::util::ser::Readable;
@ -198,6 +199,7 @@ pub fn do_test(data: &[u8]) {
channel_id: [0; 32],
short_channel_id: Some(slice_to_be64(get_slice!(8))),
remote_network_id: get_pubkey!(),
counterparty_features: InitFeatures::empty(),
channel_value_satoshis: slice_to_be64(get_slice!(8)),
user_id: 0,
inbound_capacity_msat: 0,

View file

@ -215,10 +215,10 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
@ -237,10 +237,10 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
@ -938,8 +938,8 @@ fn test_monitor_update_fail_reestablish() {
commitment_signed_dance!(nodes[1], nodes[2], updates.commitment_signed, false);
*nodes[1].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let as_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
@ -954,8 +954,8 @@ fn test_monitor_update_fail_reestablish() {
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
assert!(as_reestablish == get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()));
assert!(bs_reestablish == get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()));
@ -1118,8 +1118,8 @@ fn claim_while_disconnected_monitor_update_fail() {
assert!(nodes[1].node.claim_funds(payment_preimage_1, 1_000_000));
check_added_monitors!(nodes[1], 1);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let as_reconnect = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
let bs_reconnect = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
@ -1246,8 +1246,8 @@ fn monitor_failed_no_reestablish_response() {
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let as_reconnect = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
let bs_reconnect = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());

View file

@ -275,6 +275,12 @@ pub(super) struct ChannelHolder<ChanSigner: ChannelKeys> {
pub(super) pending_msg_events: Vec<events::MessageSendEvent>,
}
/// State we hold per-peer. In the future we should put channels in here, but for now we only hold
/// the latest Init features we heard from the peer.
struct PeerState {
latest_features: InitFeatures,
}
#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
const ERR: () = "You need at least 32 bit pointers (well, usize, but we'll assume they're the same) for ChannelManager::latest_block_height";
@ -328,6 +334,14 @@ pub struct ChannelManager<ChanSigner: ChannelKeys> {
channel_state: Mutex<ChannelHolder<ChanSigner>>,
our_network_key: SecretKey,
/// The bulk of our storage will eventually be here (channels and message queues and the like).
/// If we are connected to a peer we always at least have an entry here, even if no channels
/// are currently open with that peer.
/// Because adding or removing an entry is rare, we usually take an outer read lock and then
/// operate on the inner value freely. Sadly, this prevents parallel operation when opening a
/// new channel.
per_peer_state: RwLock<HashMap<PublicKey, Mutex<PeerState>>>,
pending_events: Mutex<Vec<events::Event>>,
/// Used when we have to take a BIG lock to make sure everything is self-consistent.
/// Essentially just when we're serializing ourselves out.
@ -390,6 +404,10 @@ pub struct ChannelDetails {
pub short_channel_id: Option<u64>,
/// The node_id of our counterparty
pub remote_network_id: PublicKey,
/// The Features the channel counterparty provided upon last connection.
/// Useful for routing as it is the most up-to-date copy of the counterparty's features and
/// many routing-relevant features are present in the init context.
pub counterparty_features: InitFeatures,
/// The value, in satoshis, of this channel as appears in the funding output
pub channel_value_satoshis: u64,
/// The user_id passed in to create_channel, or 0 if the channel was inbound.
@ -610,6 +628,8 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
}),
our_network_key: keys_manager.get_node_secret(),
per_peer_state: RwLock::new(HashMap::new()),
pending_events: Mutex::new(Vec::new()),
total_consistency_lock: RwLock::new(()),
@ -660,25 +680,39 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
Ok(())
}
fn list_channels_with_filter<F: FnMut(&(&[u8; 32], &Channel<ChanSigner>)) -> bool>(&self, f: F) -> Vec<ChannelDetails> {
let mut res = Vec::new();
{
let channel_state = self.channel_state.lock().unwrap();
res.reserve(channel_state.by_id.len());
for (channel_id, channel) in channel_state.by_id.iter().filter(f) {
let (inbound_capacity_msat, outbound_capacity_msat) = channel.get_inbound_outbound_available_balance_msat();
res.push(ChannelDetails {
channel_id: (*channel_id).clone(),
short_channel_id: channel.get_short_channel_id(),
remote_network_id: channel.get_their_node_id(),
counterparty_features: InitFeatures::empty(),
channel_value_satoshis: channel.get_value_satoshis(),
inbound_capacity_msat,
outbound_capacity_msat,
user_id: channel.get_user_id(),
is_live: channel.is_live(),
});
}
}
let per_peer_state = self.per_peer_state.read().unwrap();
for chan in res.iter_mut() {
if let Some(peer_state) = per_peer_state.get(&chan.remote_network_id) {
chan.counterparty_features = peer_state.lock().unwrap().latest_features.clone();
}
}
res
}
/// Gets the list of open channels, in random order. See ChannelDetail field documentation for
/// more information.
pub fn list_channels(&self) -> Vec<ChannelDetails> {
let channel_state = self.channel_state.lock().unwrap();
let mut res = Vec::with_capacity(channel_state.by_id.len());
for (channel_id, channel) in channel_state.by_id.iter() {
let (inbound_capacity_msat, outbound_capacity_msat) = channel.get_inbound_outbound_available_balance_msat();
res.push(ChannelDetails {
channel_id: (*channel_id).clone(),
short_channel_id: channel.get_short_channel_id(),
remote_network_id: channel.get_their_node_id(),
channel_value_satoshis: channel.get_value_satoshis(),
inbound_capacity_msat,
outbound_capacity_msat,
user_id: channel.get_user_id(),
is_live: channel.is_live(),
});
}
res
self.list_channels_with_filter(|_| true)
}
/// Gets the list of usable channels, in random order. Useful as an argument to
@ -687,27 +721,10 @@ impl<ChanSigner: ChannelKeys> ChannelManager<ChanSigner> {
/// These are guaranteed to have their is_live value set to true, see the documentation for
/// ChannelDetails::is_live for more info on exactly what the criteria are.
pub fn list_usable_channels(&self) -> Vec<ChannelDetails> {
let channel_state = self.channel_state.lock().unwrap();
let mut res = Vec::with_capacity(channel_state.by_id.len());
for (channel_id, channel) in channel_state.by_id.iter() {
// Note we use is_live here instead of usable which leads to somewhat confused
// internal/external nomenclature, but that's ok cause that's probably what the user
// really wanted anyway.
if channel.is_live() {
let (inbound_capacity_msat, outbound_capacity_msat) = channel.get_inbound_outbound_available_balance_msat();
res.push(ChannelDetails {
channel_id: (*channel_id).clone(),
short_channel_id: channel.get_short_channel_id(),
remote_network_id: channel.get_their_node_id(),
channel_value_satoshis: channel.get_value_satoshis(),
inbound_capacity_msat,
outbound_capacity_msat,
user_id: channel.get_user_id(),
is_live: true,
});
}
}
res
// Note we use is_live here instead of usable which leads to somewhat confused
// internal/external nomenclature, but that's ok cause that's probably what the user
// really wanted anyway.
self.list_channels_with_filter(|&(_, ref channel)| channel.is_live())
}
/// Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs
@ -2780,6 +2797,7 @@ impl<ChanSigner: ChannelKeys> ChannelMessageHandler for ChannelManager<ChanSigne
let _ = self.total_consistency_lock.read().unwrap();
let mut failed_channels = Vec::new();
let mut failed_payments = Vec::new();
let mut no_channels_remain = true;
{
let mut channel_state_lock = self.channel_state.lock().unwrap();
let channel_state = &mut *channel_state_lock;
@ -2818,6 +2836,8 @@ impl<ChanSigner: ChannelKeys> ChannelMessageHandler for ChannelManager<ChanSigne
short_to_id.remove(&short_id);
}
return false;
} else {
no_channels_remain = false;
}
}
true
@ -2843,6 +2863,10 @@ impl<ChanSigner: ChannelKeys> ChannelMessageHandler for ChannelManager<ChanSigne
}
});
}
if no_channels_remain {
self.per_peer_state.write().unwrap().remove(their_node_id);
}
for failure in failed_channels.drain(..) {
self.finish_force_close_channel(failure);
}
@ -2853,10 +2877,25 @@ impl<ChanSigner: ChannelKeys> ChannelMessageHandler for ChannelManager<ChanSigne
}
}
fn peer_connected(&self, their_node_id: &PublicKey) {
fn peer_connected(&self, their_node_id: &PublicKey, init_msg: &msgs::Init) {
log_debug!(self, "Generating channel_reestablish events for {}", log_pubkey!(their_node_id));
let _ = self.total_consistency_lock.read().unwrap();
{
let mut peer_state_lock = self.per_peer_state.write().unwrap();
match peer_state_lock.entry(their_node_id.clone()) {
hash_map::Entry::Vacant(e) => {
e.insert(Mutex::new(PeerState {
latest_features: init_msg.features.clone(),
}));
},
hash_map::Entry::Occupied(e) => {
e.get().lock().unwrap().latest_features = init_msg.features.clone();
},
}
}
let mut channel_state_lock = self.channel_state.lock().unwrap();
let channel_state = &mut *channel_state_lock;
let pending_msg_events = &mut channel_state.pending_msg_events;
@ -3123,6 +3162,14 @@ impl<ChanSigner: ChannelKeys + Writeable> Writeable for ChannelManager<ChanSigne
}
}
let per_peer_state = self.per_peer_state.write().unwrap();
(per_peer_state.len() as u64).write(writer)?;
for (peer_pubkey, peer_state_mutex) in per_peer_state.iter() {
peer_pubkey.write(writer)?;
let peer_state = peer_state_mutex.lock().unwrap();
peer_state.latest_features.write(writer)?;
}
Ok(())
}
}
@ -3256,6 +3303,16 @@ impl<'a, R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArg
claimable_htlcs.insert(payment_hash, previous_hops);
}
let peer_count: u64 = Readable::read(reader)?;
let mut per_peer_state = HashMap::with_capacity(cmp::min(peer_count as usize, 128));
for _ in 0..peer_count {
let peer_pubkey = Readable::read(reader)?;
let peer_state = PeerState {
latest_features: Readable::read(reader)?,
};
per_peer_state.insert(peer_pubkey, Mutex::new(peer_state));
}
let channel_manager = ChannelManager {
genesis_hash,
fee_estimator: args.fee_estimator,
@ -3275,6 +3332,8 @@ impl<'a, R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArg
}),
our_network_key: args.keys_manager.get_node_secret(),
per_peer_state: RwLock::new(per_peer_state),
pending_events: Mutex::new(Vec::new()),
total_consistency_lock: RwLock::new(()),
keys_manager: args.keys_manager,

View file

@ -118,6 +118,13 @@ impl ChannelFeatures {
mark: PhantomData,
}
}
/// Takes the flags that we know how to interpret in an init-context features that are also
/// relevant in a channel-context features and creates a channel-context features from them.
pub(crate) fn with_known_relevant_init_flags(_init_ctx: &InitFeatures) -> Self {
// There are currently no channel flags defined that we understand.
Self { flags: Vec::new(), mark: PhantomData, }
}
}
impl NodeFeatures {
@ -136,6 +143,17 @@ impl NodeFeatures {
mark: PhantomData,
}
}
/// Takes the flags that we know how to interpret in an init-context features that are also
/// relevant in a node-context features and creates a node-context features from them.
pub(crate) fn with_known_relevant_init_flags(init_ctx: &InitFeatures) -> Self {
let mut flags = Vec::new();
if init_ctx.flags.len() > 0 {
// Pull out data_loss_protect and upfront_shutdown_script (bits 0, 1, 4, and 5)
flags.push(init_ctx.flags.last().unwrap() & 0b00110011);
}
Self { flags, mark: PhantomData, }
}
}
impl<T: sealed::Context> Features<T> {

View file

@ -1087,9 +1087,9 @@ macro_rules! handle_chan_reestablish_msgs {
/// pending_htlc_adds includes both the holding cell and in-flight update_add_htlcs, whereas
/// for claims/fails they are separated out.
pub fn reconnect_nodes(node_a: &Node, node_b: &Node, send_funding_locked: (bool, bool), pending_htlc_adds: (i64, i64), pending_htlc_claims: (usize, usize), pending_cell_htlc_claims: (usize, usize), pending_cell_htlc_fails: (usize, usize), pending_raa: (bool, bool)) {
node_a.node.peer_connected(&node_b.node.get_our_node_id());
node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_1 = get_chan_reestablish_msgs!(node_a, node_b);
node_b.node.peer_connected(&node_a.node.get_our_node_id());
node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_2 = get_chan_reestablish_msgs!(node_b, node_a);
if send_funding_locked.0 {

View file

@ -11,7 +11,7 @@ use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD
use ln::channel::{Channel, ChannelError};
use ln::onion_utils;
use ln::router::{Route, RouteHop};
use ln::features::{ChannelFeatures, InitFeatures};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction};
use util::enforcing_trait_impls::EnforcingChannelKeys;
@ -852,9 +852,9 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) {
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let node_0_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let node_1_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &node_0_reestablish);
@ -916,9 +916,9 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) {
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let node_0_2nd_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
if recv_count == 0 {
// If all closing_signeds weren't delivered we can just resume where we left off...
let node_1_2nd_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
@ -1029,19 +1029,25 @@ fn fake_network_test() {
let mut hops = Vec::with_capacity(3);
hops.push(RouteHop {
pubkey: nodes[2].node.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: chan_2.0.contents.short_channel_id,
channel_features: ChannelFeatures::empty(),
fee_msat: 0,
cltv_expiry_delta: chan_3.0.contents.cltv_expiry_delta as u32
});
hops.push(RouteHop {
pubkey: nodes[3].node.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: chan_3.0.contents.short_channel_id,
channel_features: ChannelFeatures::empty(),
fee_msat: 0,
cltv_expiry_delta: chan_4.1.contents.cltv_expiry_delta as u32
});
hops.push(RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: chan_4.0.contents.short_channel_id,
channel_features: ChannelFeatures::empty(),
fee_msat: 1000000,
cltv_expiry_delta: TEST_FINAL_CLTV,
});
@ -1052,19 +1058,25 @@ fn fake_network_test() {
let mut hops = Vec::with_capacity(3);
hops.push(RouteHop {
pubkey: nodes[3].node.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: chan_4.0.contents.short_channel_id,
channel_features: ChannelFeatures::empty(),
fee_msat: 0,
cltv_expiry_delta: chan_3.1.contents.cltv_expiry_delta as u32
});
hops.push(RouteHop {
pubkey: nodes[2].node.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: chan_3.0.contents.short_channel_id,
channel_features: ChannelFeatures::empty(),
fee_msat: 0,
cltv_expiry_delta: chan_2.1.contents.cltv_expiry_delta as u32
});
hops.push(RouteHop {
pubkey: nodes[1].node.get_our_node_id(),
node_features: NodeFeatures::empty(),
short_channel_id: chan_2.0.contents.short_channel_id,
channel_features: ChannelFeatures::empty(),
fee_msat: 1000000,
cltv_expiry_delta: TEST_FINAL_CLTV,
});
@ -3254,10 +3266,10 @@ fn test_drop_messages_peer_disconnect_dual_htlc() {
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
@ -3451,9 +3463,9 @@ fn test_no_txn_manager_serialize_deserialize() {
assert_eq!(nodes[0].node.list_channels().len(), 1);
check_added_monitors!(nodes[0], 1);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[0]);
@ -3586,9 +3598,9 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
//... and we can even still claim the payment!
claim_payment(&nodes[2], &[&nodes[0], &nodes[1]], our_payment_preimage, 1_000_000);
nodes[3].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[3].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish = get_event_msg!(nodes[3], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[3].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
nodes[0].node.handle_channel_reestablish(&nodes[3].node.get_our_node_id(), &reestablish);
let msg_events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(msg_events.len(), 1);
@ -5380,10 +5392,10 @@ fn test_update_add_htlc_bolt2_receiver_check_repeated_id_ignore() {
//Disconnect and Reconnect
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 1);
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 1);
nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &reestablish_2[0]);
@ -6155,8 +6167,8 @@ fn test_data_loss_protect() {
check_added_monitors!(nodes[0], 1);
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_0 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
@ -6297,10 +6309,10 @@ fn test_announce_disable_channels() {
}
}
// Reconnect peers
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
assert_eq!(reestablish_1.len(), 3);
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
assert_eq!(reestablish_2.len(), 3);

View file

@ -56,7 +56,10 @@ pub enum DecodeError {
/// An init message to be sent or received from a peer
pub struct Init {
#[cfg(not(feature = "fuzztarget"))]
pub(crate) features: InitFeatures,
#[cfg(feature = "fuzztarget")]
pub features: InitFeatures,
}
/// An error message to be sent or received from a peer
@ -571,7 +574,7 @@ pub trait ChannelMessageHandler : events::MessageSendEventsProvider + Send + Syn
fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);
/// Handle a peer reconnecting, possibly generating channel_reestablish message(s).
fn peer_connected(&self, their_node_id: &PublicKey);
fn peer_connected(&self, their_node_id: &PublicKey, msg: &Init);
/// Handle an incoming channel_reestablish message from the given peer.
fn handle_channel_reestablish(&self, their_node_id: &PublicKey, msg: &ChannelReestablish);

View file

@ -425,6 +425,7 @@ pub(super) fn process_onion_failure<T: secp256k1::Signing>(secp_ctx: &Secp256k1<
#[cfg(test)]
mod tests {
use ln::channelmanager::PaymentHash;
use ln::features::{ChannelFeatures, NodeFeatures};
use ln::router::{Route, RouteHop};
use ln::msgs;
use util::ser::Writeable;
@ -444,22 +445,27 @@ mod tests {
hops: vec!(
RouteHop {
pubkey: PublicKey::from_slice(&hex::decode("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap(),
channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
short_channel_id: 0, fee_msat: 0, cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
},
RouteHop {
pubkey: PublicKey::from_slice(&hex::decode("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()[..]).unwrap(),
channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
short_channel_id: 0, fee_msat: 0, cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
},
RouteHop {
pubkey: PublicKey::from_slice(&hex::decode("027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007").unwrap()[..]).unwrap(),
channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
short_channel_id: 0, fee_msat: 0, cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
},
RouteHop {
pubkey: PublicKey::from_slice(&hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]).unwrap(),
channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
short_channel_id: 0, fee_msat: 0, cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
},
RouteHop {
pubkey: PublicKey::from_slice(&hex::decode("02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145").unwrap()[..]).unwrap(),
channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(),
short_channel_id: 0, fee_msat: 0, cltv_expiry_delta: 0 // Test vectors are garbage and not generateble from a RouteHop, we fill in payloads manually
},
),

View file

@ -622,7 +622,6 @@ impl<Descriptor: SocketDescriptor> PeerManager<Descriptor> {
peer.sync_status = InitSyncTracker::ChannelsSyncing(0);
peers.peers_needing_send.insert(peer_descriptor.clone());
}
peer.their_features = Some(msg.features);
if !peer.outbound {
let mut features = InitFeatures::supported();
@ -636,7 +635,8 @@ impl<Descriptor: SocketDescriptor> PeerManager<Descriptor> {
}, 16);
}
self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap());
self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg);
peer.their_features = Some(msg.features);
},
17 => {
let msg = try_potential_decodeerror!(msgs::ErrorMessage::read(&mut reader));

View file

@ -31,8 +31,14 @@ use std;
pub struct RouteHop {
/// The node_id of the node at this hop.
pub pubkey: PublicKey,
/// The node_announcement features of the node at this hop. For the last hop, these may be
/// amended to match the features present in the invoice this node generated.
pub node_features: NodeFeatures,
/// The channel that should be used from the previous hop to reach this node.
pub short_channel_id: u64,
/// The channel_announcement features of the channel that should be used from the previous hop
/// to reach this node.
pub channel_features: ChannelFeatures,
/// The fee taken on this hop. For the last hop, this should be the full value of the payment.
pub fee_msat: u64,
/// The CLTV delta added for this hop. For the last hop, this should be the full CLTV value
@ -54,7 +60,9 @@ impl Writeable for Route {
(self.hops.len() as u8).write(writer)?;
for hop in self.hops.iter() {
hop.pubkey.write(writer)?;
hop.node_features.write(writer)?;
hop.short_channel_id.write(writer)?;
hop.channel_features.write(writer)?;
hop.fee_msat.write(writer)?;
hop.cltv_expiry_delta.write(writer)?;
}
@ -69,7 +77,9 @@ impl<R: ::std::io::Read> Readable<R> for Route {
for _ in 0..hops_count {
hops.push(RouteHop {
pubkey: Readable::read(reader)?,
node_features: Readable::read(reader)?,
short_channel_id: Readable::read(reader)?,
channel_features: Readable::read(reader)?,
fee_msat: Readable::read(reader)?,
cltv_expiry_delta: Readable::read(reader)?,
});
@ -840,13 +850,15 @@ impl Router {
return Ok(Route {
hops: vec![RouteHop {
pubkey: chan.remote_network_id,
node_features: NodeFeatures::with_known_relevant_init_flags(&chan.counterparty_features),
short_channel_id,
channel_features: ChannelFeatures::with_known_relevant_init_flags(&chan.counterparty_features),
fee_msat: final_value_msat,
cltv_expiry_delta: final_cltv,
}],
});
}
first_hop_targets.insert(chan.remote_network_id, short_channel_id);
first_hop_targets.insert(chan.remote_network_id, (short_channel_id, chan.counterparty_features.clone()));
}
if first_hop_targets.is_empty() {
return Err(LightningError{err: "Cannot route when there are no outbound routes away from us", action: ErrorAction::IgnoreError});
@ -857,7 +869,7 @@ impl Router {
// Adds entry which goes from the node pointed to by $directional_info to
// $dest_node_id over the channel with id $chan_id with fees described in
// $directional_info.
( $chan_id: expr, $dest_node_id: expr, $directional_info: expr, $starting_fee_msat: expr ) => {
( $chan_id: expr, $dest_node_id: expr, $directional_info: expr, $chan_features: expr, $starting_fee_msat: expr ) => {
//TODO: Explore simply adding fee to hit htlc_minimum_msat
if $starting_fee_msat as u64 + final_value_msat >= $directional_info.htlc_minimum_msat {
let proportional_fee_millions = ($starting_fee_msat + final_value_msat).checked_mul($directional_info.fee_proportional_millionths as u64);
@ -873,7 +885,9 @@ impl Router {
node.lowest_inbound_channel_fee_proportional_millionths,
RouteHop {
pubkey: $dest_node_id.clone(),
node_features: NodeFeatures::empty(),
short_channel_id: 0,
channel_features: $chan_features.clone(),
fee_msat: 0,
cltv_expiry_delta: 0,
})
@ -899,7 +913,9 @@ impl Router {
old_entry.0 = total_fee;
old_entry.3 = RouteHop {
pubkey: $dest_node_id.clone(),
node_features: NodeFeatures::empty(),
short_channel_id: $chan_id.clone(),
channel_features: $chan_features.clone(),
fee_msat: new_fee, // This field is ignored on the last-hop anyway
cltv_expiry_delta: $directional_info.cltv_expiry_delta as u32,
}
@ -912,8 +928,8 @@ impl Router {
macro_rules! add_entries_to_cheapest_to_target_node {
( $node: expr, $node_id: expr, $fee_to_target_msat: expr ) => {
if first_hops.is_some() {
if let Some(first_hop) = first_hop_targets.get(&$node_id) {
add_entry!(first_hop, $node_id, dummy_directional_info, $fee_to_target_msat);
if let Some(&(ref first_hop, ref features)) = first_hop_targets.get(&$node_id) {
add_entry!(first_hop, $node_id, dummy_directional_info, ChannelFeatures::with_known_relevant_init_flags(&features), $fee_to_target_msat);
}
}
@ -925,13 +941,13 @@ impl Router {
// ie $node is one, ie next hop in A* is two, via the two_to_one channel
if first_hops.is_none() || chan.two_to_one.src_node_id != network.our_node_id {
if chan.two_to_one.enabled {
add_entry!(chan_id, chan.one_to_two.src_node_id, chan.two_to_one, $fee_to_target_msat);
add_entry!(chan_id, chan.one_to_two.src_node_id, chan.two_to_one, chan.features, $fee_to_target_msat);
}
}
} else {
if first_hops.is_none() || chan.one_to_two.src_node_id != network.our_node_id {
if chan.one_to_two.enabled {
add_entry!(chan_id, chan.two_to_one.src_node_id, chan.one_to_two, $fee_to_target_msat);
add_entry!(chan_id, chan.two_to_one.src_node_id, chan.one_to_two, chan.features, $fee_to_target_msat);
}
}
}
@ -952,11 +968,17 @@ impl Router {
if first_hops.is_none() || hop.src_node_id != network.our_node_id { // first_hop overrules last_hops
if network.nodes.get(&hop.src_node_id).is_some() {
if first_hops.is_some() {
if let Some(first_hop) = first_hop_targets.get(&hop.src_node_id) {
add_entry!(first_hop, hop.src_node_id, dummy_directional_info, 0);
if let Some(&(ref first_hop, ref features)) = first_hop_targets.get(&hop.src_node_id) {
// Currently there are no channel-context features defined, so we are a
// bit lazy here. In the future, we should pull them out via our
// ChannelManager, but there's no reason to waste the space until we
// need them.
add_entry!(first_hop, hop.src_node_id, dummy_directional_info, ChannelFeatures::with_known_relevant_init_flags(&features), 0);
}
}
add_entry!(hop.short_channel_id, target, hop, 0);
// BOLT 11 doesn't allow inclusion of features for the last hop hints, which
// really sucks, cause we're gonna need that eventually.
add_entry!(hop.short_channel_id, target, hop, ChannelFeatures::empty(), 0);
}
}
}
@ -964,7 +986,22 @@ impl Router {
while let Some(RouteGraphNode { pubkey, lowest_fee_to_node, .. }) = targets.pop() {
if pubkey == network.our_node_id {
let mut res = vec!(dist.remove(&network.our_node_id).unwrap().3);
while res.last().unwrap().pubkey != *target {
loop {
if let Some(&(_, ref features)) = first_hop_targets.get(&res.last().unwrap().pubkey) {
res.last_mut().unwrap().node_features = NodeFeatures::with_known_relevant_init_flags(&features);
} else if let Some(node) = network.nodes.get(&res.last().unwrap().pubkey) {
res.last_mut().unwrap().node_features = node.features.clone();
} else {
// We should be able to fill in features for everything except the last
// hop, if the last hop was provided via a BOLT 11 invoice (though we
// should be able to extend it further as BOLT 11 does have feature
// flags for the last hop node itself).
assert!(res.last().unwrap().pubkey == *target);
}
if res.last().unwrap().pubkey == *target {
break;
}
let new_entry = match dist.remove(&res.last().unwrap().pubkey) {
Some(hop) => hop.3,
None => return Err(LightningError{err: "Failed to find a non-fee-overflowing path to the given destination", action: ErrorAction::IgnoreError}),
@ -997,7 +1034,7 @@ mod tests {
use chain::chaininterface;
use ln::channelmanager;
use ln::router::{Router,NodeInfo,NetworkMap,ChannelInfo,DirectionalChannelInfo,RouteHint};
use ln::features::{ChannelFeatures, NodeFeatures};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs::{LightningError, ErrorAction};
use util::test_utils;
use util::test_utils::TestVecWriter;
@ -1091,6 +1128,23 @@ mod tests {
let zero_hash = Sha256dHash::hash(&[0; 32]);
macro_rules! id_to_feature_flags {
// Set the feature flags to the id'th odd (ie non-required) feature bit so that we can
// test for it later.
($id: expr) => { {
let idx = ($id - 1) * 2 + 1;
if idx > 8*3 {
vec![1 << (idx - 8*3), 0, 0, 0]
} else if idx > 8*2 {
vec![1 << (idx - 8*2), 0, 0]
} else if idx > 8*1 {
vec![1 << (idx - 8*1), 0]
} else {
vec![1 << idx]
}
} }
}
{
let mut network = router.network_map.write().unwrap();
@ -1098,7 +1152,7 @@ mod tests {
channels: vec!(NetworkMap::get_key(1, zero_hash.clone()), NetworkMap::get_key(3, zero_hash.clone())),
lowest_inbound_channel_fee_base_msat: 100,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::empty(),
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(1)),
last_update: 1,
rgb: [0; 3],
alias: [0; 32],
@ -1106,7 +1160,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(1, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(1)),
one_to_two: DirectionalChannelInfo {
src_node_id: our_id.clone(),
last_update: 0,
@ -1132,7 +1186,7 @@ mod tests {
channels: vec!(NetworkMap::get_key(2, zero_hash.clone()), NetworkMap::get_key(4, zero_hash.clone())),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::empty(),
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(2)),
last_update: 1,
rgb: [0; 3],
alias: [0; 32],
@ -1140,7 +1194,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(2, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(2)),
one_to_two: DirectionalChannelInfo {
src_node_id: our_id.clone(),
last_update: 0,
@ -1166,7 +1220,7 @@ mod tests {
channels: vec!(NetworkMap::get_key(12, zero_hash.clone()), NetworkMap::get_key(13, zero_hash.clone())),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::empty(),
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(8)),
last_update: 1,
rgb: [0; 3],
alias: [0; 32],
@ -1174,7 +1228,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(12, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(12)),
one_to_two: DirectionalChannelInfo {
src_node_id: our_id.clone(),
last_update: 0,
@ -1206,7 +1260,7 @@ mod tests {
NetworkMap::get_key(7, zero_hash.clone())),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::empty(),
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(3)),
last_update: 1,
rgb: [0; 3],
alias: [0; 32],
@ -1214,7 +1268,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(3, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(3)),
one_to_two: DirectionalChannelInfo {
src_node_id: node1.clone(),
last_update: 0,
@ -1237,7 +1291,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(4, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(4)),
one_to_two: DirectionalChannelInfo {
src_node_id: node2.clone(),
last_update: 0,
@ -1260,7 +1314,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(13, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(13)),
one_to_two: DirectionalChannelInfo {
src_node_id: node8.clone(),
last_update: 0,
@ -1286,7 +1340,7 @@ mod tests {
channels: vec!(NetworkMap::get_key(5, zero_hash.clone()), NetworkMap::get_key(11, zero_hash.clone())),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::empty(),
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(4)),
last_update: 1,
rgb: [0; 3],
alias: [0; 32],
@ -1294,7 +1348,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(5, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(5)),
one_to_two: DirectionalChannelInfo {
src_node_id: node3.clone(),
last_update: 0,
@ -1320,7 +1374,7 @@ mod tests {
channels: vec!(NetworkMap::get_key(6, zero_hash.clone()), NetworkMap::get_key(11, zero_hash.clone())),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::empty(),
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(5)),
last_update: 1,
rgb: [0; 3],
alias: [0; 32],
@ -1328,7 +1382,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(6, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(6)),
one_to_two: DirectionalChannelInfo {
src_node_id: node3.clone(),
last_update: 0,
@ -1351,7 +1405,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(11, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(11)),
one_to_two: DirectionalChannelInfo {
src_node_id: node5.clone(),
last_update: 0,
@ -1377,7 +1431,7 @@ mod tests {
channels: vec!(NetworkMap::get_key(7, zero_hash.clone())),
lowest_inbound_channel_fee_base_msat: 0,
lowest_inbound_channel_fee_proportional_millionths: 0,
features: NodeFeatures::empty(),
features: NodeFeatures::from_le_bytes(id_to_feature_flags!(6)),
last_update: 1,
rgb: [0; 3],
alias: [0; 32],
@ -1385,7 +1439,7 @@ mod tests {
announcement_message: None,
});
network.channels.insert(NetworkMap::get_key(7, zero_hash.clone()), ChannelInfo {
features: ChannelFeatures::empty(),
features: ChannelFeatures::from_le_bytes(id_to_feature_flags!(7)),
one_to_two: DirectionalChannelInfo {
src_node_id: node3.clone(),
last_update: 0,
@ -1417,11 +1471,15 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 2);
assert_eq!(route.hops[0].fee_msat, 100);
assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[1].pubkey, node3);
assert_eq!(route.hops[1].short_channel_id, 4);
assert_eq!(route.hops[1].fee_msat, 100);
assert_eq!(route.hops[1].cltv_expiry_delta, 42);
assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
}
{ // Disable channels 4 and 12 by requiring unknown feature bits
@ -1441,6 +1499,7 @@ mod tests {
channel_id: [0; 32],
short_channel_id: Some(42),
remote_network_id: node8.clone(),
counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
channel_value_satoshis: 0,
user_id: 0,
outbound_capacity_msat: 0,
@ -1454,11 +1513,15 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 42);
assert_eq!(route.hops[0].fee_msat, 200);
assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]); // it should also override our view of their features
assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion
assert_eq!(route.hops[1].pubkey, node3);
assert_eq!(route.hops[1].short_channel_id, 13);
assert_eq!(route.hops[1].fee_msat, 100);
assert_eq!(route.hops[1].cltv_expiry_delta, 42);
assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13));
}
{ // Re-enable channels 4 and 12 by wiping the unknown feature bits
@ -1485,6 +1548,7 @@ mod tests {
channel_id: [0; 32],
short_channel_id: Some(42),
remote_network_id: node8.clone(),
counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
channel_value_satoshis: 0,
user_id: 0,
outbound_capacity_msat: 0,
@ -1498,11 +1562,15 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 42);
assert_eq!(route.hops[0].fee_msat, 200);
assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]); // it should also override our view of their features
assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion
assert_eq!(route.hops[1].pubkey, node3);
assert_eq!(route.hops[1].short_channel_id, 13);
assert_eq!(route.hops[1].fee_msat, 100);
assert_eq!(route.hops[1].cltv_expiry_delta, 42);
assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13));
}
{ // Re-enable nodes 1, 2, and 8
@ -1524,16 +1592,22 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 2);
assert_eq!(route.hops[0].fee_msat, 200);
assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[1].pubkey, node3);
assert_eq!(route.hops[1].short_channel_id, 4);
assert_eq!(route.hops[1].fee_msat, 100);
assert_eq!(route.hops[1].cltv_expiry_delta, (3 << 8) | 2);
assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
assert_eq!(route.hops[2].pubkey, node1);
assert_eq!(route.hops[2].short_channel_id, 3);
assert_eq!(route.hops[2].fee_msat, 100);
assert_eq!(route.hops[2].cltv_expiry_delta, 42);
assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(1));
assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(3));
}
{ // If we specify a channel to node8, that overrides our local channel view and that gets used
@ -1541,6 +1615,7 @@ mod tests {
channel_id: [0; 32],
short_channel_id: Some(42),
remote_network_id: node8.clone(),
counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
channel_value_satoshis: 0,
user_id: 0,
outbound_capacity_msat: 0,
@ -1554,11 +1629,15 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 42);
assert_eq!(route.hops[0].fee_msat, 200);
assert_eq!(route.hops[0].cltv_expiry_delta, (13 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]);
assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion
assert_eq!(route.hops[1].pubkey, node3);
assert_eq!(route.hops[1].short_channel_id, 13);
assert_eq!(route.hops[1].fee_msat, 100);
assert_eq!(route.hops[1].cltv_expiry_delta, 42);
assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(13));
}
let mut last_hops = vec!(RouteHint {
@ -1592,26 +1671,38 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 2);
assert_eq!(route.hops[0].fee_msat, 100);
assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[1].pubkey, node3);
assert_eq!(route.hops[1].short_channel_id, 4);
assert_eq!(route.hops[1].fee_msat, 0);
assert_eq!(route.hops[1].cltv_expiry_delta, (6 << 8) | 1);
assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
assert_eq!(route.hops[2].pubkey, node5);
assert_eq!(route.hops[2].short_channel_id, 6);
assert_eq!(route.hops[2].fee_msat, 0);
assert_eq!(route.hops[2].cltv_expiry_delta, (11 << 8) | 1);
assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(5));
assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(6));
assert_eq!(route.hops[3].pubkey, node4);
assert_eq!(route.hops[3].short_channel_id, 11);
assert_eq!(route.hops[3].fee_msat, 0);
assert_eq!(route.hops[3].cltv_expiry_delta, (8 << 8) | 1);
// If we have a peer in the node map, we'll use their features here since we don't have
// a way of figuring out their features from the invoice:
assert_eq!(route.hops[3].node_features.le_flags(), &id_to_feature_flags!(4));
assert_eq!(route.hops[3].channel_features.le_flags(), &id_to_feature_flags!(11));
assert_eq!(route.hops[4].pubkey, node7);
assert_eq!(route.hops[4].short_channel_id, 8);
assert_eq!(route.hops[4].fee_msat, 100);
assert_eq!(route.hops[4].cltv_expiry_delta, 42);
assert_eq!(route.hops[4].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet
assert_eq!(route.hops[4].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly
}
{ // Simple test with outbound channel to 4 to test that last_hops and first_hops connect
@ -1619,6 +1710,7 @@ mod tests {
channel_id: [0; 32],
short_channel_id: Some(42),
remote_network_id: node4.clone(),
counterparty_features: InitFeatures::from_le_bytes(vec![0b11]),
channel_value_satoshis: 0,
user_id: 0,
outbound_capacity_msat: 0,
@ -1632,11 +1724,15 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 42);
assert_eq!(route.hops[0].fee_msat, 0);
assert_eq!(route.hops[0].cltv_expiry_delta, (8 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &vec![0b11]);
assert_eq!(route.hops[0].channel_features.le_flags(), &Vec::new()); // No feature flags will meet the relevant-to-channel conversion
assert_eq!(route.hops[1].pubkey, node7);
assert_eq!(route.hops[1].short_channel_id, 8);
assert_eq!(route.hops[1].fee_msat, 100);
assert_eq!(route.hops[1].cltv_expiry_delta, 42);
assert_eq!(route.hops[1].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet
assert_eq!(route.hops[1].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly
}
last_hops[0].fee_base_msat = 1000;
@ -1649,21 +1745,31 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 2);
assert_eq!(route.hops[0].fee_msat, 200); // fee increased as its % of value transferred across node
assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[1].pubkey, node3);
assert_eq!(route.hops[1].short_channel_id, 4);
assert_eq!(route.hops[1].fee_msat, 100);
assert_eq!(route.hops[1].cltv_expiry_delta, (7 << 8) | 1);
assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
assert_eq!(route.hops[2].pubkey, node6);
assert_eq!(route.hops[2].short_channel_id, 7);
assert_eq!(route.hops[2].fee_msat, 0);
assert_eq!(route.hops[2].cltv_expiry_delta, (10 << 8) | 1);
// If we have a peer in the node map, we'll use their features here since we don't have
// a way of figuring out their features from the invoice:
assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(6));
assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(7));
assert_eq!(route.hops[3].pubkey, node7);
assert_eq!(route.hops[3].short_channel_id, 10);
assert_eq!(route.hops[3].fee_msat, 100);
assert_eq!(route.hops[3].cltv_expiry_delta, 42);
assert_eq!(route.hops[3].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet
assert_eq!(route.hops[3].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly
}
{ // ...but still use 8 for larger payments as 6 has a variable feerate
@ -1674,26 +1780,38 @@ mod tests {
assert_eq!(route.hops[0].short_channel_id, 2);
assert_eq!(route.hops[0].fee_msat, 3000);
assert_eq!(route.hops[0].cltv_expiry_delta, (4 << 8) | 1);
assert_eq!(route.hops[0].node_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[0].channel_features.le_flags(), &id_to_feature_flags!(2));
assert_eq!(route.hops[1].pubkey, node3);
assert_eq!(route.hops[1].short_channel_id, 4);
assert_eq!(route.hops[1].fee_msat, 0);
assert_eq!(route.hops[1].cltv_expiry_delta, (6 << 8) | 1);
assert_eq!(route.hops[1].node_features.le_flags(), &id_to_feature_flags!(3));
assert_eq!(route.hops[1].channel_features.le_flags(), &id_to_feature_flags!(4));
assert_eq!(route.hops[2].pubkey, node5);
assert_eq!(route.hops[2].short_channel_id, 6);
assert_eq!(route.hops[2].fee_msat, 0);
assert_eq!(route.hops[2].cltv_expiry_delta, (11 << 8) | 1);
assert_eq!(route.hops[2].node_features.le_flags(), &id_to_feature_flags!(5));
assert_eq!(route.hops[2].channel_features.le_flags(), &id_to_feature_flags!(6));
assert_eq!(route.hops[3].pubkey, node4);
assert_eq!(route.hops[3].short_channel_id, 11);
assert_eq!(route.hops[3].fee_msat, 1000);
assert_eq!(route.hops[3].cltv_expiry_delta, (8 << 8) | 1);
// If we have a peer in the node map, we'll use their features here since we don't have
// a way of figuring out their features from the invoice:
assert_eq!(route.hops[3].node_features.le_flags(), &id_to_feature_flags!(4));
assert_eq!(route.hops[3].channel_features.le_flags(), &id_to_feature_flags!(11));
assert_eq!(route.hops[4].pubkey, node7);
assert_eq!(route.hops[4].short_channel_id, 8);
assert_eq!(route.hops[4].fee_msat, 2000);
assert_eq!(route.hops[4].cltv_expiry_delta, 42);
assert_eq!(route.hops[4].node_features.le_flags(), &Vec::new()); // We dont pass flags in from invoices yet
assert_eq!(route.hops[4].channel_features.le_flags(), &Vec::new()); // We can't learn any flags from invoices, sadly
}
{ // Test Router serialization/deserialization

View file

@ -117,7 +117,7 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
fn handle_announcement_signatures(&self, _their_node_id: &PublicKey, _msg: &msgs::AnnouncementSignatures) {}
fn handle_channel_reestablish(&self, _their_node_id: &PublicKey, _msg: &msgs::ChannelReestablish) {}
fn peer_disconnected(&self, _their_node_id: &PublicKey, _no_connection_possible: bool) {}
fn peer_connected(&self, _their_node_id: &PublicKey) {}
fn peer_connected(&self, _their_node_id: &PublicKey, _msg: &msgs::Init) {}
fn handle_error(&self, _their_node_id: &PublicKey, _msg: &msgs::ErrorMessage) {}
}