Browse Source

funding: add RPC arg to specify a 'close_to' address

Takes advantage of upfront-shutdown-script to permit users to
specify the close-to address for a channel at open, by adding
a `close_to` field to `fundchannel_start`.

Note that this only is in effect if `fundchannel_start` returns
with `close_to` set -- otherwise, peer doesn't
support `option_upfront_shutdown_script`.
travis-debug
lisa neigut 5 years ago
committed by neil saitug
parent
commit
422b4502d3
  1. 1
      CHANGELOG.md
  2. 5
      contrib/pylightning/lightning/lightning.py
  3. 13
      doc/lightning-fundchannel_start.7
  4. 8
      doc/lightning-fundchannel_start.7.md
  5. 2
      lightningd/channel.c
  6. 6
      lightningd/channel.h
  7. 32
      lightningd/opening_control.c
  8. 159
      lightningd/peer_control.c
  9. 6
      openingd/opening_wire.csv
  10. 27
      openingd/openingd.c

1
CHANGELOG.md

@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- JSON API: `fundchannel_start` now includes field `scriptpubkey`
- JSON API: New method `listtransactions`
- JSON API: `signmessage` will now create a signature from your node on a message; `checkmessage` will verify it.
- JSON API: `fundchannel_start` now accepts an optional parameter `close_to`, the address to which these channel funds should be sent to on close. Returns `using_close_to` if will use.
- Plugin: new notifications `sendpay_success` and `sendpay_failure`.
- Protocol: nodes now announce features in `node_announcement` broadcasts.
- Protocol: we now offer `option_gossip_queries_ex` for finegrained gossip control.

5
contrib/pylightning/lightning/lightning.py

@ -568,12 +568,13 @@ class LightningRpc(UnixDomainSocketRpc):
if 'satoshi' in kwargs:
return self._deprecated_fundchannel_start(node_id, *args, **kwargs)
def _fundchannel_start(node_id, amount, feerate=None, announce=True):
def _fundchannel_start(node_id, amount, feerate=None, announce=True, close_to=None):
payload = {
"id": node_id,
"amount": amount,
"feerate": feerate,
"announce": announce
"announce": announce,
"close_to": close_to,
}
return self.call("fundchannel_start", payload)

13
doc/lightning-fundchannel_start.7

@ -3,7 +3,7 @@
lightning-fundchannel_start - Command for initiating channel establishment for a lightning channel
.SH SYNOPSIS
\fBfundchannel_start\fR \fIid\fR \fIamount\fR [\fIfeerate\fR \fIannounce\fR]
\fBfundchannel_start\fR \fIid\fR \fIamount\fR [\fIfeerate\fR \fIannounce\fR \fIclose_to\fR]
.SH DESCRIPTION
@ -26,6 +26,11 @@ commitment transactions\.
\fIannounce\fR whether or not to announce this channel\.
\fIclose_to\fR is a Bitcoin address to which the channel funds should be sent to
on close\. Only valid if both peers have negotiated \fBoption_upfront_shutdown_script\fR\.
Returns \fBclose_to\fR set to closing script iff is negotiated\.
Note that the funding transaction MUST NOT be broadcast until after
channel establishment has been successfully completed by running
\fBfundchannel_complete\fR, as the commitment transactions for this channel
@ -35,6 +40,8 @@ transaction before that can lead to unrecoverable loss of funds\.
.SH RETURN VALUE
On success, returns the \fIfunding_address\fR and the \fIscriptpubkey\fR for the channel funding output\.
If a \fBclose_to\fR address was provided, will close to this address iff the \fBclose_to\fR address is
returned in the response\. Otherwise, the peer does not support \fBoption_upfront_shutdownscript\fR\.
On failure, returns an error\.
@ -52,7 +59,3 @@ lightning-fundchannel_\fBcomplete\fR(7), lightning-fundchannel_\fBcancel\fR(7)
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
.HL
Last updated 2019-06-12 11:16:20 CEST

