df-open: commands to update a PSBT or submit a signed PSBT

`openchannel_signed` and `openchannel_update` which allow a user to
continue a openchannel or kick off the completion of a openchannel.

`openchannel_update` should be called until it returns with
`commitments_secured`.
This commit is contained in:
niftynei 2020-09-10 14:43:40 -05:00 committed by Rusty Russell
parent 537eeab208
commit 8858ae4f3d
10 changed files with 445 additions and 1 deletions

View File

@ -957,6 +957,36 @@ class LightningRpc(UnixDomainSocketRpc):
}
return self.call("pay", payload)
def openchannel_init(self, node_id, channel_amount, psbt, feerate=None, funding_feerate=None, announce=True, close_to=None, *args, **kwargs):
"""Initiate an openchannel with a peer """
payload = {
"id": node_id,
"amount": channel_amount,
"initialpsbt": psbt,
"commitment_feerate": feerate,
"funding_feerate": funding_feerate,
"announce": announce,
"close_to": close_to,
}
return self.call("openchannel_init", payload)
def openchannel_signed(self, channel_id, signed_psbt, *args, **kwargs):
""" Send the funding transaction signatures to the peer, finish
the channel open """
payload = {
"channel_id": channel_id,
"signed_psbt": signed_psbt,
}
return self.call("openchannel_signed", payload)
def openchannel_update(self, channel_id, psbt, *args, **kwargs):
"""Update an openchannel with a peer """
payload = {
"channel_id": channel_id,
"psbt": psbt,
}
return self.call("openchannel_update", payload)
def paystatus(self, bolt11=None):
"""Detail status of attempts to pay {bolt11} or any."""
payload = {

View File

@ -41,6 +41,8 @@ MANPAGES := doc/lightning-cli.1 \
doc/lightning-multiwithdraw.7 \
doc/lightning-newaddr.7 \
doc/lightning-openchannel_init.7 \
doc/lightning-openchannel_signed.7 \
doc/lightning-openchannel_update.7 \
doc/lightning-pay.7 \
doc/lightning-plugin.7 \
doc/lightning-reserveinputs.7 \
@ -67,7 +69,7 @@ MANPAGES := doc/lightning-cli.1 \
doc/lightning-listnodes.7 \
doc/lightning-listconfigs.7 \
doc/lightning-help.7 \
doc/lightning-getlog.7
doc/lightning-getlog.7
doc-all: $(MANPAGES) doc/index.rst

View File

@ -69,6 +69,8 @@ c-lightning Documentation
lightning-multiwithdraw <lightning-multiwithdraw.7.md>
lightning-newaddr <lightning-newaddr.7.md>
lightning-openchannel_init <lightning-openchannel_init.7.md>
lightning-openchannel_signed <lightning-openchannel_signed.7.md>
lightning-openchannel_update <lightning-openchannel_update.7.md>
lightning-pay <lightning-pay.7.md>
lightning-ping <lightning-ping.7.md>
lightning-plugin <lightning-plugin.7.md>

68
doc/lightning-openchannel_signed.7 generated Normal file
View File

@ -0,0 +1,68 @@
.TH "LIGHTNING-OPENCHANNEL_SIGNED" "7" "" "" "lightning-openchannel_signed"
.SH NAME
lightning-openchannel_signed - Command to conclude a channel open
.SH SYNOPSIS
\fBopenchannel_signed\fR \fIid\fR \fIsigned_psbt\fR
.SH DESCRIPTION
\fBopenchannel_signed\fR is a low level RPC command which concludes a channel
open with the specified peer\. It uses the v2 openchannel protocol, which
allows for interactive transaction construction\.
This command should be called after \fBopenchannel_update\fR returns
\fIcommitments_secured\fR \fBtrue\fR\.
This command will broadcast the finalized funding transaction,
if we receive valid signatures from the peer\.
\fIid\fR is the node id of the remote peer\.
\fIsigned_psbt\fR is the PSBT returned from \fBopenchannel_update\fR (where
\fIcommitments_secured\fR was true) with partial signatures or finalized
witness stacks included for every input that we contributed to the
PSBT\.
.SH RETURN VALUE
On success, returns the \fIchannel_id\fR for this channel; hex \fItx\fR of the
published funding transaction; and \fItxid\fR of the funding transaction\.
On error, the returned object will contain \fBcode\fR and \fBmessage\fR properties,
with \fBcode\fR being one of the following:
.RS
.IP \[bu]
-32602: If the given parameters are wrong\.
.IP \[bu]
-1: Catchall nonspecific error\.
.IP \[bu]
303: Funding transaction broadcast failed\.
.IP \[bu]
306: Unknown peer id\.
.IP \[bu]
309: PSBT missing required fields\.
.RE
.SH SEE ALSO
lightning-openchannel_\fBupdate\fR(7), lightning-openchannel_\fBsigned\fR(7),
lightning-fundchannel_\fBstart\fR(7), lightning-fundchannel_\fBcomplete\fR(7),
\fBlightning-fundchannel\fR(7), \fBlightning-fundpsbt\fR(7), \fBlightning-utxopsbt\fR(7),
\fBlightning-multifundchannel\fR(7)
.SH AUTHOR
@niftynei \fI<niftynei@gmail.com\fR> is mainly responsible\.
.SH RESOURCES
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
\" SHA256STAMP:68fb78430a5ee3707fdb1324ba46373dd3dfaf325fe4e1bd3dcdc1589d80435c

View File

@ -0,0 +1,60 @@
lightning-openchannel\_signed -- Command to conclude a channel open
===================================================================
SYNOPSIS
--------
**openchannel_signed** *id* *signed_psbt*
DESCRIPTION
-----------
`openchannel_signed` is a low level RPC command which concludes a channel
open with the specified peer. It uses the v2 openchannel protocol, which
allows for interactive transaction construction.
This command should be called after `openchannel_update` returns
*commitments_secured* `true`.
This command will broadcast the finalized funding transaction,
if we receive valid signatures from the peer.
*id* is the node id of the remote peer.
*signed_psbt* is the PSBT returned from `openchannel_update` (where
*commitments_secured* was true) with partial signatures or finalized
witness stacks included for every input that we contributed to the
PSBT.
RETURN VALUE
------------
On success, returns the *channel_id* for this channel; hex *tx* of the
published funding transaction; and *txid* of the funding transaction.
On error, the returned object will contain `code` and `message` properties,
with `code` being one of the following:
- -32602: If the given parameters are wrong.
- -1: Catchall nonspecific error.
- 303: Funding transaction broadcast failed.
- 306: Unknown peer id.
- 309: PSBT missing required fields.
SEE ALSO
--------
lightning-openchannel\_update(7), lightning-openchannel\_signed(7),
lightning-fundchannel\_start(7), lightning-fundchannel\_complete(7),
lightning-fundchannel(7), lightning-fundpsbt(7), lightning-utxopsbt(7),
lightning-multifundchannel(7)
AUTHOR
------
@niftynei <<niftynei@gmail.com>> is mainly responsible.
RESOURCES
---------
Main web site: <https://github.com/ElementsProject/lightning>

66
doc/lightning-openchannel_update.7 generated Normal file
View File

@ -0,0 +1,66 @@
.TH "LIGHTNING-OPENCHANNEL_UPDATE" "7" "" "" "lightning-openchannel_update"
.SH NAME
lightning-openchannel_update - Command to update a collab channel open
.SH SYNOPSIS
\fBopenchannel_update\fR \fIid\fR \fIpsbt\fR
.SH DESCRIPTION
\fBopenchannel_update\fR is a low level RPC command which continues an open
channel with peer, as specified by \fIid\fR\. An updated \fIpsbt\fR is passed in; any
changes from the PSBT last returned (either from \fBopenchannel_init\fR or
a previous call to \fBopenchannel_update\fR) will be communicated to the peer\.
Must be called after \fBopenchannel_init\fR and before \fBopenchannel_signed\fR\.
Must be called until \fIcommitments_secured\fR is returned as true, at which point
\fBopenchannel_signed\fR should be called with a signed version of the PSBT
returned by the last call to \fBopenchannel_update\fR\.
\fIid\fR is the node id of the remote peer\.
\fIpsbt\fR is the updated PSBT to be sent to the peer\. May be identical to
the PSBT last returned by either \fBopenchannel_init\fR or \fBopenchannel_update\fR\.
.SH RETURN VALUE
On success, returns the \fIchannel_id\fR for this channel; an updated, potentially
complete \fIpsbt\fR for this channel's funding transaction; and the flag
\fIcommitments_secured\fR, which indicates the completeness of the returned \fIpsbt\fR\.
If \fIcommitments_secured\fR is true, caller should proceed with signing the
returned PSBT and calling \fBopenchannel_signed\fR to complete the channel open\.
.RS
.IP \[bu]
-32602: If the given parameters are wrong\.
.IP \[bu]
-1: Catchall nonspecific error\.
.IP \[bu]
305: Peer is not connected\.
.IP \[bu]
306: Unknown peer id\.
.IP \[bu]
309: PSBT missing required fields
.RE
.SH SEE ALSO
lightning-openchannel_\fBupdate\fR(7), lightning-openchannel_\fBsigned\fR(7),
lightning-fundchannel_\fBstart\fR(7), lightning-fundchannel_\fBcomplete\fR(7),
\fBlightning-fundchannel\fR(7), \fBlightning-fundpsbt\fR(7), \fBlightning-utxopsbt\fR(7),
\fBlightning-multifundchannel\fR(7)
.SH AUTHOR
@niftynei \fI<niftynei@gmail.com\fR> is mainly responsible\.
.SH RESOURCES
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
\" SHA256STAMP:dcf253e7b1658e71a9721fccee76a6bb07af7579ca4b0413428d2a1e8c9613bc

View File

@ -0,0 +1,59 @@
lightning-openchannel\_update -- Command to update a collab channel open
========================================================================
SYNOPSIS
--------
**openchannel_update** *id* *psbt*
DESCRIPTION
-----------
`openchannel_update` is a low level RPC command which continues an open
channel with peer, as specified by *id*. An updated *psbt* is passed in; any
changes from the PSBT last returned (either from `openchannel_init` or
a previous call to `openchannel_update`) will be communicated to the peer.
Must be called after `openchannel_init` and before `openchannel_signed`.
Must be called until *commitments_secured* is returned as true, at which point
`openchannel_signed` should be called with a signed version of the PSBT
returned by the last call to `openchannel_update`.
*id* is the node id of the remote peer.
*psbt* is the updated PSBT to be sent to the peer. May be identical to
the PSBT last returned by either `openchannel_init` or `openchannel_update`.
RETURN VALUE
------------
On success, returns the *channel_id* for this channel; an updated, potentially
complete *psbt* for this channel's funding transaction; and the flag
*commitments_secured*, which indicates the completeness of the returned *psbt*.
If *commitments_secured* is true, caller should proceed with signing the
returned PSBT and calling `openchannel_signed` to complete the channel open.
- -32602: If the given parameters are wrong.
- -1: Catchall nonspecific error.
- 305: Peer is not connected.
- 306: Unknown peer id.
- 309: PSBT missing required fields
SEE ALSO
--------
lightning-openchannel\_update(7), lightning-openchannel\_signed(7),
lightning-fundchannel\_start(7), lightning-fundchannel\_complete(7),
lightning-fundchannel(7), lightning-fundpsbt(7), lightning-utxopsbt(7),
lightning-multifundchannel(7)
AUTHOR
------
@niftynei <<niftynei@gmail.com>> is mainly responsible.
RESOURCES
---------
Main web site: <https://github.com/ElementsProject/lightning>

View File

@ -3,6 +3,7 @@
#include "config.h"
#include <ccan/list/list.h>
#include <common/channel_id.h>
#include <common/per_peer_state.h>
#include <lightningd/channel_state.h>
#include <lightningd/peer_htlcs.h>
#include <wallet/wallet.h>
@ -146,6 +147,13 @@ struct channel {
/* Our position in the round-robin list. */
u64 rr_number;
/* PSBT, for v2 channels. Saved until it's sent */
const struct wally_psbt *psbt;
/* Stashed pps, saved until channeld is started.
* Needed only for v2 channel open flow */
struct per_peer_state *pps;
};
struct channel *new_channel(struct peer *peer, u64 dbid,

View File

@ -703,6 +703,7 @@ static void opener_psbt_changed(struct subd *dualopend,
json_add_bool(response, "commitments_secured", false);
uc->fc->inflight = true;
uc->fc->cmd = NULL;
was_pending(command_success(cmd, response));
}
@ -918,6 +919,7 @@ static void opener_commit_received(struct subd *dualopend,
goto failed;
}
channel->pps = tal_steal(channel, pps);
if (pbase)
wallet_penalty_base_add(ld->wallet, channel->dbid, pbase);
@ -1004,6 +1006,128 @@ static void accepter_got_offer(struct subd *dualopend,
plugin_hook_call_openchannel2(dualopend->ld, payload);
}
static struct command_result *json_open_channel_signed(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct wally_psbt *psbt;
struct node_id *id;
struct peer *peer;
struct channel *channel;
struct bitcoin_txid txid;
if (!param(cmd, buffer, params,
p_req("id", param_node_id, &id),
p_req("signed_psbt", param_psbt, &psbt),
NULL))
return command_param_failed();
peer = peer_by_id(cmd->ld, id);
if (!peer)
return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer");
channel = peer_active_channel(peer);
if (!channel)
return command_fail(cmd, LIGHTNINGD,
"Peer has no active channel");
if (!channel->pps)
return command_fail(cmd, LIGHTNINGD,
"Missing per-peer-state for channel, "
"are you in the right state to call "
"this method?");
if (channel->psbt)
return command_fail(cmd, LIGHTNINGD,
"Already have a finalized PSBT for "
"this channel");
/* Verify that the psbt's txid matches that of the
* funding txid for this channel */
psbt_txid(NULL, psbt, &txid, NULL);
if (!bitcoin_txid_eq(&txid, &channel->funding_txid))
return command_fail(cmd, FUNDING_PSBT_INVALID,
"Txid for passed in PSBT does not match"
" funding txid for channel. Expected %s, "
"received %s",
type_to_string(tmpctx, struct bitcoin_txid,
&channel->funding_txid),
type_to_string(tmpctx, struct bitcoin_txid,
&txid));
/* Go ahead and try to finalize things, or what we can */
psbt_finalize(psbt);
/* Check that all of *our* outputs are finalized */
if (!psbt_side_finalized(cmd->ld->log, psbt, LOCAL))
return command_fail(cmd, FUNDING_PSBT_INVALID,
"Local PSBT input(s) not finalized");
channel_watch_funding(cmd->ld, channel);
register_open_command(cmd->ld, cmd, channel);
peer_start_channeld(channel, channel->pps,
NULL, psbt, false);
channel->pps = tal_free(channel->pps);
return command_still_pending(cmd);
}
static struct command_result *json_open_channel_update(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct wally_psbt *psbt;
struct node_id *id;
struct peer *peer;
struct channel *channel;
struct channel_id chan_id_unused;
u8 *msg;
if (!param(cmd, buffer, params,
p_req("id", param_node_id, &id),
p_req("psbt", param_psbt, &psbt),
NULL))
return command_param_failed();
peer = peer_by_id(cmd->ld, id);
if (!peer)
return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer");
channel = peer_active_channel(peer);
if (channel)
return command_fail(cmd, LIGHTNINGD, "Peer already %s",
channel_state_name(channel));
if (!peer->uncommitted_channel)
return command_fail(cmd, FUNDING_PEER_NOT_CONNECTED,
"Peer not connected");
if (!peer->uncommitted_channel->fc || !peer->uncommitted_channel->fc->inflight)
return command_fail(cmd, LIGHTNINGD, "No channel funding in progress");
if (peer->uncommitted_channel->fc->cmd)
return command_fail(cmd, LIGHTNINGD, "Channel funding in progress");
/* Add serials to PSBT */
psbt_add_serials(psbt, LOCAL);
if (!psbt_has_required_fields(psbt))
return command_fail(cmd, FUNDING_PSBT_INVALID,
"PSBT is missing required fields %s",
type_to_string(tmpctx, struct wally_psbt, psbt));
peer->uncommitted_channel->fc->cmd = cmd;
memset(&chan_id_unused, 0, sizeof(chan_id_unused));
msg = towire_dual_open_psbt_changed(NULL, &chan_id_unused, psbt);
subd_send_msg(peer->uncommitted_channel->open_daemon, take(msg));
return command_still_pending(cmd);
}
static struct command_result *json_open_channel_init(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
@ -1231,7 +1355,28 @@ static const struct json_command open_channel_init_command = {
"Init an open channel to {id} with {initialpsbt} for {amount} satoshis. "
"Returns updated {psbt} with (partial) contributions from peer"
};
static const struct json_command open_channel_update_command = {
"openchannel_update",
"channels",
json_open_channel_update,
"Update {channel_id} with {psbt}. "
"Returns updated {psbt} with (partial) contributions from peer. "
"If {commitments_secured} is true, next call should be to openchannel_signed"
};
static const struct json_command open_channel_signed_command = {
"openchannel_signed",
"channels",
json_open_channel_signed,
"Finish opening {channel_id} with {signed_psbt}. "
};
#if EXPERIMENTAL_FEATURES
AUTODATA(json_command, &open_channel_init_command);
AUTODATA(json_command, &open_channel_update_command);
AUTODATA(json_command, &open_channel_signed_command);
#endif /* EXPERIMENTAL_FEATURES */
void peer_start_dualopend(struct peer *peer,
struct per_peer_state *pps,

View File

@ -74,6 +74,10 @@ struct funding_channel {
/* Any commands trying to cancel us. */
struct command **cancels;
/* Place to stash the per-peer-state while we wait
* for them to get back to us with signatures */
struct per_peer_state *pps;
};
struct uncommitted_channel *