-
Notifications
You must be signed in to change notification settings - Fork 407
Implement checks amt_to_forward and outgoing_cltv_value acceptable ranges #114
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
Implement checks amt_to_forward and outgoing_cltv_value acceptable ranges #114
Conversation
Looks like maybe the fake network tests are violating the rules somehow? |
4b2281d
to
a5a1f7e
Compare
Yeah, it's the 6th send_payment in fake_network_test with a channel_outbound increase. I'm still digging to see if this case is right handle by get_route to generate first hop amount_msat.. |
Looking on how others implementations manage get_our_fee_base_msat, spec is unclear on what is the right way to do it. |
a5a1f7e
to
90d6260
Compare
Was a funny one to track :) I wouldn't have fall on this if we didn't used get_our_fee_base_msat, I find it a little bit complex due to the channel_outbound case but I guess it's better than a magic default value of 1000 msat as lnd and c-lightning do. 90d626 is log stuff for NetworkMap, really useful for route bug tracking , but it's need network map fields as public so maybe not? |
src/ln/router.rs
Outdated
htlc_minimum_msat: u64, | ||
fee_base_msat: u32, | ||
fee_proportional_millionths: u32, | ||
pub struct DirectionalChannelInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These probably want pub(crate), not pub, and maybe a comment that they're only crate-pub for the logger's access.
src/ln/channelmanager.rs
Outdated
@@ -1625,7 +1625,18 @@ impl ChannelMessageHandler for ChannelManager { | |||
hmac: next_hop_data.hmac.clone(), | |||
}; | |||
|
|||
//TODO: Check amt_to_forward and outgoing_cltv_value are within acceptable ranges! | |||
let channel_state = self.channel_state.lock().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, can you move this check down past the existing channel_state.lock() call? It really sucks to lock, do a channel lookup, check something, unlock, then lock and do the same channel lookup again. That's likely to introduce strange races as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, but it's add a check to prevent the case of the HTLC being our payment
src/ln/router.rs
Outdated
$target.htlc_minimum_msat = msg.contents.htlc_minimum_msat; | ||
$target.fee_base_msat = msg.contents.fee_base_msat; | ||
$target.fee_proportional_millionths = msg.contents.fee_proportional_millionths; | ||
chan_was_enabled = $first_side.enabled; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice debugging, but sadly I think you came to the wrong conclusion. The way I read the second paragraph in https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#the-channel_update-message reads to me like the original code here is correct and the issue is in the new check - fees/cltv_deltas are announced on the basis of the channel where the HTLC will be forwarded to, not the basis of which channel the HTLC came in on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah but seems that my code follows rfc 07 fee calculation : fee_base_msat + ( amount_msat * fee_proportional_millionths / 1000000 ) and the rfc 04 check : incoming_htlc_amt - fee >= amt_to_forward ? The amounts don't match as seen there, running cargo test fake_network_test -- --no-capture on my demo_bug_channelinfo_handling
branch : https://0bin.net/paste/lixegfyl2cDb+n25#B9BdwQDf4pqNYa5S4dZuK6i1ZGM+OQMYqjIcMgSuilW
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, fees/cltv_deltas are based on the receiving node policy where the HTLC will be forwarded to, the issue is on the way handle_channel_update is recording the channel_update as one_to_two or two_to_one. When the node is one, and uses the one_to_two side, it has to use the two_to_one directional info and so the receiving node policy. That's this policy in ChannelInfo, i think, is inverted now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The information going into the channels map here looks right to me - its setting the fees on a channel on the entry that represents the outgoing hop (as indicated by it being the side with the src_node_id being equal to the node which signed the message). In order to be calculating the fee on the basis of where the payment is being forwarded to (ie if you route A -> B -> C, the fees paid are the ones that B announced for the B -> C hop) you'd need to change the check that was added to update_add_htlc.
src/util/macro_logger.rs
Outdated
Ok(()) | ||
} | ||
} | ||
macro_rules! log_networkmap { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are really awesome, but it sucks to add unused code cause it generates way more compile warnings. Honestly its probably worth adding a pub fn Router::log_network function to keep these around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use [allow(dead_code)] and [allow(unused_macros], seems that these attributes been there for avoid lint warnings ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just adding allow(dead_code) doesn't resolve the issue - the point is that code should be used or it won't be kept up-to-date and probably doesn't belong in the repo at all.
4762f02
to
65d8210
Compare
travis failures on fuzz part due to amount in/out fee required mismatch, what is test:test_no_existing_test_breakage? it's calling handle_update_add_htlc somewhere? |
65d8210
to
bfce91c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new full_stack_target test tests that existing fuzz test cases aren't broken by changes in behavior. This is mostly for my tracking so I know what bits to not take until I want to restart fuzzing on all new test-cases. It will break generally when you add new feerate requests and new checks like this. If you don't feel like fiing the test case that's written out there that's find, I'd generally be fine merging things that comment it out and then fixing it myself.
There is another issue here that I forgot about - if we let routing fees charged float with network fees (which I think is prudent, but may be more complexity than its worth) then we have to pay close attention to when those fees change and send channel_update messages when the feerate info causes us to change our feerate, which is hopefully not too often.
src/ln/channelmanager.rs
Outdated
{ | ||
if next_hop_data.hmac != [0;32] { | ||
// check doesn't apply if we are last node (check happens here due to lock optimizations) | ||
let chan = channel_state_lock.by_id.get(&msg.channel_id).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still wrong - we should be doing the fee checks against the place we're sending the payment (ie pending_forward_info.short_channel_id ie the channel that is looked up in the next if statement.
src/ln/router.rs
Outdated
$target.htlc_minimum_msat = msg.contents.htlc_minimum_msat; | ||
$target.fee_base_msat = msg.contents.fee_base_msat; | ||
$target.fee_proportional_millionths = msg.contents.fee_proportional_millionths; | ||
chan_was_enabled = $first_side.enabled; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The information going into the channels map here looks right to me - its setting the fees on a channel on the entry that represents the outgoing hop (as indicated by it being the side with the src_node_id being equal to the node which signed the message). In order to be calculating the fee on the basis of where the payment is being forwarded to (ie if you route A -> B -> C, the fees paid are the ones that B announced for the B -> C hop) you'd need to change the check that was added to update_add_htlc.
9ff8238
to
50bcfda
Compare
Aaaaah finally got it! After reading again and scrupulously this time the rfcs and lnd, c-lightning codes! Sorry for the lost time, i was perpexled at first i think by the channel_outbound estimation thing case and from then, misjudged all the rest.. At least i've seen the Router internals. For the routing fees coupled on network fees I think that's an issue with FeeEstimator implementation to avoid too much channel_update messages. We should warn it to have an update limit for a given window time and not necessarily to echo all network fees moves (but don't know algorithm fees so surely harder to implement than to describe I guess). |
I commented out the new fuzzing case, will dig into the fuzz tools and set it up on my environnement soon, need to understand this too |
src/ln/channelmanager.rs
Outdated
@@ -1656,6 +1654,20 @@ impl ChannelMessageHandler for ChannelManager { | |||
Some(id) => id.clone(), | |||
}; | |||
let chan = channel_state.by_id.get_mut(&forwarding_id).unwrap(); | |||
let fee = 0; | |||
if next_hop_data.hmac != [0;32] { | |||
let fee = chan.get_our_fee_base_msat(&*self.fee_estimator) + (pending_forward_info.amt_to_forward * self.fee_proportional_millionths as u64 / 1000000) as u32; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because you have a "let" here, fee is always 0 in the next if statement. Also, the pending_forward_info.onion_packet.is_some() check above is duplicative with this - if next_hop_data.hmac is 0s onion_packet is always None.
src/ln/router.rs
Outdated
fee_base_msat: u32, | ||
fee_proportional_millionths: u32, | ||
//Here, DirectionalChannelInfo, ChannelInfo, NodeInfo and NetworkMap are pub(crate) only for log_* macros access | ||
pub(crate) struct DirectionalChannelInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, it seems weird to put the logger in log macros and then expose all these things, maybe just implement Display for these types directly instead of going through the indirection?
acceptable ranges add log_route macro
50bcfda
to
8462362
Compare
Updated, with Display trait on networkmap structs. |
Cool, thanks, will take as #125. |
Just implemented checks as described in rfc 04 Packet structure. Maybe we should check also against an older fee value as recommended in rfc 07 due to propagation delay, but if so need to log old fee somewhere?