8
doc/lightning-fundchannel_start.7.md

@ -4,7 +4,7 @@ lightning-fundchannel\_start -- Command for initiating channel establishment for
SYNOPSIS
--------
**fundchannel\_start** *id* *amount* \[*feerate* *announce*\]
**fundchannel\_start** *id* *amount* \[*feerate* *announce* *close_to*\]
DESCRIPTION
-----------
@ -23,6 +23,10 @@ commitment transactions.
*announce* whether or not to announce this channel.
*close_to* is a Bitcoin address to which the channel funds should be sent to
on close. Only valid if both peers have negotiated `option_upfront_shutdown_script`.
Returns `close_to` set to closing script iff is negotiated.
Note that the funding transaction MUST NOT be broadcast until after
channel establishment has been successfully completed by running
`fundchannel_complete`, as the commitment transactions for this channel
@ -33,6 +37,8 @@ RETURN VALUE
------------
On success, returns the *funding\_address* and the *scriptpubkey* for the channel funding output.
If a `close_to` address was provided, will close to this address iff the `close_to` address is
returned in the response. Otherwise, the peer does not support `option_upfront_shutdownscript`.
On failure, returns an error.

2
lightningd/channel.c

@ -170,7 +170,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
const struct channel_info *channel_info,
/* NULL or stolen */
u8 *remote_shutdown_scriptpubkey,
u8 *local_shutdown_scriptpubkey,
const u8 *local_shutdown_scriptpubkey,
u64 final_key_idx,
bool last_was_revoke,
/* NULL or stolen */

6
lightningd/channel.h

