-
Notifications
You must be signed in to change notification settings - Fork 275
Send CMD_UPDATE_RELAY_FEES to self at restore
#1922
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -284,32 +284,20 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId | |||||
| watchFundingTx(data.commitments) | ||||||
| context.system.eventStream.publish(ShortChannelIdAssigned(self, normal.channelId, normal.channelUpdate.shortChannelId, None)) | ||||||
|
|
||||||
| // we rebuild a new channel_update with values from the configuration because they may have changed while eclair was down | ||||||
| // we check the configuration because the values for channel_update may have changed while eclair was down | ||||||
| val fees = getRelayFees(nodeParams, remoteNodeId, data.commitments) | ||||||
| val candidateChannelUpdate = Announcements.makeChannelUpdate( | ||||||
| nodeParams.chainHash, | ||||||
| nodeParams.privateKey, | ||||||
| remoteNodeId, | ||||||
| normal.channelUpdate.shortChannelId, | ||||||
| nodeParams.expiryDelta, | ||||||
| normal.commitments.remoteParams.htlcMinimum, | ||||||
| fees.feeBase, | ||||||
| fees.feeProportionalMillionths, | ||||||
| normal.commitments.capacity.toMilliSatoshi, | ||||||
| enable = Announcements.isEnabled(normal.channelUpdate.channelFlags)) | ||||||
| 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 | ||||||
| if (fees.feeBase != normal.channelUpdate.feeBaseMsat || | ||||||
| fees.feeProportionalMillionths != normal.channelUpdate.feeProportionalMillionths || | ||||||
| nodeParams.expiryDelta != normal.channelUpdate.cltvExpiryDelta) { | ||||||
| log.info("refreshing channel_update due to configuration changes") | ||||||
| self ! CMD_UPDATE_RELAY_FEE(ActorRef.noSender, fees.feeBase, fees.feeProportionalMillionths, Some(nodeParams.expiryDelta)) | ||||||
| } | ||||||
| // we need to periodically re-send channel updates, otherwise channel will be considered stale and get pruned by network | ||||||
| // we take into account the date of the last update so that we don't send superfluous updates when we restart the app | ||||||
| val periodicRefreshInitialDelay = Helpers.nextChannelUpdateRefresh(channelUpdate1.timestamp) | ||||||
| val periodicRefreshInitialDelay = Helpers.nextChannelUpdateRefresh(normal.channelUpdate.timestamp) | ||||||
| context.system.scheduler.scheduleWithFixedDelay(initialDelay = periodicRefreshInitialDelay, delay = REFRESH_CHANNEL_UPDATE_INTERVAL, receiver = self, message = BroadcastChannelUpdate(PeriodicRefresh)) | ||||||
|
|
||||||
| goto(OFFLINE) using normal.copy(channelUpdate = channelUpdate1) | ||||||
| goto(OFFLINE) using normal | ||||||
|
|
||||||
| case funding: DATA_WAIT_FOR_FUNDING_CONFIRMED => | ||||||
| watchFundingTx(funding.commitments) | ||||||
|
|
@@ -1013,12 +1001,12 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId | |||||
| } | ||||||
|
|
||||||
| case Event(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) => | ||||||
| log.info("updating relay fees: prevFeeBaseMsat={} nextFeeBaseMsat={} prevFeeProportionalMillionths={} nextFeeProportionalMillionths={}", d.channelUpdate.feeBaseMsat, c.feeBase, d.channelUpdate.feeProportionalMillionths, c.feeProportionalMillionths) | ||||||
| val channelUpdate = Announcements.makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, d.shortChannelId, d.channelUpdate.cltvExpiryDelta, d.channelUpdate.htlcMinimumMsat, c.feeBase, c.feeProportionalMillionths, d.commitments.capacity.toMilliSatoshi, enable = Helpers.aboveReserve(d.commitments)) | ||||||
| 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 = Helpers.aboveReserve(d.commitments)) | ||||||
| log.info(s"updating relay fees: prev={} next={}", d.channelUpdate.toStringShort, channelUpdate1.toStringShort) | ||||||
| val replyTo = if (c.replyTo == ActorRef.noSender) sender() else c.replyTo | ||||||
| replyTo ! RES_SUCCESS(c, d.channelId) | ||||||
| // we use GOTO instead of stay() because we want to fire transitions | ||||||
| goto(NORMAL) using d.copy(channelUpdate = channelUpdate) storing() | ||||||
| goto(NORMAL) using d.copy(channelUpdate = channelUpdate1) storing() | ||||||
|
|
||||||
| case Event(BroadcastChannelUpdate(reason), d: DATA_NORMAL) => | ||||||
| val age = System.currentTimeMillis.milliseconds - d.channelUpdate.timestamp.seconds | ||||||
|
|
@@ -1542,18 +1530,11 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId | |||||
| // -> in CLOSING we either have mutual closed (so no more htlcs), or already have unilaterally closed (so no action required), and we can't be in OFFLINE state anyway | ||||||
| case Event(ProcessCurrentBlockCount(c), d: HasCommitments) => handleNewBlock(c, d) | ||||||
|
|
||||||
| case Event(c: CurrentFeerates, d: HasCommitments) => | ||||||
| handleOfflineFeerate(c, d) | ||||||
| case Event(c: CurrentFeerates, d: HasCommitments) => handleCurrentFeerateDisconnected(c, d) | ||||||
|
|
||||||
| case Event(c: CMD_ADD_HTLC, d: DATA_NORMAL) => handleAddDisconnected(c, d) | ||||||
|
|
||||||
| case Event(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) => | ||||||
| log.info(s"updating relay fees: prevFeeBaseMsat={} nextFeeBaseMsat={} prevFeeProportionalMillionths={} nextFeeProportionalMillionths={}", d.channelUpdate.feeBaseMsat, c.feeBase, d.channelUpdate.feeProportionalMillionths, c.feeProportionalMillionths) | ||||||
| val channelUpdate = Announcements.makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, d.shortChannelId, d.channelUpdate.cltvExpiryDelta, d.channelUpdate.htlcMinimumMsat, c.feeBase, c.feeProportionalMillionths, d.commitments.capacity.toMilliSatoshi, enable = false) | ||||||
| val replyTo = if (c.replyTo == ActorRef.noSender) sender() else c.replyTo | ||||||
| replyTo ! RES_SUCCESS(c, d.channelId) | ||||||
| // 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 = channelUpdate) storing() | ||||||
| case Event(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) => handleUpdateRelayFeeDisconnected(c, d) | ||||||
|
|
||||||
| case Event(getTxResponse: GetTxWithMetaResponse, d: DATA_WAIT_FOR_FUNDING_CONFIRMED) if getTxResponse.txid == d.commitments.commitInput.outPoint.txid => handleGetFundingTx(getTxResponse, d.waitingSinceBlock, d.fundingTx) | ||||||
|
|
||||||
|
|
@@ -1692,6 +1673,8 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId | |||||
|
|
||||||
| case Event(c: CMD_ADD_HTLC, d: DATA_NORMAL) => handleAddDisconnected(c, d) | ||||||
|
|
||||||
| case Event(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) => handleUpdateRelayFeeDisconnected(c, d) | ||||||
|
|
||||||
| case Event(channelReestablish: ChannelReestablish, d: DATA_SHUTDOWN) => | ||||||
| var sendQueue = Queue.empty[LightningMessage] | ||||||
| val (commitments1, sendQueue1) = handleSync(channelReestablish, d) | ||||||
|
|
@@ -1734,8 +1717,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId | |||||
|
|
||||||
| case Event(ProcessCurrentBlockCount(c), d: HasCommitments) => handleNewBlock(c, d) | ||||||
|
|
||||||
| case Event(c: CurrentFeerates, d: HasCommitments) => | ||||||
| handleOfflineFeerate(c, d) | ||||||
| case Event(c: CurrentFeerates, d: HasCommitments) => handleCurrentFeerateDisconnected(c, d) | ||||||
|
|
||||||
| case Event(getTxResponse: GetTxWithMetaResponse, d: DATA_WAIT_FOR_FUNDING_CONFIRMED) if getTxResponse.txid == d.commitments.commitInput.outPoint.txid => handleGetFundingTx(getTxResponse, d.waitingSinceBlock, d.fundingTx) | ||||||
|
|
||||||
|
|
@@ -1879,24 +1861,23 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId | |||||
| case _ => () | ||||||
| } | ||||||
|
|
||||||
| val previousChannelUpdate_opt = stateData match { | ||||||
| case data: DATA_NORMAL => Some(data.channelUpdate) | ||||||
| case _ => None | ||||||
| } | ||||||
|
|
||||||
| (state, nextState, stateData, nextStateData) match { | ||||||
| // ORDER MATTERS! | ||||||
| case (WAIT_FOR_INIT_INTERNAL, OFFLINE, _, normal: DATA_NORMAL) => | ||||||
| Logs.withMdc(diagLog)(Logs.mdc(category_opt = Some(Logs.LogCategory.CONNECTION))) { | ||||||
| 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)) | ||||||
| case (_, _, d1: DATA_NORMAL, d2: DATA_NORMAL) if d1.channelUpdate == d2.channelUpdate && d1.channelAnnouncement == d2.channelAnnouncement => | ||||||
| // don't do anything if neither the channel_update nor the channel_announcement didn't change | ||||||
| () | ||||||
| case (WAIT_FOR_FUNDING_LOCKED | NORMAL | OFFLINE | SYNCING, NORMAL | OFFLINE, _, normal: DATA_NORMAL) => | ||||||
| // when we do WAIT_FOR_FUNDING_LOCKED->NORMAL or NORMAL->NORMAL or SYNCING->NORMAL or NORMAL->OFFLINE, we send out the new channel_update (most of the time it will just be to enable/disable the channel) | ||||||
| log.info("emitting channel_update={} enabled={} ", normal.channelUpdate, Announcements.isEnabled(normal.channelUpdate.channelFlags)) | ||||||
| val previousChannelUpdate_opt = stateData match { | ||||||
| case data: DATA_NORMAL => Some(data.channelUpdate) | ||||||
| case _ => None | ||||||
| } | ||||||
| context.system.eventStream.publish(LocalChannelUpdate(self, normal.commitments.channelId, normal.shortChannelId, normal.commitments.remoteParams.nodeId, normal.channelAnnouncement, normal.channelUpdate, previousChannelUpdate_opt, normal.commitments)) | ||||||
| case (_, _, _: DATA_NORMAL, _: DATA_NORMAL) => | ||||||
| // in any other case (e.g. OFFLINE->SYNCING) we do nothing | ||||||
|
|
@@ -1995,7 +1976,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId | |||||
| * @param d the channel commtiments | ||||||
| * @return | ||||||
| */ | ||||||
| private def handleOfflineFeerate(c: CurrentFeerates, d: HasCommitments) = { | ||||||
| private def handleCurrentFeerateDisconnected(c: CurrentFeerates, d: HasCommitments) = { | ||||||
| val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(remoteNodeId, d.commitments.channelFeatures, d.commitments.capacity, Some(c)) | ||||||
| val currentFeeratePerKw = d.commitments.localCommit.spec.feeratePerKw | ||||||
| // if the network fees are too high we risk to not be able to confirm our current commitment | ||||||
|
|
@@ -2148,6 +2129,15 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| 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) | ||||||
|
Member
Author
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. It probably doesn't matter a lot, but I believe this is a bug:
Suggested change
|
||||||
| log.info(s"updating relay fees: prev={} next={}", d.channelUpdate.toStringShort, channelUpdate1.toStringShort) | ||||||
| val replyTo = if (c.replyTo == ActorRef.noSender) sender() else c.replyTo | ||||||
| replyTo ! RES_SUCCESS(c, d.channelId) | ||||||
| // 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() | ||||||
|
Comment on lines
+2137
to
+2138
Member
Author
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. So... this doesn't work, as evidenced by 2c8db6e. By using a |
||||||
| } | ||||||
|
|
||||||
| private def handleNewBlock(c: CurrentBlockCount, d: HasCommitments) = { | ||||||
| val timedOutOutgoing = d.commitments.timedOutOutgoingHtlcs(c.blockCount) | ||||||
| val almostTimedOutIncoming = d.commitments.almostTimedOutIncomingHtlcs(c.blockCount, nodeParams.fulfillSafetyBeforeTimeout) | ||||||
|
|
||||||
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.
Here we will emit an additional outdated LocalChannelUpdate in case the config has changed.