-
Notifications
You must be signed in to change notification settings - Fork 407
Do not always persist ChannelManager on channel_update messages #972
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -632,7 +632,7 @@ const CHECK_CLTV_EXPIRY_SANITY: u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRA | |
const CHECK_CLTV_EXPIRY_SANITY_2: u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - 2*CLTV_CLAIM_BUFFER; | ||
|
||
/// Details of a channel, as returned by ChannelManager::list_channels and ChannelManager::list_usable_channels | ||
#[derive(Clone)] | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub struct ChannelDetails { | ||
/// The channel's ID (prior to funding transaction generation, this is a random 32 bytes, | ||
/// thereafter this is the txid of the funding transaction xor the funding transaction output). | ||
|
@@ -3346,14 +3346,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana | |
Ok(()) | ||
} | ||
|
||
fn internal_channel_update(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelUpdate) -> Result<(), MsgHandleErrInternal> { | ||
/// Returns ShouldPersist if anything changed, otherwise either SkipPersist or an Err. | ||
fn internal_channel_update(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelUpdate) -> Result<NotifyOption, MsgHandleErrInternal> { | ||
let mut channel_state_lock = self.channel_state.lock().unwrap(); | ||
let channel_state = &mut *channel_state_lock; | ||
let chan_id = match channel_state.short_to_id.get(&msg.contents.short_channel_id) { | ||
Some(chan_id) => chan_id.clone(), | ||
None => { | ||
// It's not a local channel | ||
return Ok(()) | ||
return Ok(NotifyOption::SkipPersist) | ||
} | ||
}; | ||
match channel_state.by_id.entry(chan_id) { | ||
|
@@ -3363,15 +3364,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana | |
// If the announcement is about a channel of ours which is public, some | ||
// other peer may simply be forwarding all its gossip to us. Don't provide | ||
// a scary-looking error message and return Ok instead. | ||
return Ok(()); | ||
return Ok(NotifyOption::SkipPersist); | ||
} | ||
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a channel_update for a channel from the wrong node - it shouldn't know about our private channels!".to_owned(), chan_id)); | ||
} | ||
try_chan_entry!(self, chan.get_mut().channel_update(&msg), channel_state, chan); | ||
}, | ||
hash_map::Entry::Vacant(_) => unreachable!() | ||
} | ||
Ok(()) | ||
Ok(NotifyOption::DoPersist) | ||
} | ||
|
||
fn internal_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) -> Result<(), MsgHandleErrInternal> { | ||
|
@@ -4116,8 +4117,13 @@ impl<Signer: Sign, M: Deref , T: Deref , K: Deref , F: Deref , L: Deref > | |
} | ||
|
||
fn handle_channel_update(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelUpdate) { | ||
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); | ||
let _ = handle_error!(self, self.internal_channel_update(counterparty_node_id, msg), *counterparty_node_id); | ||
PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock, &self.persistence_notifier, || { | ||
if let Ok(persist) = handle_error!(self, self.internal_channel_update(counterparty_node_id, msg), *counterparty_node_id) { | ||
persist | ||
} else { | ||
NotifyOption::SkipPersist | ||
} | ||
}); | ||
} | ||
|
||
fn handle_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) { | ||
|
@@ -4823,6 +4829,9 @@ mod tests { | |
use core::sync::atomic::{AtomicBool, Ordering}; | ||
use std::thread; | ||
use core::time::Duration; | ||
use ln::functional_test_utils::*; | ||
use ln::features::InitFeatures; | ||
use ln::msgs::ChannelMessageHandler; | ||
|
||
#[test] | ||
fn test_wait_timeout() { | ||
|
@@ -4865,6 +4874,53 @@ mod tests { | |
} | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_notify_limits() { | ||
valentinewallace marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Check that a few cases which don't require the persistence of a new ChannelManager, | ||
// indeed, do not cause the persistence of a new ChannelManager. | ||
let chanmon_cfgs = create_chanmon_cfgs(3); | ||
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); | ||
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); | ||
let nodes = create_network(3, &node_cfgs, &node_chanmgrs); | ||
|
||
let mut chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); | ||
|
||
// We check that the channel info nodes have doesn't change too early, even though we try | ||
// to connect messages with new values | ||
chan.0.contents.fee_base_msat *= 2; | ||
chan.1.contents.fee_base_msat *= 2; | ||
let node_a_chan_info = nodes[0].node.list_channels()[0].clone(); | ||
let node_b_chan_info = nodes[1].node.list_channels()[0].clone(); | ||
|
||
// The first two nodes (which opened a channel) should now require fresh persistence | ||
assert!(nodes[0].node.await_persistable_update_timeout(Duration::from_millis(1))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if by design, but don't think this test covers the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what I'm looking at there, but if not that's a bug - There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just meant that the test doesn't cover the case where we do want to persist after handling a channel update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, yes, sorry. As I was writing the test I found another bug, so the test is finished in the last commit at #949. |
||
assert!(nodes[1].node.await_persistable_update_timeout(Duration::from_millis(1))); | ||
// ... but the last node should not. | ||
assert!(!nodes[2].node.await_persistable_update_timeout(Duration::from_millis(1))); | ||
// After persisting the first two nodes they should no longer need fresh persistence. | ||
assert!(!nodes[0].node.await_persistable_update_timeout(Duration::from_millis(1))); | ||
assert!(!nodes[1].node.await_persistable_update_timeout(Duration::from_millis(1))); | ||
|
||
// Node 3, unrelated to the only channel, shouldn't care if it receives a channel_update | ||
// about the channel. | ||
nodes[2].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan.0); | ||
nodes[2].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &chan.1); | ||
assert!(!nodes[2].node.await_persistable_update_timeout(Duration::from_millis(1))); | ||
|
||
// The nodes which are a party to the channel should also ignore messages from unrelated | ||
// parties. | ||
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan.0); | ||
nodes[0].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan.1); | ||
nodes[1].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan.0); | ||
nodes[1].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &chan.1); | ||
assert!(!nodes[0].node.await_persistable_update_timeout(Duration::from_millis(1))); | ||
assert!(!nodes[1].node.await_persistable_update_timeout(Duration::from_millis(1))); | ||
|
||
// At this point the channel info given by peers should still be the same. | ||
assert_eq!(nodes[0].node.list_channels()[0], node_a_chan_info); | ||
assert_eq!(nodes[1].node.list_channels()[0], node_b_chan_info); | ||
} | ||
} | ||
|
||
#[cfg(all(any(test, feature = "_test_utils"), feature = "unstable"))] | ||
|
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.
Instead of implementing
PartialEq
, test thatfee_base_msat
hasn't changed.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.
I think its generally a good thing to have either way - its a public struct and its reasonable for users to want to compare it? If you disagree we can change it in a followup.