@ -89,8 +89,8 @@ struct channel {
/* Our funding tx pubkey. */
struct pubkey local_funding_pubkey;
/* Their scriptpubkey if they sent shutdown. */
u8 *shutdown_scriptpubkey[NUM_SIDES];
/* scriptpubkey for shutdown, if applicable. */
const u8 *shutdown_scriptpubkey[NUM_SIDES];
/* Address for any final outputs */
u64 final_key_idx;
@ -157,7 +157,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
const struct channel_info *channel_info,
/* NULL or stolen */
u8 *remote_shutdown_scriptpubkey,
u8 *local_shutdown_scriptpubkey,
const u8 *local_shutdown_scriptpubkey,
u64 final_key_idx,
bool last_was_revoke,
/* NULL or stolen */

32
lightningd/opening_control.c

@ -77,6 +77,7 @@ struct funding_channel {
struct amount_msat push;
struct amount_sat funding;
u8 channel_flags;
const u8 *our_upfront_shutdown_script;
/* Variables we need to compose fields in cmd's response */
const char *hextx;
@ -165,6 +166,7 @@ wallet_commit_channel(struct lightningd *ld,
u8 channel_flags,
struct channel_info *channel_info,
u32 feerate,
const u8 *our_upfront_shutdown_script,
const u8 *remote_upfront_shutdown_script)
{
struct channel *channel;
@ -247,7 +249,7 @@ wallet_commit_channel(struct lightningd *ld,
NULL, /* No HTLC sigs yet */
channel_info,
NULL, /* No shutdown_scriptpubkey[REMOTE] yet */
NULL, /* No shutdown_scriptpubkey[LOCAL] yet. Generate the default one. */
our_upfront_shutdown_script,
final_key_idx, false,
NULL, /* No commit sent yet */
/* If we're fundee, could be a little before this
@ -290,7 +292,8 @@ static void funding_success(struct channel *channel)
}
static void funding_started_success(struct funding_channel *fc,
u8 *scriptPubkey)
u8 *scriptPubkey,
bool supports_shutdown)
{
struct json_stream *response;
struct command *cmd = fc->cmd;
@ -303,6 +306,8 @@ static void funding_started_success(struct funding_channel *fc,
if (out) {
json_add_string(response, "funding_address", out);
json_add_hex_talarr(response, "scriptpubkey", scriptPubkey);
if (fc->our_upfront_shutdown_script)
json_add_hex_talarr(response, "close_to", fc->our_upfront_shutdown_script);
}
/* Clear this so cancel doesn't think it's still in progress */
@ -315,9 +320,11 @@ static void opening_funder_start_replied(struct subd *openingd, const u8 *resp,
struct funding_channel *fc)
{
u8 *funding_scriptPubkey;
bool supports_shutdown_script;
if (!fromwire_opening_funder_start_reply(resp, resp,
&funding_scriptPubkey)) {
&funding_scriptPubkey,
&supports_shutdown_script)) {
log_broken(fc->uc->log,
"bad OPENING_FUNDER_REPLY %s",
tal_hex(resp, resp));
@ -327,7 +334,12 @@ static void opening_funder_start_replied(struct subd *openingd, const u8 *resp,
goto failed;
}
funding_started_success(fc, funding_scriptPubkey);
/* If we're not using the upfront shutdown script, forget it */
if (!supports_shutdown_script)
fc->our_upfront_shutdown_script =
tal_free(fc->our_upfront_shutdown_script);
funding_started_success(fc, funding_scriptPubkey, supports_shutdown_script);
/* Mark that we're in-flight */
fc->inflight = true;
@ -401,6 +413,7 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp,
fc->channel_flags,
&channel_info,
feerate,
fc->our_upfront_shutdown_script,
remote_upfront_shutdown_script);
if (!channel) {
was_pending(command_fail(fc->cmd, LIGHTNINGD,
@ -496,6 +509,7 @@ static void opening_fundee_finished(struct subd *openingd,
channel_flags,
&channel_info,
feerate,
NULL,
remote_upfront_shutdown_script);
if (!channel) {
uncommitted_channel_disconnect(uc, "Commit channel failed");
@ -1078,6 +1092,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd,
p_req("amount", param_sat, &amount),
p_opt("feerate", param_feerate, &feerate_per_kw),
p_opt_def("announce", param_bool, &announce_channel, true),
p_opt("close_to", param_bitcoin_address, &fc->our_upfront_shutdown_script),
NULL))
return command_param_failed();
} else {
@ -1101,6 +1116,9 @@ static struct command_result *json_fund_channel_start(struct command *cmd,
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Need set 'amount' field");
}
/* No upfront shutdown script option for deprecated API */
fc->our_upfront_shutdown_script = NULL;
}
if (amount_sat_greater(*amount, max_funding_satoshi))
@ -1161,9 +1179,15 @@ static struct command_result *json_fund_channel_start(struct command *cmd,
peer->uncommitted_channel->fc = tal_steal(peer->uncommitted_channel, fc);
fc->uc = peer->uncommitted_channel;
/* Needs to be stolen away from cmd */
if (fc->our_upfront_shutdown_script)
fc->our_upfront_shutdown_script
= tal_steal(fc, fc->our_upfront_shutdown_script);
msg = towire_opening_funder_start(NULL,
*amount,
fc->push,
fc->our_upfront_shutdown_script,
*feerate_per_kw,
fc->channel_flags);

159
lightningd/peer_control.c

@ -1288,9 +1288,9 @@ static struct command_result *json_close(struct command *cmd,
unsigned int *timeout = NULL;
bool force = true;
bool do_timeout;
const u8 *local_shutdown_script = NULL;
const u8 *close_to_script = NULL;
unsigned int *old_timeout;
bool *old_force;
bool *old_force, close_script_set;
/* For generating help, give new-style. */
if (!params || !deprecated_apis) {
@ -1299,7 +1299,7 @@ static struct command_result *json_close(struct command *cmd,
p_opt_def("unilateraltimeout", param_number,
&timeout, 48 * 3600),
p_opt("destination", param_bitcoin_address,
&local_shutdown_script),
&close_to_script),
NULL))
return command_param_failed();
do_timeout = (*timeout != 0);
@ -1345,7 +1345,7 @@ static struct command_result *json_close(struct command *cmd,
res = json_to_address_scriptpubkey(cmd,
get_chainparams(cmd->ld),
buffer, secondtok,
&local_shutdown_script);
&close_to_script);
if (res == ADDRESS_PARSE_UNRECOGNIZED)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Could not parse destination address");
@ -1368,7 +1368,7 @@ static struct command_result *json_close(struct command *cmd,
res = json_to_address_scriptpubkey(cmd,
get_chainparams(cmd->ld),
buffer, secondtok,
&local_shutdown_script);
&close_to_script);
if (res == ADDRESS_PARSE_UNRECOGNIZED)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Could not parse destination address");
@ -1397,14 +1397,14 @@ static struct command_result *json_close(struct command *cmd,
p_opt_def("unilateraltimeout", param_number,
&timeout, 48 * 3600),
p_opt("destination", param_bitcoin_address,
&local_shutdown_script),
&close_to_script),
p_opt("force", param_bool, &old_force),
p_opt("timeout", param_number, &old_timeout),
NULL))
return command_param_failed();
/* Old style has lower priority. */
if (!local_shutdown_script) {
if (!close_to_script) {
/* Old style. */
if (old_timeout) {
*timeout = *old_timeout;
@ -1446,6 +1446,45 @@ static struct command_result *json_close(struct command *cmd,
"Peer has no active channel");
}
/* If we've set a local shutdown script for this peer, and it's not the
* default upfront script, try to close to a different channel.
* Error is an operator error */
if (close_to_script && channel->shutdown_scriptpubkey[LOCAL]
&& !memeq(close_to_script,
tal_count(close_to_script),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL]))) {
u8 *default_close_to = p2wpkh_for_keyidx(tmpctx, cmd->ld,
channel->final_key_idx);
if (!memeq(default_close_to, tal_count(default_close_to),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL]))) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Destination address %s does not match "
"previous shutdown script %s",
tal_hex(tmpctx, channel->shutdown_scriptpubkey[LOCAL]),
tal_hex(tmpctx, close_to_script));
} else {
channel->shutdown_scriptpubkey[LOCAL] =
tal_free(channel->shutdown_scriptpubkey[LOCAL]);
channel->shutdown_scriptpubkey[LOCAL] =
tal_steal(channel, close_to_script);
close_script_set = true;
}
} else if (close_to_script && !channel->shutdown_scriptpubkey[LOCAL]) {
channel->shutdown_scriptpubkey[LOCAL]
= tal_steal(channel, cast_const(u8 *, close_to_script));
close_script_set = true;
} else if (!channel->shutdown_scriptpubkey[LOCAL]) {
channel->shutdown_scriptpubkey[LOCAL]
= p2wpkh_for_keyidx(channel, cmd->ld, channel->final_key_idx);
/* We don't save the default to disk */
close_script_set = false;
} else
close_script_set = false;
/* Normal case.
* We allow states shutting down and sigexchange; a previous
* close command may have timed out, and this current command
@ -1456,95 +1495,33 @@ static struct command_result *json_close(struct command *cmd,
* state.
* (if already shutting down or sigexchange, just keep
* waiting) */
if (channel->state == CHANNELD_NORMAL || channel->state == CHANNELD_AWAITING_LOCKIN) {
/* Change the channel state first. */
channel_set_state(channel,
channel->state, CHANNELD_SHUTTING_DOWN);
/* FIXME: When we support local upfront_shutdown_script, local_shutdown_script
* must equal to the local upfront_shutdown_script. */
if (local_shutdown_script) {
tal_free(channel->shutdown_scriptpubkey[LOCAL]);
channel->shutdown_scriptpubkey[LOCAL]
= tal_steal(channel, cast_const(u8 *, local_shutdown_script));
}
if (channel->owner)
subd_send_msg(channel->owner,
take(towire_channel_send_shutdown(NULL,
channel->shutdown_scriptpubkey[LOCAL])));
} else if (channel->state == CHANNELD_SHUTTING_DOWN) {
/* FIXME: Add to spec that we must allow repeated shutdown! */
if (!local_shutdown_script)
local_shutdown_script = p2wpkh_for_keyidx(channel,
cmd->ld,
channel->final_key_idx);
bool change_script = !memeq(local_shutdown_script,
tal_count(local_shutdown_script),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL]));
if (change_script) {
log_debug(channel->log, "Repeated close command: "
"the new local scriptpubkey is %s, "
"and the old local scriptpubkey is %s",
local_shutdown_script,
channel->shutdown_scriptpubkey[LOCAL]);
if (!channel->owner)
return command_fail(cmd, LIGHTNINGD,
"The sub-daemon of channel is down(state %s), "
"can't change to-local destination "
"from %s to %s",
channel_state_name(channel),
channel->shutdown_scriptpubkey[LOCAL],
local_shutdown_script);
}
tal_free(channel->shutdown_scriptpubkey[LOCAL]);
channel->shutdown_scriptpubkey[LOCAL]
= tal_steal(channel, cast_const(u8 *, local_shutdown_script));
if (channel->owner)
subd_send_msg(channel->owner,
take(towire_channel_send_shutdown(NULL,
channel->shutdown_scriptpubkey[LOCAL])));
} else if (channel->state == CLOSINGD_SIGEXCHANGE) {
u8 *default_script = p2wpkh_for_keyidx(tmpctx, cmd->ld,
channel->final_key_idx);
bool is_default = memeq(default_script,
tal_count(default_script),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL]));
if (!local_shutdown_script) {
/* Means the user want to send to default address. */
local_shutdown_script = p2wpkh_for_keyidx(tmpctx, cmd->ld,
channel->final_key_idx);
}
if (!memeq(local_shutdown_script,
tal_count(local_shutdown_script),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL])))
return command_fail(cmd, LIGHTNINGD,
"Channel has already been closing now (in state %s) "
"with to-local destination %s",
channel_state_name(channel),
is_default ?
tal_fmt(tmpctx, "(default) %s",
channel->shutdown_scriptpubkey[LOCAL]) :
(char *)channel->shutdown_scriptpubkey[LOCAL]);
} else
return command_fail(cmd, LIGHTNINGD, "Channel is in state %s",
channel_state_name(channel));
switch (channel->state) {
case CHANNELD_NORMAL:
case CHANNELD_AWAITING_LOCKIN:
channel_set_state(channel,
channel->state, CHANNELD_SHUTTING_DOWN);
/* fallthrough */
case CHANNELD_SHUTTING_DOWN:
if (channel->owner)
subd_send_msg(channel->owner,
take(towire_channel_send_shutdown(NULL,
channel->shutdown_scriptpubkey[LOCAL])));
break;
case CLOSINGD_SIGEXCHANGE:
break;
default:
return command_fail(cmd, LIGHTNINGD, "Channel is in state %s",
channel_state_name(channel));
}
/* Register this command for later handling. */
register_close_command(cmd->ld, cmd, channel,
do_timeout ? timeout : NULL, force);
/* We may set new `channel->shutdown_scriptpubkey[LOCAL]` field. Save it. */
wallet_channel_save(cmd->ld->wallet, channel);
/* If we set `channel->shutdown_scriptpubkey[LOCAL]`, save it. */
if (close_script_set)
wallet_channel_save(cmd->ld->wallet, channel);
/* Wait until close drops down to chain. */
return command_still_pending(cmd);
}

