mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 23:08:36 +01:00
Merge pull request #433 from TheBlueMatt/2019-12-features-in-routes
Plumb Features through into Routes
This commit is contained in:
commit
c991643746
12 changed files with 332 additions and 108 deletions
|
@ -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;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
},
|
||||
),
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue