bolts
bolts copied to clipboard
Funding Timeout Recovery proposal
Since we recently strengthened the "you're allowed to forget" rule I though it might be nice to revisit the state that this leaves the funder in. When a fundee forgets about a channel, the funder is forced to either double-spend the funding transaction (if possible), or use the negotiated commitment transaction, which usually has much higher fees attached than necessary, and results in the funds being unavailable until the to_us timeout expires.
This proposal describes a minimal set of information a fundee might want to keep around, to assist the funder to recover its funds. It basically boils down to writing a blank check to the funder and the funder can then implement arbitrary recovery logic. The blank check is limited to the channel in question via the funding_privkey which is channel specific.
In addition. it adds a small facility, based on the same ground-work, to recover funds from malleated funding transactions, which we've had one recently due to the user importing the private key into an external wallet and manipulating the funding transaction there before broadcasting. It might be a rare case, but I think it's a nice escape hatch to use if anything goes bad. In that case it was re-negotiating a close on a funding transaction alias.
Update: #866 was filed as a competing variant based on exchanging the keys. Please continue discussing trade-offs here, so we don't spread the discussion over two PRs.
Closes #866
I also proposed the "give the funding_key" to @cdecker but I wasn't sure anyone would be comfortable with it....
I also proposed the "give the funding_key" to @cdecker but I wasn't sure anyone would be comfortable with it....
This came up in the last IRC meeting with many attendees preferring that route "just send the multi-sig private key" instead of the blank check out. Although this route is much simpler, IMO it's to be avoided (in favor of the original proposal) as:
- We make no requirements w.r.t the method of derivation used for the private keys. Depending on the implementation, leaking those keys could compromise other keys if non hardened derivation is used.
- It creates a new foot-gun where a user could possibly be manipulated into sending the keys while the actually is still active, thereby forfeiting all their funds.
- Just even the thought of "users just sending their private keys of the wire" should make us all shudder...
I added the KEYOLO variant as #866 as promised during the last spec
meeting, however I find the more restricted variant exchanging just
the sighash_none signature a bit more palatable, as it clearly has
fewer requirements on the way the fundee funding_privkey is
derived. I added the requirement for hardened derivation multiple
times, but some implementers might eventually forget about it.
To summarize the differences:
- KEYOLO is less fingerprintable on-chain, given that it doesn't require a non-default sighash-flag.
- KEYOLO also covers the case of a user sending funds to a funding
output script, outside of a channel funding.
- Should we consider this part of our spec at all? We can't prevent users from doing dumb things, neither should we. And this only applies when they happen to send to a channel that timed out anyway, i.e., if they send to a channel script that was used the funds are unrecoverable even with KEYOLO.
- It creates a new foot-gun where a user could possibly be manipulated into sending the keys while the actually is still active, thereby forfeiting all their funds.
I'm afraid this is even the case with the more restrictive #854
proposal: if you send out a sighash_none signature as per this
proposal, and then fail to mark the channel as inactive, then whatever
you do going forward could race with a close transaction that the
funder can now create using that signature. All the invalidation logic
just went out the window. Hence my insistence on marking the channel
as unusable before exchanging signatures. Ideally we'd mark the
channel as forgotten/abandoned on a timeout, and generate the
signature only as a reaction to getting a re-establish for a channel
that is already marked abandoned in the committed state to disk. This
avoids having to deal with some edge-cases like marking in a DB
transaction while queuing the message, and then rolling back or
abandoning the DB transaction, but not clearing the message queue.