From 06c41a05474eee8891610005bfb275574e5705c3 Mon Sep 17 00:00:00 2001 From: niftynei Date: Thu, 3 Sep 2020 13:01:45 -0500 Subject: [PATCH] dualfund: opener, openchannel_init command (1/3) There are 3 commands for opening a channel with dualfunding. `openchannel_init` is the first of these. It initializes the open-channel dialog, and stops once we've run out of updates (input/outputs) to send to the peer. --- common/jsonrpc_errors.h | 2 + doc/Makefile | 1 + doc/index.rst | 1 + doc/lightning-openchannel_init.7 | 97 ++++++++++++++ doc/lightning-openchannel_init.7.md | 82 ++++++++++++ lightningd/dual_open_control.c | 200 +++++++++++++++++++++++++++- openingd/dualopend.c | 184 ++++++++++++++++++++++++- openingd/dualopend_wire.csv | 12 +- openingd/dualopend_wiregen.c | 45 ++++++- openingd/dualopend_wiregen.h | 13 +- 10 files changed, 629 insertions(+), 8 deletions(-) create mode 100644 doc/lightning-openchannel_init.7 create mode 100644 doc/lightning-openchannel_init.7.md diff --git a/common/jsonrpc_errors.h b/common/jsonrpc_errors.h index ccc7c791c..389aea521 100644 --- a/common/jsonrpc_errors.h +++ b/common/jsonrpc_errors.h @@ -52,6 +52,8 @@ static const errcode_t FUNDING_PEER_NOT_CONNECTED = 305; static const errcode_t FUNDING_UNKNOWN_PEER = 306; static const errcode_t FUNDING_NOTHING_TO_CANCEL = 307; static const errcode_t FUNDING_CANCEL_NOT_SAFE = 308; +static const errcode_t FUNDING_PSBT_INVALID = 309; +static const errcode_t FUNDING_V2_NOT_SUPPORTED = 310; /* `connect` errors */ static const errcode_t CONNECT_NO_KNOWN_ADDRESS = 400; diff --git a/doc/Makefile b/doc/Makefile index 8cdbb511a..19fe2ddae 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -40,6 +40,7 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-multifundchannel.7 \ doc/lightning-multiwithdraw.7 \ doc/lightning-newaddr.7 \ + doc/lightning-openchannel_init.7 \ doc/lightning-pay.7 \ doc/lightning-plugin.7 \ doc/lightning-reserveinputs.7 \ diff --git a/doc/index.rst b/doc/index.rst index 60ab06900..523dfe799 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -68,6 +68,7 @@ c-lightning Documentation lightning-multifundchannel lightning-multiwithdraw lightning-newaddr + lightning-openchannel_init lightning-pay lightning-ping lightning-plugin diff --git a/doc/lightning-openchannel_init.7 b/doc/lightning-openchannel_init.7 new file mode 100644 index 000000000..2a313db09 --- /dev/null +++ b/doc/lightning-openchannel_init.7 @@ -0,0 +1,97 @@ +.TH "LIGHTNING-OPENCHANNEL_INIT" "7" "" "" "lightning-openchannel_init" +.SH NAME +lightning-openchannel_init - Command to initiate a channel to a peer +.SH SYNOPSIS + +\fBopenchannel_init\fR \fIid\fR \fIamount\fR \fIinitalpsbt\fR [\fIcommitment_feerate\fR] [\fIfunding_feerate\fR] [\fIannounce\fR] [\fIclose_to\fR] + +.SH DESCRIPTION + +\fBopenchannel_init\fR is a low level RPC command which initiates a channel +open with a specified peer\. It uses the openchannel protocol +which allows for interactive transaction construction\. + + +\fIid\fR is the node id of the remote peer\. + + +\fIamount\fR is the satoshi value that we will contribute to the channel\. +This value will be \fIadded\fR to the provided PSBT in the output which is +encumbered by the 2-of-2 script for this channel\. + + +\fIinitialpsbt\fR is the funded, incomplete PSBT that specifies the UTXOs and +change output for our channel contribution\. It can be updated, +see \fBopenchannel_update\fR; \fIinitialpsbt\fR must have at least one input to +provide a PoDLE to the peer\. Must have the Non-Witness UTXO +(PSBT_IN_NON_WITNESS_UTXO) set for every input\. An error +(code 309) will be returned if this requirement is not met\. + + +\fIcommitment_feerate\fR is an optional field\. Sets the feerate for +commitment transactions: see \fBfundchannel\fR\. + + +\fIfunding_feerate\fR is an optional field\. Sets the feerate for the +funding transaction\. Defaults to 'opening' feerate\. + + +\fIannounce\fR is an optional field\. Whether or not to announce this channel\. + + +\fIclose_to\fR is a Bitcoin address to which the channel funds should be +sent on close\. Only valid if both peers have negotiated +\fBoption_upfront_shutdown_script\fR\. + +.SH RETURN VALUE + +On success, returns the \fIchannel_id\fR for this channel; an updated +incomplete \fIinitialpsbt\fR for this funding transaction; and the flag +\fIcommitments_secured\fR, which indiciates the completeness of the +passed back \fIpsbt\fR\. (Will always be false)\. + + +If the peer does not support \fBoption_dual_fund\fR, this command +will return an error\. + + +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] +300: The amount exceeded the maximum configured funding amount\. +.IP \[bu] +301: The provided PSBT cannot afford the funding amount\. +.IP \[bu] +304: Still syncing with bitcoin network +.IP \[bu] +305: Peer is not connected\. +.IP \[bu] +306: Unknown peer id\. +.IP \[bu] +309: PSBT missing required fields +.IP \[bu] +310: v2 channel open protocol not supported by peer + +.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 is mainly responsible\. + +.SH RESOURCES + +Main web site: \fIhttps://github.com/ElementsProject/lightning\fR + +\" SHA256STAMP:a06dc67176c3c9863e4fc3048de7d0172eb79d091479415eb639335b3d096860 diff --git a/doc/lightning-openchannel_init.7.md b/doc/lightning-openchannel_init.7.md new file mode 100644 index 000000000..8a18b3148 --- /dev/null +++ b/doc/lightning-openchannel_init.7.md @@ -0,0 +1,82 @@ +lightning-openchannel\_init -- Command to initiate a channel to a peer +===================================================================== + +SYNOPSIS +-------- + +**openchannel_init** *id* *amount* *initalpsbt* \[*commitment_feerate*\] \[*funding_feerate*\] \[*announce*\] \[*close_to*\] + +DESCRIPTION +----------- + +`openchannel_init` is a low level RPC command which initiates a channel +open with a specified peer. It uses the openchannel protocol +which allows for interactive transaction construction. + +*id* is the node id of the remote peer. + +*amount* is the satoshi value that we will contribute to the channel. +This value will be _added_ to the provided PSBT in the output which is +encumbered by the 2-of-2 script for this channel. + +*initialpsbt* is the funded, incomplete PSBT that specifies the UTXOs and +change output for our channel contribution. It can be updated, +see `openchannel_update`; *initialpsbt* must have at least one input to +provide a PoDLE to the peer. Must have the Non-Witness UTXO +(PSBT\_IN\_NON\_WITNESS\_UTXO) set for every input. An error +(code 309) will be returned if this requirement is not met. + +*commitment_feerate* is an optional field. Sets the feerate for +commitment transactions: see **fundchannel**. + +*funding_feerate* is an optional field. Sets the feerate for the +funding transaction. Defaults to 'opening' feerate. + +*announce* is an optional field. Whether or not to announce this channel. + +*close_to* is a Bitcoin address to which the channel funds should be +sent on close. Only valid if both peers have negotiated +`option_upfront_shutdown_script`. + + +RETURN VALUE +------------ + +On success, returns the *channel_id* for this channel; an updated +incomplete *initialpsbt* for this funding transaction; and the flag +*commitments_secured*, which indiciates the completeness of the +passed back *psbt*. (Will always be false). + +If the peer does not support `option_dual_fund`, this command +will return an error. + +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. +- 300: The amount exceeded the maximum configured funding amount. +- 301: The provided PSBT cannot afford the funding amount. +- 304: Still syncing with bitcoin network +- 305: Peer is not connected. +- 306: Unknown peer id. +- 309: PSBT missing required fields +- 310: v2 channel open protocol not supported by peer + +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 <> is mainly responsible. + +RESOURCES +--------- + +Main web site: diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 97a2d575d..406c31a37 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -741,6 +741,35 @@ wallet_commit_channel(struct lightningd *ld, return channel; } +static void opener_psbt_changed(struct subd *dualopend, + struct uncommitted_channel *uc, + const u8 *msg) +{ + struct channel_id cid; + struct wally_psbt *psbt; + struct json_stream *response; + struct command *cmd = uc->fc->cmd; + + if (!fromwire_dual_open_psbt_changed(cmd, msg, + &cid, + &psbt)) { + log_broken(dualopend->log, + "Malformed dual_open_psbt_changed %s", + tal_hex(tmpctx, msg)); + tal_free(dualopend); + return; + } + + response = json_stream_success(cmd); + json_add_string(response, "channel_id", + type_to_string(tmpctx, struct channel_id, &cid)); + json_add_psbt(response, "psbt", psbt); + json_add_bool(response, "commitments_secured", false); + + uc->fc->inflight = true; + was_pending(command_success(cmd, response)); +} + static void accepter_commit_received(struct subd *dualopend, struct uncommitted_channel *uc, const int *fds, @@ -923,6 +952,155 @@ static void accepter_got_offer(struct subd *dualopend, plugin_hook_call_openchannel2(dualopend->ld, payload); } +static struct command_result *json_open_channel_init(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct funding_channel *fc = tal(cmd, struct funding_channel); + struct node_id *id; + struct peer *peer; + struct channel *channel; + bool *announce_channel; + u32 *feerate_per_kw_funding; + u32 *feerate_per_kw; + struct amount_sat *amount, psbt_val; + struct wally_psbt *psbt; + + u8 *msg = NULL; + + fc->cmd = cmd; + fc->cancels = tal_arr(fc, struct command *, 0); + fc->uc = NULL; + fc->inflight = false; + + if (!param(fc->cmd, buffer, params, + p_req("id", param_node_id, &id), + p_req("amount", param_sat, &amount), + p_req("initialpsbt", param_psbt, &psbt), + p_opt("commitment_feerate", param_feerate, &feerate_per_kw), + p_opt("funding_feerate", param_feerate, &feerate_per_kw_funding), + 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(); + + psbt_val = AMOUNT_SAT(0); + for (size_t i = 0; i < psbt->num_inputs; i++) { + struct amount_sat in_amt = psbt_input_get_amount(psbt, i); + if (!amount_sat_add(&psbt_val, psbt_val, in_amt)) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Overflow in adding PSBT input values. %s", + type_to_string(tmpctx, struct wally_psbt, psbt)); + } + + /* If they don't pass in at least enough in the PSBT to cover + * their amount, nope */ + if (!amount_sat_greater(psbt_val, *amount)) + return command_fail(cmd, FUND_CANNOT_AFFORD, + "Provided PSBT cannot afford funding of " + "amount %s. %s", + type_to_string(tmpctx, struct amount_sat, amount), + type_to_string(tmpctx, struct wally_psbt, psbt)); + + fc->funding = *amount; + if (!feerate_per_kw) { + feerate_per_kw = tal(cmd, u32); + /* Anchors exist, set the commitment feerate to min */ + *feerate_per_kw = feerate_min(cmd->ld, NULL); + } + if (!feerate_per_kw_funding) { + feerate_per_kw_funding = tal(cmd, u32); + *feerate_per_kw_funding = opening_feerate(cmd->ld->topology); + if (!*feerate_per_kw_funding) + return command_fail(cmd, LIGHTNINGD, + "`funding_feerate` not specified and fee " + "estimation failed"); + } + + if (!topology_synced(cmd->ld->topology)) { + return command_fail(cmd, FUNDING_STILL_SYNCING_BITCOIN, + "Still syncing with bitcoin network"); + } + + 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) { + return command_fail(cmd, LIGHTNINGD, "Already funding channel"); + } + +#if EXPERIMENTAL_FEATURES + if (!feature_negotiated(cmd->ld->our_features, + peer->their_features, + OPT_DUAL_FUND)) { + return command_fail(cmd, FUNDING_V2_NOT_SUPPORTED, + "v2 openchannel not supported " + "by peer"); + } +#endif /* EXPERIMENTAL_FEATURES */ + + /* BOLT #2: + * - if both nodes advertised `option_support_large_channel`: + * - MAY set `funding_satoshis` greater than or equal to 2^24 satoshi. + * - otherwise: + * - MUST set `funding_satoshis` to less than 2^24 satoshi. + */ + if (!feature_negotiated(cmd->ld->our_features, + peer->their_features, OPT_LARGE_CHANNELS) + && amount_sat_greater(*amount, chainparams->max_funding)) + return command_fail(cmd, FUND_MAX_EXCEEDED, + "Amount exceeded %s", + type_to_string(tmpctx, struct amount_sat, + &chainparams->max_funding)); + + fc->channel_flags = OUR_CHANNEL_FLAGS; + if (!*announce_channel) { + fc->channel_flags &= ~CHANNEL_FLAGS_ANNOUNCE_CHANNEL; + log_info(peer->ld->log, "Will open private channel with node %s", + type_to_string(fc, struct node_id, id)); + } + + /* Add serials to any input that's missing them */ + 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 = 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_dual_open_opener_init(NULL, + psbt, *amount, + fc->our_upfront_shutdown_script, + *feerate_per_kw, + *feerate_per_kw_funding, + fc->channel_flags); + + subd_send_msg(peer->uncommitted_channel->open_daemon, take(msg)); + return command_still_pending(cmd); +} + static unsigned int dual_opend_msg(struct subd *dualopend, const u8 *msg, const int *fds) { @@ -934,7 +1112,17 @@ static unsigned int dual_opend_msg(struct subd *dualopend, accepter_got_offer(dualopend, uc, msg); return 0; case WIRE_DUAL_OPEN_PSBT_CHANGED: - accepter_psbt_changed(dualopend, msg); + if (uc->fc) { + if (!uc->fc->cmd) { + log_unusual(dualopend->log, + "Unexpected PSBT_CHANGED %s", + tal_hex(tmpctx, msg)); + tal_free(dualopend); + return 0; + } + opener_psbt_changed(dualopend, uc, msg); + } else + accepter_psbt_changed(dualopend, msg); return 0; case WIRE_DUAL_OPEN_COMMIT_RCVD: if (tal_count(fds) != 3) @@ -946,6 +1134,7 @@ static unsigned int dual_opend_msg(struct subd *dualopend, /* Messages we send */ case WIRE_DUAL_OPEN_INIT: + case WIRE_DUAL_OPEN_OPENER_INIT: case WIRE_DUAL_OPEN_GOT_OFFER_REPLY: case WIRE_DUAL_OPEN_FAIL: case WIRE_DUAL_OPEN_DEV_MEMLEAK: @@ -971,6 +1160,15 @@ static unsigned int dual_opend_msg(struct subd *dualopend, return 0; } +static const struct json_command open_channel_init_command = { + "openchannel_init", + "channels", + json_open_channel_init, + "Init an open channel to {id} with {initialpsbt} for {amount} satoshis. " + "Returns updated {psbt} with (partial) contributions from peer" +}; +AUTODATA(json_command, &open_channel_init_command); + void peer_start_dualopend(struct peer *peer, struct per_peer_state *pps, const u8 *send_msg) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 2d56c8d87..bb4517a50 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1236,6 +1236,186 @@ static u8 *accepter_start(struct state *state, const u8 *oc2_msg) } #endif /* EXPERIMENTAL_FEATURES */ +static u8 *opener_start(struct state *state, u8 *msg) +{ + struct tlv_opening_tlvs *open_tlv; + struct tlv_accept_tlvs *a_tlv; + struct channel_id cid; + char *err_reason; + struct amount_sat total; + struct wally_psbt *psbt; + struct wally_psbt_output *funding_out; + u8 channel_flags; + const u8 *wscript; + u16 serial_id; + struct sha256 podle; + + if (!fromwire_dual_open_opener_init(state, msg, + &psbt, + &state->opener_funding, + &state->upfront_shutdown_script[LOCAL], + &state->feerate_per_kw, + &state->feerate_per_kw_funding, + &channel_flags)) + master_badmsg(WIRE_DUAL_OPEN_OPENER_INIT, msg); + + state->our_role = TX_INITIATOR; + state->tx_locktime = psbt->tx->locktime; + open_tlv = tlv_opening_tlvs_new(tmpctx); + + if (state->upfront_shutdown_script[LOCAL]) { + open_tlv->option_upfront_shutdown_script = + tal(open_tlv, + struct tlv_opening_tlvs_option_upfront_shutdown_script); + open_tlv->option_upfront_shutdown_script->shutdown_scriptpubkey = + state->upfront_shutdown_script[LOCAL]; + } + + /* FIXME: actually set the podle */ + memset(&podle, 0, sizeof(podle)); + msg = towire_open_channel2(NULL, + &chainparams->genesis_blockhash, + &podle, /* FIXME: podle H2! */ + state->feerate_per_kw_funding, + state->opener_funding, + state->localconf.dust_limit, + state->localconf.max_htlc_value_in_flight, + state->localconf.htlc_minimum, + state->feerate_per_kw, + state->localconf.to_self_delay, + state->localconf.max_accepted_htlcs, + state->tx_locktime, + &state->our_funding_pubkey, + &state->our_points.revocation, + &state->our_points.payment, + &state->our_points.delayed_payment, + &state->our_points.htlc, + &state->first_per_commitment_point[LOCAL], + channel_flags, + open_tlv); + + sync_crypto_write(state->pps, take(msg)); + + /* This is usually a very transient state... */ + peer_billboard(false, "channel open: offered, waiting for accept_channel2"); + + /* ... since their reply should be immediate. */ + msg = opening_negotiate_msg(tmpctx, state, true); + if (!msg) + return NULL; + + /* Set a cid default value, so on failure it's populated */ + memset(&cid, 0xFF, sizeof(cid)); + + a_tlv = tlv_accept_tlvs_new(state); + if (!fromwire_accept_channel2(msg, &cid, + &state->accepter_funding, + &state->remoteconf.dust_limit, + &state->remoteconf.max_htlc_value_in_flight, + &state->remoteconf.htlc_minimum, + &state->minimum_depth, + &state->remoteconf.to_self_delay, + &state->remoteconf.max_accepted_htlcs, + &state->their_funding_pubkey, + &state->their_points.revocation, + &state->their_points.payment, + &state->their_points.delayed_payment, + &state->their_points.htlc, + &state->first_per_commitment_point[REMOTE], + a_tlv)) + peer_failed(state->pps, &cid, + "Parsing accept_channel2 %s", tal_hex(msg, msg)); + + if (a_tlv->option_upfront_shutdown_script) { + state->upfront_shutdown_script[REMOTE] = tal_steal(state, + a_tlv->option_upfront_shutdown_script->shutdown_scriptpubkey); + } else + state->upfront_shutdown_script[REMOTE] = NULL; + + derive_channel_id_v2(&state->channel_id, + &state->our_points.revocation, + &state->their_points.revocation); + + if (!channel_id_eq(&cid, &state->channel_id)) + peer_failed(state->pps, &state->channel_id, + "accept_channel2 ids don't match: expected %s, got %s", + type_to_string(msg, struct channel_id, &state->channel_id), + type_to_string(msg, struct channel_id, &cid)); + + /* Check that total funding doesn't overflow */ + if (!amount_sat_add(&total, state->opener_funding, + state->accepter_funding)) + peer_failed(state->pps, &state->channel_id, + "Amount overflow. Local sats %s. " + "Remote sats %s", + type_to_string(tmpctx, struct amount_sat, + &state->opener_funding), + type_to_string(tmpctx, struct amount_sat, + &state->accepter_funding)); + + /* Check that total funding doesn't exceed allowed channel capacity */ + /* BOLT #2: + * + * The receiving node MUST fail the channel if: + *... + * - `funding_satoshis` is greater than or equal to 2^24 and the receiver does not support + * `option_support_large_channel`. */ + /* We choose to require *negotiation*, not just support! */ + if (!feature_negotiated(state->our_features, state->their_features, + OPT_LARGE_CHANNELS) + && amount_sat_greater(total, chainparams->max_funding)) { + negotiation_failed(state, false, + "total funding_satoshis %s too large", + type_to_string(tmpctx, struct amount_sat, + &total)); + return NULL; + } + + /* BOLT-78de9a79b491ae9fb84b1fdb4546bacf642dce87 #2: + * The sending node: + * - if is the `opener`: + * - MUST send at least one `tx_add_output`, the channel funding output. + */ + wscript = bitcoin_redeem_2of2(state, + &state->our_funding_pubkey, + &state->their_funding_pubkey); + funding_out = psbt_append_output(psbt, + scriptpubkey_p2wsh(tmpctx, wscript), + total); + /* Add a serial_id for this output */ + serial_id = 0; /* FIXME: generate new serial */ + psbt_output_add_serial_id(psbt, funding_out, serial_id); + + /* Add all of our inputs/outputs to the changeset */ + init_changeset(state, psbt); + + /* Now that we know the total of the channel, we can set the reserve */ + set_reserve(state, total); + + if (!check_config_bounds(tmpctx, total, state->feerate_per_kw, + state->max_to_self_delay, + state->min_effective_htlc_capacity, + &state->remoteconf, + &state->localconf, + true, true, /* v2 means we use anchor outputs */ + &err_reason)) { + negotiation_failed(state, false, "%s", err_reason); + return NULL; + } + + /* Send our first message, we're opener we initiate here */ + if (send_next(state, &psbt)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Must have at least one update to send"); + + /* Figure out what the funding transaction looks like! */ + if (!run_tx_interactive(state, &psbt)) + return NULL; + + /* FIXME! */ + return NULL; +} + /* Memory leak detection is DEVELOPER-only because we go to great lengths to * record the backtrace when allocations occur: without that, the leak * detection tends to be useless for diagnosing where the leak came from, but @@ -1321,9 +1501,11 @@ static u8 *handle_master_in(struct state *state) handle_dev_memleak(state, msg); return NULL; #endif + case WIRE_DUAL_OPEN_OPENER_INIT: + return opener_start(state, msg); /* mostly handled inline */ - case WIRE_DUAL_OPEN_DEV_MEMLEAK_REPLY: case WIRE_DUAL_OPEN_INIT: + case WIRE_DUAL_OPEN_DEV_MEMLEAK_REPLY: case WIRE_DUAL_OPEN_FAILED: case WIRE_DUAL_OPEN_FAIL: case WIRE_DUAL_OPEN_GOT_OFFER: diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index b21597b79..fa01c0ecf 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -93,10 +93,20 @@ msgdata,dual_open_psbt_changed,psbt,wally_psbt, msgtype,dual_open_fail,7003 msgdata,dual_open_fail,reason,wirestring, -# dualopend->master: we failed to negotiation channel +# dualopend->master: we failed to negotiate channel msgtype,dual_open_failed,7004 msgdata,dual_open_failed,reason,wirestring, +# master->dualopend: hello, I'd like to start a channel open +msgtype,dual_open_opener_init,7200 +msgdata,dual_open_opener_init,psbt,wally_psbt, +msgdata,dual_open_opener_init,funding_amount,amount_sat, +msgdata,dual_open_opener_init,local_shutdown_len,u16, +msgdata,dual_open_opener_init,local_shutdown_scriptpubkey,u8,local_shutdown_len +msgdata,dual_open_opener_init,feerate_per_kw,u32, +msgdata,dual_open_opener_init,feerate_per_kw_funding,u32, +msgdata,dual_open_opener_init,channel_flags,u8, + # master -> dualopend: do you have a memleak? msgtype,dual_open_dev_memleak,7033 diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 61df76eab..6d91a2826 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -27,6 +27,7 @@ const char *dualopend_wire_name(int e) case WIRE_DUAL_OPEN_PSBT_CHANGED: return "WIRE_DUAL_OPEN_PSBT_CHANGED"; case WIRE_DUAL_OPEN_FAIL: return "WIRE_DUAL_OPEN_FAIL"; case WIRE_DUAL_OPEN_FAILED: return "WIRE_DUAL_OPEN_FAILED"; + case WIRE_DUAL_OPEN_OPENER_INIT: return "WIRE_DUAL_OPEN_OPENER_INIT"; case WIRE_DUAL_OPEN_DEV_MEMLEAK: return "WIRE_DUAL_OPEN_DEV_MEMLEAK"; case WIRE_DUAL_OPEN_DEV_MEMLEAK_REPLY: return "WIRE_DUAL_OPEN_DEV_MEMLEAK_REPLY"; } @@ -45,6 +46,7 @@ bool dualopend_wire_is_defined(u16 type) case WIRE_DUAL_OPEN_PSBT_CHANGED:; case WIRE_DUAL_OPEN_FAIL:; case WIRE_DUAL_OPEN_FAILED:; + case WIRE_DUAL_OPEN_OPENER_INIT:; case WIRE_DUAL_OPEN_DEV_MEMLEAK:; case WIRE_DUAL_OPEN_DEV_MEMLEAK_REPLY:; return true; @@ -352,7 +354,7 @@ bool fromwire_dual_open_fail(const tal_t *ctx, const void *p, wirestring **reaso } /* WIRE: DUAL_OPEN_FAILED */ -/* dualopend->master: we failed to negotiation channel */ +/* dualopend->master: we failed to negotiate channel */ u8 *towire_dual_open_failed(const tal_t *ctx, const wirestring *reason) { u8 *p = tal_arr(ctx, u8, 0); @@ -373,6 +375,45 @@ bool fromwire_dual_open_failed(const tal_t *ctx, const void *p, wirestring **rea return cursor != NULL; } +/* WIRE: DUAL_OPEN_OPENER_INIT */ +/* master->dualopend: hello */ +u8 *towire_dual_open_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags) +{ + u16 local_shutdown_len = tal_count(local_shutdown_scriptpubkey); + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_DUAL_OPEN_OPENER_INIT); + towire_wally_psbt(&p, psbt); + towire_amount_sat(&p, funding_amount); + towire_u16(&p, local_shutdown_len); + towire_u8_array(&p, local_shutdown_scriptpubkey, local_shutdown_len); + towire_u32(&p, feerate_per_kw); + towire_u32(&p, feerate_per_kw_funding); + towire_u8(&p, channel_flags); + + return memcheck(p, tal_count(p)); +} +bool fromwire_dual_open_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags) +{ + u16 local_shutdown_len; + + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_DUAL_OPEN_OPENER_INIT) + return false; + *psbt = fromwire_wally_psbt(ctx, &cursor, &plen); + *funding_amount = fromwire_amount_sat(&cursor, &plen); + local_shutdown_len = fromwire_u16(&cursor, &plen); + // 2nd case local_shutdown_scriptpubkey + *local_shutdown_scriptpubkey = local_shutdown_len ? tal_arr(ctx, u8, local_shutdown_len) : NULL; + fromwire_u8_array(&cursor, &plen, *local_shutdown_scriptpubkey, local_shutdown_len); + *feerate_per_kw = fromwire_u32(&cursor, &plen); + *feerate_per_kw_funding = fromwire_u32(&cursor, &plen); + *channel_flags = fromwire_u8(&cursor, &plen); + return cursor != NULL; +} + /* WIRE: DUAL_OPEN_DEV_MEMLEAK */ /* master -> dualopend: do you have a memleak? */ u8 *towire_dual_open_dev_memleak(const tal_t *ctx) @@ -413,4 +454,4 @@ bool fromwire_dual_open_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:45ac65939acab987dfb71715f3a03db62863aa2048923666845e2adf45387eba +// SHA256STAMP:4d357681ca9bea1ad36f3fe4d3482a0a12f808dfe20b71f0b9bee78beed0950e diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 39d4d776a..588756e5a 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -31,8 +31,10 @@ enum dualopend_wire { WIRE_DUAL_OPEN_PSBT_CHANGED = 7107, /* master->dualopend: fail this channel open */ WIRE_DUAL_OPEN_FAIL = 7003, - /* dualopend->master: we failed to negotiation channel */ + /* dualopend->master: we failed to negotiate channel */ WIRE_DUAL_OPEN_FAILED = 7004, + /* master->dualopend: hello */ + WIRE_DUAL_OPEN_OPENER_INIT = 7200, /* master -> dualopend: do you have a memleak? */ WIRE_DUAL_OPEN_DEV_MEMLEAK = 7033, WIRE_DUAL_OPEN_DEV_MEMLEAK_REPLY = 7133, @@ -82,10 +84,15 @@ u8 *towire_dual_open_fail(const tal_t *ctx, const wirestring *reason); bool fromwire_dual_open_fail(const tal_t *ctx, const void *p, wirestring **reason); /* WIRE: DUAL_OPEN_FAILED */ -/* dualopend->master: we failed to negotiation channel */ +/* dualopend->master: we failed to negotiate channel */ u8 *towire_dual_open_failed(const tal_t *ctx, const wirestring *reason); bool fromwire_dual_open_failed(const tal_t *ctx, const void *p, wirestring **reason); +/* WIRE: DUAL_OPEN_OPENER_INIT */ +/* master->dualopend: hello */ +u8 *towire_dual_open_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags); +bool fromwire_dual_open_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags); + /* WIRE: DUAL_OPEN_DEV_MEMLEAK */ /* master -> dualopend: do you have a memleak? */ u8 *towire_dual_open_dev_memleak(const tal_t *ctx); @@ -97,4 +104,4 @@ bool fromwire_dual_open_dev_memleak_reply(const void *p, bool *leak); #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:45ac65939acab987dfb71715f3a03db62863aa2048923666845e2adf45387eba +// SHA256STAMP:4d357681ca9bea1ad36f3fe4d3482a0a12f808dfe20b71f0b9bee78beed0950e