6
openingd/opening_wire.csv

@ -65,11 +65,12 @@ msgdata,opening_funder_reply,our_channel_reserve_satoshis,amount_sat,
msgdata,opening_funder_reply,shutdown_len,u16,
msgdata,opening_funder_reply,shutdown_scriptpubkey,u8,shutdown_len
# master->openingd: start channel establishment for a funding
# tx that will be paid for by an external wallet
# master->openingd: start channel establishment for a funding tx
msgtype,opening_funder_start,6002
msgdata,opening_funder_start,funding_satoshis,amount_sat,
msgdata,opening_funder_start,push_msat,amount_msat,
msgdata,opening_funder_start,len_upfront,u16,
msgdata,opening_funder_start,upfront_shutdown_script,u8,len_upfront
msgdata,opening_funder_start,feerate_per_kw,u32,
msgdata,opening_funder_start,channel_flags,u8,
@ -77,6 +78,7 @@ msgdata,opening_funder_start,channel_flags,u8,
msgtype,opening_funder_start_reply,6102
msgdata,opening_funder_start_reply,script_len,u8,
msgdata,opening_funder_start_reply,scriptpubkey,u8,script_len
msgdata,opening_funder_start_reply,upfront_shutdown_negotiated,bool,
# master->openingd: complete channel establishment for a funding
# tx that will be paid for by an external wallet

