Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions proposals/001-funding-timeout-recovery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# Funding Timeout Recovery

> "So long, and thanks for all the sigs"
> -- Hitchhikers guide to Lightning


## Problem description

Due to circumstances it may take considerable time for a funding
transaction to confirm, e.g., the funder chose to attach a fee that is
too low to guarantee timely confirmation. This means the channel
funding may not complete for quite some time, and the specification
thus allows the fundee to forget the channel after 2016 blocks:

> - SHOULD forget the channel if it does not see the correct funding
> transaction after a timeout of 2016 blocks.

Since this leaves the funder in a situation where they are forced
to use the commitment transaction, and since the commitment
transaction is using an overestimated feerate, this could end up
costing the funder more than strictly necessary, and the specification
suggests avoiding this situation thus:

> If the fundee forgets the channel before it was confirmed, the
> funder will need to broadcast the commitment transaction to get his
> funds back and open a new channel. To avoid this, the funder should
> ensure the funding transaction confirms in the next 2016 blocks.

However, despite a funder's best efforts to estimate the funding
transaction fee correctly, the estimation may still fail to guarantee
timely confirmation.
Comment thread
t-bast marked this conversation as resolved.

This proposal describes a method for a channel to be closed
collaboratively, without going through the commitment transaction with
overestimated feerate, and without encumbering the funder's funds with
the unilateral close timeout.


## Overview

Upon agreeing to open a new channel with a peer, the fundee generates
a new bitcoin private key `funding_privkey` (corresponding to the
`funding_pubkey`) that is used to sign off on the funds in the channel
once the funding is complete, i.e., the funding transaction is
confirmed. This *funding_pubkey* is used exclusively when signing off
on changes to the channel, no unrelated funds are ever secured using
this private key.

The fundee may therefore sign a collaborative close transaction with
the `funding_privkey` at any time, as long as they remember not to
sign any future commitment transactions. Thus the fundee may provide a
blanked signature for a commitment transaction using `sighash_none`,
signing off whatever the funder intends to do with the funding
outpoint. This frees the parties from having to negotiate a closing
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I feel a little bit dumb asking this but would this idea not also work for a regular mutual close? The fees are paid by the funder and this would remove the necessity to have the negotiation of closing fees via closing_signed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

sighash none would allow the other party to only include an output for himself, it think you mean a sighash single, but that would be clearly visible on chain that a lightning channel was closed, this doesn't matter with announced ones (just search the txid on an LN explorer) but it does with private channels

transaction fee, since the funder can simply change the outputs on the
closing transaction without invalidating the fundee's signature.

The fundee receives the blank signature as part of an error message
when attempting to re-establish a connection, allowing them to build a
closing transaction, with arbitrary outputs, e.g., not encumbering the
funder's return output with a timeout.

This comment was marked as abuse.


## Implementation

This proposal is only applicable to single-funded channels, as
dual-funded channels do not suffer from this issue.

The fundee may forget a channel if it hasn't been confirmed after
2016, however it may chose to retain a minimal stub of the channel to
help the funder recover the funds gracefully in case the funding
transaction eventually confirms. In order to do so it must retain the
following information:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Of course this is less information than a regular channel but it still wont forget the channel opening attempt completely. So How is that an improvement?


- The `channel_id` that was exchanged during the funding
sub-protocol.
- Information used to derive the `funding_privkey`.
- The `funding_outpoint` from the `funding_created` message.
- The funder's `funding_pubkey`.

This information is required in order to construct a valid closing
transaction without any outputs. The outputs will later be modifiable
by the funder, and committed to by their own signature. The fundee
signs the closing transaction with `sighash_none` to allow these

This comment was marked as abuse.

changes by the funder.

A stub MUST NOT be created if the funding transaction confirmed before
the fundee decided to forget the channel and mark it as closed /
forgotten.

Upon forgetting the channel, the fundee has to store the above
information locally in order to retrieve it when required. The fundee
MUST mark the channel as closed, preventing them from signing off on
any future changes, and any re-establishment attempt of the channel
MUST result in an immediate error being returned.

The following steps encompass the funding timeout recovery:

1. Upon reconnecting the funder sends a `channel_reestablish` message
as usual.
2. Upon receiving the `channel_reestablish` the fundee notices that
it has forgotten the channel, but it has a funding timeout
recovery stub matching the `channel_id`.
3. The fundee create a closing transaction from the channel stub,
with `nSequence=0xfffffffd`, sign it with the private key matching
`fundee_privkey`.
4. The signature is sent as part of the `error` message (see Error
Details change below), as TLV type XXX.
5. The funder receives the signature and verifies that it matches the

