-
Notifications
You must be signed in to change notification settings - Fork 268
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
Always re-send ChannelUpdate to private channels #1317
Always re-send ChannelUpdate to private channels #1317
Conversation
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 agree with the overall goal: it's cheap to send channel_update
s for unannounced channels more aggressively (as they won't be forwarded further in the network).
But your current proposal will send it way too often (every time the commitment tx is updated).
I would instead only add a re-broadcast when going OFFLINE -> NORMAL.
eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala
Outdated
Show resolved
Hide resolved
@@ -2409,9 +2409,7 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { | |||
sender.send(alice, INPUT_DISCONNECTED) | |||
assert(relayerA.expectMsgType[Status.Failure].cause.asInstanceOf[AddHtlcFailed].paymentHash === htlc1.paymentHash) | |||
assert(relayerA.expectMsgType[Status.Failure].cause.asInstanceOf[AddHtlcFailed].paymentHash === htlc2.paymentHash) | |||
val update2a = alice2bob.expectMsgType[ChannelUpdate] | |||
assert(channelUpdateListener.expectMsgType[LocalChannelUpdate].channelUpdate === update2a) | |||
assert(!Announcements.isEnabled(update2a.channelFlags)) |
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.
Looks like this was catching a superfluous ChannelUpdate
on entering into OFFLINE
state, it's not sent now.
(state, nextState, stateData, nextStateData) match { | ||
// if channel is private, we send the channel_update directly to remote on each reconnect | ||
// they need it "to learn the other end's forwarding parameters" (BOLT 7) | ||
case (NORMAL, NORMAL, d1: DATA_NORMAL, d2: DATA_NORMAL) if !d1.commitments.announceChannel && (!d1.buried && d2.buried || d1.channelUpdate != d2.channelUpdate) => |
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 that's incorrect. You still always want to wait for d2.buried
before sending a channel_update
(which isn't the case here if d1.channelUpdate != d2.channelUpdate
.
I'm a bit weary of matching now on states + data, there may be a case we're losing compared to the previous code.
Here is my take:
// if channel is private, we send the channel_update directly to remote
// they need it "to learn the other end's forwarding parameters" (BOLT 7)
(state, nextState, stateData, nextStateData) match {
case (_, _, d1: DATA_NORMAL, d2: DATA_NORMAL) if !d1.commitments.announceChannel && !d1.buried && d2.buried =>
// for a private channel, when the tx was just buried we need to send the channel_update to our peer (even if it didn't change)
forwarder ! d2.channelUpdate
case (OFFLINE, NORMAL, d1: DATA_NORMAL, d2: DATA_NORMAL) if !d1.commitments.announceChannel && d2.buried =>
// otherwise if we're coming back online, we rebroadcast the latest channel_update
// this makes sure that if the channel_update was missed, we have a chance to re-send it
forwarder ! d2.channelUpdate
case (_, _, d1: DATA_NORMAL, d2: DATA_NORMAL) if !d1.commitments.announceChannel && d1.channelUpdate != d2.channelUpdate && d2.buried =>
// otherwise, we only send it when it is different, and tx is already buried
forwarder ! d2.channelUpdate
case _ => ()
}
I believe it's safer as it keeps the existing behavior and only adds a new case when coming back online. WDYT?
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 that's incorrect.
It's less code and not sure it's strictly incorrect: NORMAL_DATA
is present so at least default 3 confirmations are there, occasional premature update at this point won't add too much risk.
But I'm also totally fine with using your code.
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.
LGTM, thanks!
Previous implementation in #1317 wasn't working because in a bug in the transition. Added a test and fixed it.
Current approach seems to be too brittle as
ChannelUpdate
is only sent once but may not reach a remote peer due to disconnect (this did happen to me).This is what other implementations (LND at least) do already, I suppose that traffic overhead of this would be minimal. If it is a concern though then perhaps a following smarter strategy could work: send
ChannelUpdate
to private channel on each reconnect until there was an incoming payment attempt (respected commit number updated in commitments?).