Can't render this file because it has a wrong number of fields in line 6.

27
openingd/openingd.c

@ -108,7 +108,7 @@ struct state {
bool option_static_remotekey;
};
static const u8 *dev_upfront_shutdown_script(const tal_t *ctx)
static u8 *dev_upfront_shutdown_script(const tal_t *ctx)
{
#if DEVELOPER
/* This is a hack, for feature testing */
@ -485,7 +485,8 @@ static bool setup_channel_funder(struct state *state)
/* We start the 'fund a channel' negotation with the supplied peer, but
* stop when we get to the part where we need the funding txid */
static u8 *funder_channel_start(struct state *state,
u8 channel_flags)
u8 *our_upfront_shutdown_script,
u8 channel_flags)
{
u8 *msg;
u8 *funding_output_script;
@ -504,8 +505,9 @@ static u8 *funder_channel_start(struct state *state,
* - otherwise:
* - MAY include a`shutdown_scriptpubkey`.
*/
/* We don't use shutdown_scriptpubkey (at least for now), so leave it
* NULL. */
if (!our_upfront_shutdown_script)
our_upfront_shutdown_script = dev_upfront_shutdown_script(tmpctx);
msg = towire_open_channel_option_upfront_shutdown_script(NULL,
&state->chainparams->genesis_blockhash,
&state->channel_id,
@ -525,7 +527,7 @@ static u8 *funder_channel_start(struct state *state,
&state->our_points.htlc,
&state->first_per_commitment_point[LOCAL],
channel_flags,
dev_upfront_shutdown_script(tmpctx));
our_upfront_shutdown_script);
sync_crypto_write(state->pps, take(msg));
/* This is usually a very transient state... */
@ -626,7 +628,12 @@ static u8 *funder_channel_start(struct state *state,
peer_billboard(false,
"Funding channel start: awaiting funding_txid with output to %s",
tal_hex(tmpctx, funding_output_script));
return towire_opening_funder_start_reply(state, funding_output_script);
return towire_opening_funder_start_reply(state,
funding_output_script,
feature_negotiated(
state->features,
OPT_UPFRONT_SHUTDOWN_SCRIPT));
}
static bool funder_finalize_channel_setup(struct state *state,
@ -1341,18 +1348,20 @@ static u8 *handle_master_in(struct state *state)
{
u8 *msg = wire_sync_read(tmpctx, REQ_FD);
enum opening_wire_type t = fromwire_peektype(msg);
u8 channel_flags;
u8 channel_flags, *upfront_shutdown_script;
struct bitcoin_txid funding_txid;
u16 funding_txout;
switch (t) {
case WIRE_OPENING_FUNDER_START:
if (!fromwire_opening_funder_start(msg, &state->funding,
if (!fromwire_opening_funder_start(tmpctx, msg, &state->funding,
&state->push_msat,
&upfront_shutdown_script,
&state->feerate_per_kw,
&channel_flags))
master_badmsg(WIRE_OPENING_FUNDER_START, msg);
msg = funder_channel_start(state, channel_flags);
msg = funder_channel_start(state, upfront_shutdown_script,
channel_flags);
/* We want to keep openingd alive, since we're not done yet */
if (msg)

Loading…
Cancel
Save