This comment was marked as abuse.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good point, but I guess that's pretty much implied, isn't it?

expected close transaction.
6. The funder completes the close transaction with the desired
outputs, the fundee signature, and its own signature.
7. The close transaction is broadcast, completing the close operation.
Comment thread
cdecker marked this conversation as resolved.

Notice that since the signature from the fundee is a `sighash_none`
signature, it doesn't get invalidated when changing the outputs. This
allows the funder to chose any desired feerate. In addition setting
the `nSequence=0xfffffffd` opts into RBF, allowing the funder to bump
the feerate if desired.


## Extension: Funding Transaction Alias

Under some circumstances it may happen that the funding transaction is
malleated, and the funding outpoint is no longer the same as
advertised during the negotiation. In this case any commitment
transaction negotiated during the opening will also be invalid, and
the funds are stuck in limbo.

This comment was marked as abuse.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yea, what's the exact purpose of this - is it just to allow RBF? In that case isn't it simpler to open a fresh channel?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Its main purpose is to prevent some users from losing funds because they decided to RBF-bump the funding transaction using external tools. We had one user that took the funding transaction, added it into electrum and used it to bump the funding transaction, without knowing that this would make the channel completely unusable, and unable to recover the funds, since the commitment transaction was now detached from the funding.

We know that other implementations have had similar issues in the past, so we'd like to have a builtin way of fixing this if the counterparty is collaborative. This is a gentleman's agreement to help recover funds in this case, but it is not a guarantee that it works, since a malicious peer may just as well try to extort the funder. It should be clear that the funder is at fault here, since he malleated the funding tx, but having a mechanism of helping them recover is nice :-)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this should be described in the rational for the Alias


To solve this issue, the funder can provide an alias, i.e., the
malleated outpoint as part of the re-establish. Upon receiving a
re-establish with an alias the fundee MAY mark the channel as closed,
derives the necessary information (detailed above), but replaces the
`funding_outpoint` with the one from the re-establish message and
returns the generated signature as part of the `error` message.


## Safety

The `funding_privkey` is assumed to be unique for every channel. If
this is the case then any signature the fundee provides can only ever
be applied to transactions relating to the channel, i.e., signing a
commitment or close transaction for that channel. It is possible with
the extension for a funder to receive a signature for an arbitrary
output, however given the above constraint, it must be either the
funding output for the channel, or the signature doesn't match the
output's spending requirement as it's bound to another public-key or
script.


## Required Changes

The following changes are required to existing messages.


### Error Details

The `error` message is extended with a TLV stream at the end to
include details about the error. This proposal uses this to return the
blank signature from the fundee to the funder if they forgot the
channel.


### Re-establish TLV

Only required for the funding transaction alias extension. The
`channel_reestablish` message is extended with a TLV stream at the end
to include optional fields. This proposal adds the optional
`funding_transaction_alias` TLV type to be added in this stream.


## Open Questions

- [ ] The specification appears to not require `funding_pubkey` to be
unique to the channel. Is anyone reusing their it? Can we
require it to be unique?

This comment was marked as abuse.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We also use unique per-channel secrets in eclair, it makes sense to require it to be unique.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Looks like KEYOLO is also an option then, I added #866 as a counter-proposal using the funding_privkey exchange.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sounds good. I'm adding an explicit doc in lightning-signer that the channel nonce should not be reused if supplied, and we do generate a unique one if it is not supplied. The generated keys are not in the BIP32 hierarchy, so should not collide with layer-1 keys.

- [ ] Do we want to piggyback the signature on the error message or

This comment was marked as abuse.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We can always extend this using TLVs, to include a collaboration fee (do we want to formalize extortion???) and whatever else we want, having that flexibility and re-using the message we already have are not mutually exclusive imho.

What I like about the error message is that it is atomic, either we get an error along with all the information required to react to it, or we don't. If we split across multiple messages we might get the error, but not the extra information, or we might get the extra information first, not know what to do with it, and only then the error.

shall we add a new message that preceeds the error message?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The only use case I am seeing is to request a Funding Transaction Alias but that seems a bit complicated from a communication flow perspective.

- [ ] Additional safety checks: `next_commitment_number` must be 1.