ElementsProject / lightning

Core Lightning — Lightning Network implementation focusing on spec compliance and performance
Other
2.85k stars 902 forks source link

High-level API for feebumping channel funding #4971

Open ZmnSCPxj opened 2 years ago

ZmnSCPxj commented 2 years ago

While we now have a openchannel_bump command that lets channel opening attempts to be feebumped, the API is low-level and requires a fair amount of handling at the caller.

Let me propose some changes to fundchannel/multifundchannel, as well as new APIs listfundchannels, bumpfundchannel, and isbumpablemultifundchannel.

multifundchannel/fundchannel

fundchannel is just a thin wrapper around multifundchannel, so I will describe multifundchannel.

We add two new outputs, fundchannel_uuid and bumpable. fundchannel_uuid is simply a large random hex string that uniquely identifies this multifundchannel attempt. bumpable is true if all nodes support feebumping (i.e. all nodes in the multifundchannel support openv2), false otherwise.

What happens is that we use the datastore API. We add a key lightning/plugins/spenderp/listfundchannels as a parent key, with the UUIDs as child keys. Before multifundchannel returns, generate a UUID and store the data on the db:

listfundchannels

listfundchannels [fundchannel_uuid_or_node_id]

Given no arguments this simply does listdatastore on the lightning/plugins/spenderp/listfundchannels key, and parses the returned data and prints it out in JSON, including the fundchannel_uuid.

Given an argument, it identifies it as either a UUID or a node ID. If a UUID it just parses the specific UUID and returns the data. If a node ID it looks through listdatastore and looks for the entry where the given node ID is listed.

We also run a background task. We waitblockheight starting at 0, then we listfundchannels with no arguments. If at least one node in a particular fundchannel_uuid has entered CHANNELD_NORMAL state, then we delete it. Then we just loop again, taking the blockheight returned by the previous waitblockheight + 1.

bumpfundchannel

bumpfundchannel fundchannel_uuid_or_node_id [deltafeerate]

This attempts to bump the given multifundchannel attempt. If deltafeerate is specified it is the feerate to add to the previous feerate, and must be at least 253perkw. If unspecified it defaults to 253perkw.

From what I understand of the RBFing flow, it would look like this:

isbumpablemultifundchannel

isbumpablemultifundchannel node_ids

node_ids is an array of node IDs. This checks if all the given nodes have the openv2 feature bit set. If so, it returns a bumpable of true, otherwise it returns a bumpable of false. Convenience API so that automated node managers can know beforehand if it can lowball first and feebump later, given a particular set of candidate nodes, or if it has to highball now because it cannot feebump later because nobody upgrades their software.

niftynei commented 2 years ago

@rustyrussell has made a similar request...

I need to do some work on how liquidity ads are handle across bumps. That's a good time as any to look at getting a nicer bump interface done as well, tbh. Also need to build in this logic to funder, there's some gaps there w/r/t bump attempts that need patching over also, so yes. Great suggestion.

We also run a background task. We waitblockheight starting at 0, then we listfundchannels with no arguments. If at least one node in a particular fundchannel_uuid has entered CHANNELD_NORMAL state, then we delete it. Then we just loop again, taking the blockheight returned by the previous waitblockheight + 1.

We can register for the channel_state notification (name??) and update on notice instead of running a task.

isbumpablemultifundchannel node_ids

Might be nicer to track this via txid? Every open attempt is batched under the txid of the funding attempt -- that'd make it easier to keep track of them across other logs etc.

In fact, fundchannel_uuid can probably be replaced with just the txid of the attempt you'd like to bump. Downside: may have multiple inflight at the same time. Upside: easy to keep track of. If you've already bumped that txid we can just echo back whatever the new tx was that we replaced it with, which will let you eventually find the last/most up to date tx to attempt to bump.

niftynei commented 2 years ago

This is next on my todo list, as soon as I've got the accounting plugin done.

ZmnSCPxj commented 2 years ago

In fact, fundchannel_uuid can probably be replaced with just the txid of the attempt you'd like to bump. Downside: may have multiple inflight at the same time. Upside: easy to keep track of. If you've already bumped that txid we can just echo back whatever the new tx was that we replaced it with, which will let you eventually find the last/most up to date tx to attempt to bump.

That is indeed the problem, txid is not stable for feebumps, which is why I introduced a UUID. If you keep a reference around to the original txid and it remains valid as an argument even after millions of RBF requests, then it might as well be the UUID I refer to. Using txid is misleading to the user, since if the original txid is used as the API identifier, the user might expect to find it in a blockchain explorer, but due to RBF the original txid is unlikely to confirm. So specifically saying it is a "UUID" should limit the expectations of the user better. On the other hand if the user has to use the latest txid (so that the latest txid is likely the one that will get confirmed onchain and in a blockchain explorer) then it adds burden to the user, and in particular, consider if a piece of automation is the one operating this (now the automated process has to worry about the user interfering with its operation by the user doing a manual feebump that the automated process is unaware of).

Using the txid either means:

That is why I suggested using a stable, unchanging UUID that is not a txid, because the RBF flow inherently changes txid.