-
Notifications
You must be signed in to change notification settings - Fork 266
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
Fix duplicate channel_updates in auditDb when restarting #1918
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.
This is a dangerous change, because it impacts downstream components and how we re-emit channel_update
s to our peers, which may lead to spec violations if we make a mistake.
eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala
Outdated
Show resolved
Hide resolved
(state, nextState, stateData, nextStateData) match { | ||
// ORDER MATTERS! | ||
case (WAIT_FOR_INIT_INTERNAL, OFFLINE, _, normal: DATA_NORMAL) => | ||
// LocalChannelUpdate is already published when restoring the channel |
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 preferred having it here, it was clearer when it was explicitly done in the transition phases...we've spent a lot of time ensuring the retransmit logic worked properly, I'd avoid changing that.
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 understand but the problem is that at this place we don't have enough information to know if the channel update changed or not.
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've added a channelUpdateBeforeRestore_opt
in DATA_NORMAL
so that we have access to it in the transition function and put everything back there.
eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelEvents.scala
Outdated
Show resolved
Hide resolved
I still don't get what caused the issue precisely. Didn't the following code ensure that we wouldn't emit duplicate updates? val channelUpdate1 = if (Announcements.areSame(candidateChannelUpdate, normal.channelUpdate)) {
// if there was no configuration change we keep the existing channel update
normal.channelUpdate
} else {
log.info("refreshing channel_update due to configuration changes old={} new={}", normal.channelUpdate, candidateChannelUpdate)
candidateChannelUpdate
} |
This code only reuses the previous channel update if it is still valid. But after that, without knowing what was the previous update we can't know if it has changed or not. |
Codecov Report
@@ Coverage Diff @@
## master #1918 +/- ##
==========================================
+ Coverage 87.52% 87.74% +0.22%
==========================================
Files 159 159
Lines 12104 12103 -1
Branches 502 506 +4
==========================================
+ Hits 10594 10620 +26
+ Misses 1510 1483 -27
|
eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala
Show resolved
Hide resolved
Here is an idea. We move the "update This has the following benefits:
OTOH, it also means that we would run this code at each reconnection. |
This would emit an additional |
Only if the conf changes, right? Alternatively, instead of updating the
That is a more risky change, even if sending a |
Yes, only if it changes. And in that case it will emit a first channel update that is outdated and then the correct one. If we want to not change the current flow between states, I think adding |
I've tried multiple ways doesn't seem possible to make it work by updating the channelUpdate in the SYNCING state. |
This is an alternative to #1918 and #1920. It's very close to the latter, except that we do check the conf only once in the `WAIT_FOR_INIT_INTERNAL` state, as opposed to at each reconnection in `SYNCING`. We do not change the `channel_update` in `WAIT_FOR_INIT_INTERNAL`, which allows us to set `previousChannelUpdate_opt=Some(normal.channelUpdate)` in the transition and fix the duplicate bug in the audit db. If there is a change in conf, there will be an additional `LocalChannelUpdate` emitted, but only at reconnection, and following the regular update flow, which should protect us against regressions. We do handle `CMD_UPDATE_RELAY_FEES` in both `OFFLINE` and `SYNCING`, because there may be a race between `CMD_UPDATE_RELAY_FEES` and `ChannelRestablish` if the conf change at restore. And there was no good reason to behave differently in those states anyway.
This is very similar to #1918 (ef31de1), but we use the internal actor state instead of the `ChannelData`. Pros: - conceptually simple, low risk of regression - `ChannelData` stays untouched Cons: - now there is a `var` in the channel Those are the minimal changes to have the simplest diff, but we can include some improvements made in ef31de1.
Because the previous channel update is never part of the channel state when restarting eclair, we always think that they have changed and add them to the database.
We now check that the channel update has changed when restoring it.