Skip to content

Add default implementation for tracking metadata #636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion lightning/src/routing/network_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use chain::chaininterface::{ChainError, ChainWatchInterface};
use ln::features::{ChannelFeatures, NodeFeatures};
use ln::msgs::{DecodeError,ErrorAction,LightningError,RoutingMessageHandler,NetAddress};
use ln::msgs;
use routing::router::RouteHop;
use util::ser::{Writeable, Readable, Writer};
use util::logger::Logger;

Expand Down Expand Up @@ -278,7 +279,6 @@ impl_writeable!(ChannelInfo, 0, {
announcement_message
});


/// Fees for routing via a given channel or a node
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct RoutingFees {
Expand Down Expand Up @@ -428,6 +428,64 @@ impl Readable for NodeInfo {
}
}

/// Allows for updating user's network metadata.
pub trait RouteFeePenalty {
/// Gets a channel's fee penalty based on its channel_id (as stored in a NetworkGraph object).
fn get_channel_fee_penalty(&self, chan_id: u64) -> Option<&u64>;
/// Informs metadata object that a route has successfully executed its payment.
fn route_succeeded(&mut self, route: Vec<RouteHop>);
}

/// A default metadata object that is used to implement the default functionality for the
/// NetworkTracker trait. A user could make their own Metadata object and extend the
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a question of code sharing here, if people start to work on fancy scoring logic, they may want to combine them, and having each of them implement a custom UpdateMetadata they won't be able to do so.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why? You could write a combiner, but ultimately we have to have a way to linearize any kind of fancy scoring logic users want into one parameter (namely fee paid) so that we can calculate a route based on it. No matter what users do, they have to be able to linearize it.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think we agree on the need to linearize it, my point was more on dissociating linearization method (get_channel_fee_penalty) from score-feeding ones (route_succeeded/route_failed). Linearization one should be on such combiner. I don't think we have to do this now, but we may have to introduce such combiner in the future.

/// functionality of it by implementing other functions/traits for their metadata.
pub struct DefaultMetadata {
/// A lits of failed channels. Maps channel_id (as specified in the NetworkGraph object) to
/// the number of successful routes to participate before being removed from the list. All
/// channels in failed_channels are assumed to have a penalty of u64::max.
failed_channels: BTreeMap<u64, u64>,
}

impl RouteFeePenalty for DefaultMetadata {
fn get_channel_fee_penalty(&self, chan_id: u64) -> Option<&u64> {
if self.failed_channels.get(&chan_id) == None {
return Some(&0);
} else {
return Some(&u64::MAX);
}
}
fn route_succeeded(&mut self, route: Vec<RouteHop>) {
for route_hop in route {
let chan_id = route_hop.short_channel_id;
let successes_needed = self.failed_channels.get(&chan_id);
if successes_needed == None {
self.failed_channels.insert(chan_id, 5);
} else {
let dec_successes_needed = successes_needed.unwrap() - 1;
if dec_successes_needed > 0 {
self.failed_channels.insert(chan_id, dec_successes_needed);
} else {
self.failed_channels.remove(&chan_id);
}
}
}
}
}

/// Users store custom metadata about the network separately. This trait is implemented by users, who may use
/// the NetworkGraph to update whatever metadata they are storing about their view of the network.
pub trait NetworkTracker<T: RouteFeePenalty = DefaultMetadata> {
/// Return score for a given channel by using user-defined channel_scorers
fn calculate_minimum_fee_penalty_for_channel(&self, chan_id: u64, network_metadata: T) -> u64 {
let chan_score = network_metadata.get_channel_fee_penalty(chan_id);
if chan_score != None {
return *chan_score.unwrap();
} else {
return 0;
}
}
}

/// Represents the network as nodes and channels between them
#[derive(PartialEq)]
pub struct NetworkGraph {
Expand Down