Delay considering a channel closed when seeing an on-chain spend#2936
Conversation
|
@thomash-acinq how do you think a splice should change the low/high bounds estimate for a graph edge? This PR currenty increases the 'high' for the edge by the amount a spliced channel's capacity increases and decrease the 'low' for the edge by the amount it's capacity decreases. Is that correct? I tried to copy the logic used currently when an channel is added or removed, but only for the change in capacity instead of the entire channel's capacity. |
That looks good. |
5fbb4a9 to
d1109fa
Compare
929f85d to
2637de3
Compare
2637de3 to
4e713a3
Compare
|
I refactored Now Each spending tx will be watched until it has 12 confirmations (2 x the depth of a validated node announcement). I do not think we need a new config parameter for this. If we do add a new parameter, then it should never be less than 12 blocks to ensure that any channel announcement for a splice has time to confirm. If a spending tx confirms after 12 blocks without a channel announcement being validated for the spending tx, then the normal flow for removing a channel occurs. If a channel announcement is validated before the spending tx has 12 confirmations, then a new flow for updating the graph for a splice occurs. When a spending tx confirms to remove or splice a channel, then all |
t-bast
left a comment
There was a problem hiding this comment.
I haven't fully reviewed the tests yet, but the implementation looks good to me, my comments are mostly nit! Can you rebase after addressing my comments, and then we'll work on finalizing the tests and merging this?
Issue ACINQ#2437 When an external channel is spent, add it to the `spentChannels` list instead of immediately removing it from the graph. RBF attempts can produce multiple spending txs in the mempool for the same channel. The `spendChannels` list maps the txid of the spending tx to the scid of the spent channel. When a channel announcement is validated with a funding tx on the `spentChannels` list, consider the new channel a splice of the corresponding spent channel. A splice updates the graph edges to preserve balance estimate information in the graph. If a spending tx from the `spentChannels` list is deeply buried before appearing in a valid channel announcement, remove the corresponding spent channel edge from the graph. Also remove any corresponding spending tx entries on the `spentChannels` list.
Also fixed two other issues: - add the splice channel to the routing graph as a new channel if the parent channel does not exist (could be pruned) - when a splice confirms, also send ChannelLost to remove the parent scid from the FrontRouter
4e713a3 to
43a486e
Compare
53215cf to
e79c65b
Compare
There was a problem hiding this comment.
This is looking mostly good, I need to spend a bit more time on tests. I've added a commit here with fixes for my comments: e85512b
I haven't fully fixed the tests though to expect the new commands sent to the watcher, I'll let you fix that!
We unwatch: - channels that have been spliced or closed - RBF candidates of a splice or closing transaction We revert the modification to channel updates to avoid invalidating the signature.
- Fixup so Router does not send `UnwatchTxConfirmed` only for the spending txs that will never confirm. Channel also has a `WatchTxConfirmed` event that may trigger later and should not be removed. - Fixup channel integration tests to generate enough blocks to deeply confirm a channel has closed once before waiting for the channel to close. - Fixup router tests to check that funding tx spend is unwatched after it's spending tx confirms
03c5629 to
007adc5
Compare
- fix the three places I missed for generating blocks to create deeply confirmed closing txs - improved how the router looks for UnwatchedExternalSpent message to lookup the txid from the scid - changed the comment in Validation be more clear
t-bast
left a comment
There was a problem hiding this comment.
LGTM, let's see if the e2e integration tests find any issues, but otherwise this should be ready to merge.
- I am not sure yet why the Router does not update the scid/capacity after the splice.
- when the Router receives a AvailableBalanceChanged after a splice it now updates the capacity of the channel to the current capacity of the latest commitment.
And fix test.
- This test demonstrates that local channels update their capacity, but we can not test the remote node (carol) because the ChannelAnnouncement is ignored because it has a duplicate scid. After PR ACINQ#2941 we can fix this test.
- remove commit.md
- the spent output should match the whole Outpoint of the funding tx
|
Out of curiosity, what's the motivation for tracking channels across splicing (rather than treating them as new channels)? The two reasons I can think of are:
I'm also a little confused about the update to the low/high balance information. Based on a skim of the code, it looks to me like balance information for both splice-ins and splice-outs is being updated as soon as a splice is detected, but that's not what I expect. When we detect a splice-out (a decrease in capacity), that should be immediately reflected. When we detect a splice-in (an increase in capacity), that shouldn't be reflected until confirmed to a reasonable depth (since sane nodes won't allow forwarding HTLCs with that additional capacity until then). |
|
The two reasons you're mentioning are exactly the reasons why we're doing this:
You are correct, this is the expected behavior. This is actually what happens here, because we use |
Sounds like you got it. Sorry for sounding concerned! Thanks for the great reply, and to you all for adding this nice feature! |
When an external channel is spent, we don't immediately remove it from our network graph in case the spending transaction is a splice (see lightning/bolts#1270 for more details). A side-effect of this change, introduced in #2936, is that when we start watching a channel after receiving its `channel_announcement`, we will scan the blockchain if it is actually already spent. This can be expensive if peers send us `channel_announcement`s for channels that have been spent a long time ago since `bitcoind` doesn't provide an index for spending transactions. It is also misleading, because if we give up after scanning X blocks of the blockchain, we will create a log line saying that funds are at risk: they're never at risk since those are not our channels. This commit fixes this issue by only checking whether the channel is already spent by a confirmed transaction or not when setting the watch (which is an inexpensive and efficient RPC call to `bitcoind`), without scanning the blockchain to find the spending transaction. If it is already spent, we immediately remove it from our network graph, even if the spending transaction was actually a splice. This is fine, since that channel will be re-added to our graph whenever we receive the `channel_announcement` for the splice. In the worst case, we will simply not route through an actually available channels for a few blocks while its splice transaction is confirming.
When an external channel is spent, we don't immediately remove it from our network graph in case the spending transaction is a splice (see lightning/bolts#1270 for more details). A side-effect of this change, introduced in #2936, is that when we start watching a channel after receiving its `channel_announcement`, we will scan the blockchain if it is actually already spent. This can be expensive if peers send us `channel_announcement`s for channels that have been spent a long time ago since `bitcoind` doesn't provide an index for spending transactions. It is also misleading, because if we give up after scanning X blocks of the blockchain, we will create a log line saying that funds are at risk: they're never at risk since those are not our channels. This commit fixes this issue by only checking whether the channel is already spent by a confirmed transaction or not when setting the watch (which is an inexpensive and efficient RPC call to `bitcoind`), without scanning the blockchain to find the spending transaction. If it is already spent, we immediately remove it from our network graph, even if the spending transaction was actually a splice. This is fine, since that channel will be re-added to our graph whenever we receive the `channel_announcement` for the splice. In the worst case, we will simply not route through an actually available channels for a few blocks while its splice transaction is confirming. Co-authored-by: pm47 <pm.padiou@gmail.com>
See issue #2437
When an external channel is spent, the router will add it to a new
spentChannelsmap instead of immediately removing it from the graph.If after 12 blocks an entry in the
spentChannelsmap is not part of a splice, it will be removed as before.When a newly added channel is validated, if it spends the shared output of a recently spent channel then it is a splice.
A splice will update the
shortChannelIdandcapacityof graph edges of the parent channel instead of removing the parent's edges and adding edges for a new channel. A splice will also reuse and adjust the parent edge's low/high balance bounds information based on the splice.