Skip to content

Conversation

@pm47
Copy link
Member

@pm47 pm47 commented Aug 25, 2021

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.

pm47 added 2 commits August 25, 2021 15:30
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.
@pm47 pm47 requested review from t-bast and thomash-acinq August 25, 2021 13:41
}

private def handleUpdateRelayFeeDisconnected(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) = {
val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, d.shortChannelId, c.cltvExpiryDelta_opt.getOrElse(d.channelUpdate.cltvExpiryDelta), d.channelUpdate.htlcMinimumMsat, c.feeBase, c.feeProportionalMillionths, d.commitments.capacity.toMilliSatoshi, enable = false)
Copy link
Member Author

Choose a reason for hiding this comment

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

It probably doesn't matter a lot, but I believe this is a bug:

Suggested change
val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, d.shortChannelId, c.cltvExpiryDelta_opt.getOrElse(d.channelUpdate.cltvExpiryDelta), d.channelUpdate.htlcMinimumMsat, c.feeBase, c.feeProportionalMillionths, d.commitments.capacity.toMilliSatoshi, enable = false)
val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, d.shortChannelId, c.cltvExpiryDelta_opt.getOrElse(d.channelUpdate.cltvExpiryDelta), d.channelUpdate.htlcMinimumMsat, c.feeBase, c.feeProportionalMillionths, d.commitments.capacity.toMilliSatoshi, enable = Announcements.isEnabled(d.channelUpdate.channelFlags))

@pm47 pm47 changed the title Send command to self to update relay fees at restore Send CMD_UPDATE_RELAY_FEES to self at restore Aug 25, 2021
log.debug("re-emitting channel_update={} enabled={} ", normal.channelUpdate, Announcements.isEnabled(normal.channelUpdate.channelFlags))
}
context.system.eventStream.publish(LocalChannelUpdate(self, normal.commitments.channelId, normal.shortChannelId, normal.commitments.remoteParams.nodeId, normal.channelAnnouncement, normal.channelUpdate, previousChannelUpdate_opt, normal.commitments))
context.system.eventStream.publish(LocalChannelUpdate(self, normal.commitments.channelId, normal.shortChannelId, normal.commitments.remoteParams.nodeId, normal.channelAnnouncement, normal.channelUpdate, Some(normal.channelUpdate), normal.commitments))
Copy link
Contributor

Choose a reason for hiding this comment

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

Here we will emit an additional outdated LocalChannelUpdate in case the config has changed.

Copy link
Contributor

@thomash-acinq thomash-acinq left a comment

Choose a reason for hiding this comment

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

Overall it looks like a clean solution.
The only downside is that it can behave differently than the current code by emitting an outdated LocalChannelUpdate. If you think it's fine, I'm OK with it. I'm not sure how this LocalChannelUpdate is used later, maybe it's not a problem to emit a bad one followed not too long after by a good one.

There should be some tests that the correct LocalChannelUpdate are emitted when we expect and won't produce duplicate rows in the channel_updates table.

Comment on lines +2137 to +2138
// we're in OFFLINE state, we don't broadcast the new update right away, we will do that when next time we go to NORMAL state
stay() using d.copy(channelUpdate = channelUpdate1) storing()
Copy link
Member Author

Choose a reason for hiding this comment

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

So... this doesn't work, as evidenced by 2c8db6e.

By using a stay() to defer the sending of the event, we lose the reference to the previous channel_update 🤦‍♂️

@pm47
Copy link
Member Author

pm47 commented Sep 2, 2021

Closed in favor of #1934

@pm47 pm47 closed this Sep 2, 2021
@pm47 pm47 deleted the channel-update-send-cmd-to-self-on-restore branch November 4, 2021 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants