#include "config.h"
#include <bitcoin/psbt.h>
#include <ccan/ccan/array_size/array_size.h>
#include <ccan/ccan/mem/mem.h>
#include <common/json_channel_type.h>
#include <common/json_stream.h>
#include <common/lease_rates.h>
#include <common/psbt_open.h>
#include <inttypes.h>
#include <plugins/spender/multifundchannel.h>
#include <plugins/spender/openchannel.h>
static struct list_head mfc_commands;
static void
destroy_mfc(struct multifundchannel_command *mfc)
{
list_del(&mfc->list);
}
void register_mfc(struct multifundchannel_command *mfc)
{
assert(mfc);
list_add_tail(&mfc_commands, &mfc->list);
tal_add_destructor(mfc, &destroy_mfc);
}
static struct multifundchannel_destination *
find_dest_by_channel_id(struct channel_id *cid)
{
struct multifundchannel_command *mfc, *n;
list_for_each_safe (&mfc_commands, mfc, n, list) {
for (size_t i = 0; i < tal_count(mfc->destinations); i++) {
struct multifundchannel_destination *dest =
&mfc->destinations[i];
if (channel_id_eq(&dest->channel_id, cid))
return dest;
}
}
return NULL;
}
static bool update_parent_psbt(const tal_t *ctx,
struct multifundchannel_destination *dest,
struct wally_psbt *old_node_psbt,
struct wally_psbt *new_node_psbt,
struct wally_psbt **parent_psbt)
{
struct psbt_changeset *changes;
struct wally_psbt *clone, *new_node_copy;
tal_wally_start();
if (wally_psbt_clone_alloc(*parent_psbt, 0, &clone) != WALLY_OK)
abort();
tal_wally_end_onto(ctx, clone, struct wally_psbt);
tal_wally_start();
if (wally_psbt_clone_alloc(new_node_psbt, 0, &new_node_copy)
!= WALLY_OK)
abort();
tal_wally_end(clone);
changes = psbt_get_changeset(NULL, old_node_psbt,
new_node_copy);
for (size_t i = 0; i < tal_count(changes->added_ins); i++) {
u64 serial;
int s_idx;
const struct wally_psbt_input *in =
&changes->added_ins[i].input;
size_t idx = clone->num_inputs;
if (!psbt_get_serial_id(&in->unknowns, &serial))
goto fail;
if (serial % 2 == TX_INITIATOR)
continue;
s_idx = psbt_find_serial_input(clone, serial - 1);
if (s_idx != -1)
goto fail;
const struct wally_psbt_input *input = &changes->added_ins[i].input;
struct bitcoin_outpoint outpoint;
wally_psbt_input_get_outpoint(input, &outpoint);
psbt_append_input(clone,
&outpoint,
input->sequence,
NULL ,
NULL ,
NULL );
clone->inputs[idx] = *in;
psbt_input_set_serial_id(clone, &clone->inputs[idx],
serial - 1);
}
for (size_t i = 0; i < tal_count(changes->rm_ins); i++) {
u64 serial;
int s_idx;
const struct wally_psbt_input *in =
&changes->rm_ins[i].input;
if (!psbt_get_serial_id(&in->unknowns, &serial))
goto fail;
if (serial % 2 == TX_INITIATOR)
goto fail;
s_idx = psbt_find_serial_input(clone, serial - 1);
if (s_idx == -1)
goto fail;
if (wally_psbt_remove_input(clone, s_idx) != WALLY_OK)
goto fail;
}
for (size_t i = 0; i < tal_count(changes->added_outs); i++) {
u64 serial, parent_serial;
const struct wally_psbt_output *out =
&changes->added_outs[i].output;
int s_idx;
size_t idx = clone->num_outputs;
if (!psbt_get_serial_id(&out->unknowns, &serial))
goto fail;
if (serial % 2 == TX_INITIATOR) {
if (serial == dest->funding_serial) {
parent_serial = dest->funding_serial;
} else
continue;
} else
parent_serial = serial - 1;
s_idx = psbt_find_serial_output(clone, parent_serial);
if (s_idx != -1)
goto fail;
const struct wally_psbt_output *output = &changes->added_outs[i].output;
psbt_append_output(clone, output->script, amount_sat(output->amount));
clone->outputs[idx] = *out;
psbt_output_set_serial_id(clone, &clone->outputs[idx],
parent_serial);
}
for (size_t i = 0; i < tal_count(changes->rm_outs); i++) {
u64 serial;
int s_idx;
const struct wally_psbt_output *out =
&changes->rm_outs[i].output;
if (!psbt_get_serial_id(&out->unknowns, &serial))
goto fail;
if (serial % 2 == TX_INITIATOR)
goto fail;
s_idx = psbt_find_serial_output(clone, serial - 1);
if (s_idx == -1)
goto fail;
if (wally_psbt_remove_output(clone, s_idx) != WALLY_OK)
goto fail;
}
for (size_t i = tal_count(changes->added_ins) - 1;
i > -1;
i--) {
psbt_rm_input(new_node_copy,
changes->added_ins[i].idx);
}
for (size_t i = tal_count(changes->added_outs) - 1;
i > -1;
i--) {
psbt_rm_output(new_node_copy,
changes->added_outs[i].idx);
}
tal_free(changes);
tal_free(new_node_copy);
tal_free(*parent_psbt);
*parent_psbt = clone;
return true;
fail:
tal_free(changes);
tal_free(new_node_copy);
tal_free(clone);
return false;
}
static bool update_node_psbt(const tal_t *ctx,
const struct wally_psbt *parent_psbt,
struct wally_psbt **node_psbt)
{
struct wally_psbt *clone;
tal_wally_start();
if (wally_psbt_clone_alloc(parent_psbt, 0, &clone) != WALLY_OK)
abort();
tal_wally_end_onto(ctx, clone, struct wally_psbt);
for (size_t i = 0; i < (*node_psbt)->num_inputs; i++) {
u64 serial_id;
int input_index;
if (!psbt_get_serial_id(&(*node_psbt)->inputs[i].unknowns,
&serial_id)) {
tal_wally_end(tal_free(clone));
return false;
}
if (serial_id % 2 == TX_INITIATOR)
continue;
input_index = psbt_find_serial_input(clone, serial_id - 1);
assert(input_index != -1);
psbt_input_set_serial_id(clone, &clone->inputs[input_index],
serial_id);
}
for (size_t i = 0; i < (*node_psbt)->num_outputs; i++) {
u64 serial_id;
int output_index;
if (!psbt_get_serial_id(&(*node_psbt)->outputs[i].unknowns,
&serial_id)) {
tal_wally_end(tal_free(clone));
return false;
}
if (serial_id % 2 == TX_INITIATOR)
continue;
output_index = psbt_find_serial_output(clone,
serial_id - 1);
assert(output_index != -1);
psbt_output_set_serial_id(clone, &clone->outputs[output_index],
serial_id);
}
tal_free(*node_psbt);
*node_psbt = clone;
return true;
}
static struct command_result *
openchannel_finished(struct multifundchannel_command *mfc)
{
for (size_t i = 0; i < tal_count(mfc->destinations); i++) {
struct multifundchannel_destination *dest;
dest = &mfc->destinations[i];
if (dest->state == MULTIFUNDCHANNEL_FAILED) {
struct json_stream *out;
plugin_log(mfc->cmd->plugin, LOG_DBG,
"mfc %"PRIu64": %u failed, failing."
" (%d) %s",
mfc->id, dest->index,
dest->error_code,
dest->error_message);
out = jsonrpc_stream_fail_data(mfc->cmd,
dest->error_code,
dest->error_message);
json_add_node_id(out, "id", &dest->id);
json_add_string(out, "method", "openchannel_signed");
if (dest->error_data)
json_add_jsonstr(out, "data",
dest->error_data,
strlen(dest->error_data));
json_object_end(out);
return mfc_finished(mfc, out);
}
}
mfc->psbt = tal_free(mfc->psbt);
return multifundchannel_finished(mfc);
}
static struct command_result *
after_openchannel_signed(struct multifundchannel_command *mfc)
{
--mfc->pending;
if (mfc->pending == 0)
return openchannel_finished(mfc);
else
return command_still_pending(mfc->cmd);
}
static struct command_result *
openchannel_signed_ok(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
plugin_log(mfc->cmd->plugin, LOG_DBG,
"mfc %"PRIu64", dest %u: `openchannel_signed` done",
mfc->id, dest->index);
if (!mfc->final_tx) {
const jsmntok_t *tx_tok, *txid_tok;
tx_tok = json_get_member(buf, result, "tx");
if (!tx_tok)
plugin_err(mfc->cmd->plugin,
"`openchannel_signed` has no 'tx': %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
mfc->final_tx = json_strdup(mfc, buf, tx_tok);
txid_tok = json_get_member(buf, result, "txid");
if (!txid_tok)
plugin_err(mfc->cmd->plugin,
"`openchannel_signed` has no 'txid': %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
mfc->final_txid = json_strdup(mfc, buf, txid_tok);
}
dest->psbt = tal_free(dest->psbt);
return after_openchannel_signed(mfc);
}
static struct command_result *
openchannel_signed_err(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *error,
struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
fail_destination_tok(dest, buf, error);
return after_openchannel_signed(mfc);
}
static void
openchannel_signed_dest(struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
struct command *cmd = mfc->cmd;
struct out_req *req;
plugin_log(cmd->plugin, LOG_DBG,
"mfc %"PRIu64", dest %u: `openchannel_signed` %s "
"psbt %s",
mfc->id, dest->index,
fmt_channel_id(tmpctx, &dest->channel_id),
fmt_wally_psbt(tmpctx, dest->psbt));
req = jsonrpc_request_start(cmd,
"openchannel_signed",
&openchannel_signed_ok,
&openchannel_signed_err,
dest);
json_add_channel_id(req->js, "channel_id", &dest->channel_id);
json_add_psbt(req->js, "signed_psbt", dest->psbt);
send_outreq(req);
}
struct command_result *
perform_openchannel_signed(struct multifundchannel_command *mfc)
{
plugin_log(mfc->cmd->plugin, LOG_DBG,
"mfc %"PRIu64": parallel `openchannel_signed`.",
mfc->id);
mfc->pending = dest_count(mfc, OPEN_CHANNEL);
for (size_t i = 0; i < tal_count(mfc->destinations); i++) {
if (!is_v2(&mfc->destinations[i]))
continue;
update_node_psbt(mfc, mfc->psbt,
&mfc->destinations[i].psbt);
openchannel_signed_dest(&mfc->destinations[i]);
}
assert(mfc->pending != 0);
return command_still_pending(mfc->cmd);
}
static struct command_result *
collect_sigs(struct multifundchannel_command *mfc)
{
if (mfc->sigs_collected)
return NULL;
mfc->sigs_collected = true;
for (size_t i = 0; i < tal_count(mfc->destinations); i++) {
struct multifundchannel_destination *dest;
struct bitcoin_txid dest_txid;
dest = &mfc->destinations[i];
if (!is_v2(dest)) {
assert(dest->state == MULTIFUNDCHANNEL_COMPLETED);
continue;
}
assert(dest->state == MULTIFUNDCHANNEL_SIGNED);
psbt_txid(NULL, dest->psbt, &dest_txid, NULL);
assert(bitcoin_txid_eq(mfc->txid, &dest_txid));
}
return perform_signpsbt(mfc);
}
struct command_result *
check_sigs_ready(struct multifundchannel_command *mfc)
{
static struct command_result *result;
bool ready = true;
for (size_t i = 0; i < tal_count(mfc->destinations); i++) {
enum multifundchannel_state state =
is_v2(&mfc->destinations[i]) ?
MULTIFUNDCHANNEL_SIGNED :
MULTIFUNDCHANNEL_COMPLETED;
ready &= mfc->destinations[i].state == state;
}
if (ready) {
result = collect_sigs(mfc);
if (result)
return result;
}
return command_still_pending(mfc->cmd);
}
static struct command_result *json_peer_sigs(struct command *cmd,
const char *buf,
const jsmntok_t *params)
{
struct channel_id cid;
const struct wally_psbt *psbt;
struct multifundchannel_destination *dest;
const char *err;
err = json_scan(tmpctx, buf, params,
"{openchannel_peer_sigs:"
"{channel_id:%,signed_psbt:%}}",
JSON_SCAN(json_to_channel_id, &cid),
JSON_SCAN_TAL(cmd, json_to_psbt, &psbt));
if (err)
plugin_err(cmd->plugin,
"`openchannel_peer_sigs` did not scan: %s. %.*s",
err, json_tok_full_len(params),
json_tok_full(buf, params));
dest = find_dest_by_channel_id(&cid);
if (!dest) {
plugin_log(cmd->plugin, LOG_DBG,
"mfc ??: `openchannel_peer_sigs` no "
"pending dest found for channel_id %s",
fmt_channel_id(tmpctx, &cid));
return notification_handled(cmd);
}
plugin_log(cmd->plugin, LOG_DBG,
"mfc %"PRIu64":`openchannel_peer_sigs` notice received for"
" channel %s",
dest->mfc->id,
tal_hexstr(tmpctx, &cid, sizeof(cid)));
tal_wally_start();
if (wally_psbt_combine(dest->mfc->psbt, psbt) != WALLY_OK)
plugin_err(cmd->plugin,
"mfc %"PRIu64": Unable to combine signed "
"PSBT with roll-up. "
"Signed %s, prev %s", dest->mfc->id,
fmt_wally_psbt(tmpctx, psbt),
fmt_wally_psbt(tmpctx, dest->mfc->psbt));
tal_wally_end(dest->mfc->psbt);
if (dest->state != MULTIFUNDCHANNEL_SECURED)
dest->state = MULTIFUNDCHANNEL_SIGNED_NOT_SECURED;
else {
dest->state = MULTIFUNDCHANNEL_SIGNED;
}
check_sigs_ready(dest->mfc);
return notification_handled(cmd);
}
static struct command_result *
funding_transaction_established(struct multifundchannel_command *mfc)
{
psbt_elements_normalize_fees(mfc->psbt);
mfc->txid = tal(mfc, struct bitcoin_txid);
psbt_txid(NULL, mfc->psbt, mfc->txid, NULL);
plugin_log(mfc->cmd->plugin, LOG_DBG,
"mfc %"PRIu64": funding tx %s",
mfc->id,
fmt_bitcoin_txid(tmpctx, mfc->txid));
if (dest_count(mfc, FUND_CHANNEL) == 0)
return check_sigs_ready(mfc);
for (size_t i = 0; i < tal_count(mfc->destinations); i++) {
struct multifundchannel_destination *dest;
if (is_v2(&mfc->destinations[i]))
continue;
dest = &mfc->destinations[i];
dest->outnum = mfc->psbt->num_outputs;
for (size_t j = 0; j < mfc->psbt->num_outputs; j++) {
if (memeq(dest->funding_script,
tal_bytelen(dest->funding_script),
mfc->psbt->outputs[j].script,
mfc->psbt->outputs[j].script_len))
dest->outnum = j;
}
if (dest->outnum == mfc->psbt->num_outputs)
abort();
assert(dest->outnum < mfc->psbt->num_outputs);
}
return perform_fundchannel_complete(mfc);
}
static struct command_result *
openchannel_update_returned(struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
--mfc->pending;
if (mfc->pending == 0)
return perform_openchannel_update(mfc);
else
return command_still_pending(mfc->cmd);
}
static struct command_result *
openchannel_update_ok(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
const jsmntok_t *psbt_tok, *done_tok;
bool done;
plugin_log(mfc->cmd->plugin, LOG_DBG,
"mfc %"PRIu64", dest %u: openchannel_update %s returned.",
mfc->id, dest->index,
fmt_node_id(tmpctx, &dest->id));
assert(!dest->updated_psbt);
psbt_tok = json_get_member(buf, result, "psbt");
if (!psbt_tok)
plugin_err(cmd->plugin,
"`openchannel_update` did not return "
"'psbt': %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
dest->updated_psbt = json_to_psbt(dest->mfc, buf, psbt_tok);
if (!dest->updated_psbt)
plugin_err(cmd->plugin,
"`openchannel_update` returned invalid "
"'psbt': %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
done_tok = json_get_member(buf, result, "commitments_secured");
if (!done_tok)
plugin_err(cmd->plugin,
"`openchannel_update` failed to return "
"'commitments_secured': %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
if (!json_to_bool(buf, done_tok, &done))
plugin_err(cmd->plugin,
"`openchannel_update` returned invalid "
"'commitments_secured': %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
if (dest->state == MULTIFUNDCHANNEL_STARTED)
dest->state = MULTIFUNDCHANNEL_UPDATED;
if (done) {
const jsmntok_t *outnum_tok, *close_to_tok;
outnum_tok = json_get_member(buf, result, "funding_outnum");
if (!outnum_tok)
plugin_err(cmd->plugin,
"`openchannel_update` did not return "
"'funding_outnum': %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
if (!json_to_number(buf, outnum_tok, &dest->outnum))
plugin_err(cmd->plugin,
"`openchannel_update` returned invalid "
"'funding_outnum': %.*s",
json_tok_full_len(result),
json_tok_full(buf, result));
close_to_tok = json_get_member(buf, result, "close_to");
if (close_to_tok)
dest->close_to_script =
json_tok_bin_from_hex(dest->mfc, buf,
close_to_tok);
else
dest->close_to_script = NULL;
if (dest->state == MULTIFUNDCHANNEL_SIGNED_NOT_SECURED)
dest->state = MULTIFUNDCHANNEL_SIGNED;
else
dest->state = MULTIFUNDCHANNEL_SECURED;
}
return openchannel_update_returned(dest);
}
static struct command_result *
openchannel_update_err(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *error,
struct multifundchannel_destination *dest)
{
fail_destination_tok(dest, buf, error);
return openchannel_update_returned(dest);
}
static void
openchannel_update_dest(struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
struct command *cmd = mfc->cmd;
struct out_req *req;
plugin_log(cmd->plugin, LOG_DBG,
"mfc %"PRIu64", dest %u: `openchannel_update` %s "
"with psbt %s",
mfc->id, dest->index,
fmt_node_id(tmpctx, &dest->id),
fmt_wally_psbt(tmpctx, dest->psbt));
req = jsonrpc_request_start(cmd,
"openchannel_update",
&openchannel_update_ok,
&openchannel_update_err,
dest);
json_add_channel_id(req->js, "channel_id", &dest->channel_id);
json_add_psbt(req->js, "psbt", dest->psbt);
send_outreq(req);
}
struct command_result *
perform_openchannel_update(struct multifundchannel_command *mfc)
{
size_t i, ready_count = 0;
plugin_log(mfc->cmd->plugin, LOG_DBG,
"mfc %"PRIu64": parallel `openchannel_update`.",
mfc->id);
for (i = 0; i < tal_count(mfc->destinations); i++) {
struct multifundchannel_destination *dest;
dest = &mfc->destinations[i];
if (dest->state == MULTIFUNDCHANNEL_FAILED)
return redo_multifundchannel(mfc,
"openchannel_update",
dest->error_message);
if (dest->state == MULTIFUNDCHANNEL_SECURED ||
dest->state == MULTIFUNDCHANNEL_SIGNED) {
ready_count++;
continue;
}
assert(dest->state == MULTIFUNDCHANNEL_UPDATED ||
dest->state == MULTIFUNDCHANNEL_SIGNED_NOT_SECURED ||
dest->state == MULTIFUNDCHANNEL_STARTED);
}
if (ready_count == dest_count(mfc, OPEN_CHANNEL))
return funding_transaction_established(mfc);
for (i = 0; i < tal_count(mfc->destinations); i++) {
struct multifundchannel_destination *dest;
dest = &mfc->destinations[i];
if (!is_v2(dest))
continue;
if (!update_parent_psbt(mfc, dest, dest->psbt,
dest->updated_psbt,
&mfc->psbt)) {
fail_destination_msg(dest, FUNDING_PSBT_INVALID,
"Unable to update parent "
"with node's PSBT");
return redo_multifundchannel(mfc,
"openchannel_init_parent",
dest->error_message);
}
psbt_sort_by_serial_id(mfc->psbt);
tal_free(dest->psbt);
dest->psbt = dest->updated_psbt;
dest->updated_psbt = NULL;
}
for (i = 0; i < tal_count(mfc->destinations); i++) {
struct multifundchannel_destination *dest;
dest = &mfc->destinations[i];
if (!is_v2(dest))
continue;
if (!update_node_psbt(mfc, mfc->psbt, &dest->psbt)) {
fail_destination_msg(dest, FUNDING_PSBT_INVALID,
"Unable to update peer's PSBT"
" with parent PSBT");
return redo_multifundchannel(mfc,
"openchannel_init_node",
dest->error_message);
}
}
mfc->pending = dest_count(mfc, OPEN_CHANNEL);
for (i = 0; i < tal_count(mfc->destinations); i++) {
if (is_v2(&mfc->destinations[i]))
openchannel_update_dest(&mfc->destinations[i]);
}
assert(mfc->pending != 0);
return command_still_pending(mfc->cmd);
}
static struct command_result *
openchannel_init_done(struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
--mfc->pending;
if (mfc->pending == 0)
return after_channel_start(mfc);
else
return command_still_pending(mfc->cmd);
}
static struct command_result *
openchannel_init_ok(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *result,
struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
const char *err;
plugin_log(mfc->cmd->plugin, LOG_DBG,
"mfc %"PRIu64", dest %u: openchannel_init %s done.",
mfc->id, dest->index,
fmt_node_id(tmpctx, &dest->id));
err = json_scan(mfc, buf, result,
"{psbt:%,"
"channel_id:%,"
"funding_serial:%,"
"channel_type:{bits:%}}",
JSON_SCAN_TAL(mfc, json_to_psbt, &dest->updated_psbt),
JSON_SCAN(json_to_channel_id, &dest->channel_id),
JSON_SCAN(json_to_u64, &dest->funding_serial),
JSON_SCAN_TAL(mfc, json_bits_to_channel_type, &dest->channel_type));
if (err) {
plugin_err(cmd->plugin,
"openchannel_init bad return %.*s: %s",
json_tok_full_len(result),
json_tok_full(buf, result), err);
}
dest->state = MULTIFUNDCHANNEL_STARTED;
if (!update_parent_psbt(dest->mfc, dest, dest->psbt,
dest->updated_psbt, &mfc->psbt)) {
fail_destination_msg(dest, FUNDING_PSBT_INVALID,
"Unable to update parent"
" with node's PSBT");
}
tal_wally_start();
wally_psbt_clone_alloc(dest->updated_psbt, 0, &dest->psbt);
tal_wally_end_onto(mfc, dest->updated_psbt, struct wally_psbt);
return openchannel_init_done(dest);
}
static struct command_result *
openchannel_init_err(struct command *cmd,
const char *method,
const char *buf,
const jsmntok_t *error,
struct multifundchannel_destination *dest)
{
fail_destination_tok(dest, buf, error);
return openchannel_init_done(dest);
}
struct command_result *
openchannel_init_dest(struct multifundchannel_destination *dest)
{
struct multifundchannel_command *mfc = dest->mfc;
struct command *cmd = mfc->cmd;
struct out_req *req;
plugin_log(cmd->plugin, LOG_DBG,
"mfc %"PRIu64", dest %u: openchannel_init %s.",
mfc->id, dest->index,
fmt_node_id(tmpctx, &dest->id));
req = jsonrpc_request_start(cmd,
"openchannel_init",
&openchannel_init_ok,
&openchannel_init_err,
dest);
json_add_node_id(req->js, "id", &dest->id);
assert(!dest->all);
json_add_string(req->js, "amount",
fmt_amount_sat(tmpctx, dest->amount));
tal_wally_start();
wally_psbt_clone_alloc(mfc->psbt, 0, &dest->psbt);
tal_wally_end_onto(mfc, dest->psbt, struct wally_psbt);
json_add_psbt(req->js, "initialpsbt", dest->psbt);
if (mfc->cmtmt_feerate_str)
json_add_string(req->js, "commitment_feerate",
mfc->cmtmt_feerate_str);
if (mfc->feerate_str) {
json_add_string(req->js, "funding_feerate",
mfc->feerate_str);
if (!mfc->cmtmt_feerate_str)
json_add_string(req->js, "commitment_feerate",
mfc->feerate_str);
}
json_add_bool(req->js, "announce", dest->announce);
if (dest->close_to_str)
json_add_string(req->js, "close_to", dest->close_to_str);
if (amount_msat_greater(dest->push_msat, AMOUNT_MSAT(0)))
plugin_log(cmd->plugin, LOG_INFORM,
"Using openchannel for %s open, "
"ignoring `push_msat` of %s",
fmt_node_id(tmpctx, &dest->id),
fmt_amount_msat(tmpctx, dest->push_msat));
if (!amount_sat_is_zero(dest->request_amt)) {
json_add_string(req->js, "request_amt",
fmt_amount_sat(tmpctx, dest->request_amt));
json_add_string(req->js, "compact_lease",
lease_rates_tohex(tmpctx, dest->rates));
}
if (dest->channel_type) {
json_add_channel_type_arr(req->js,
"channel_type", dest->channel_type);
}
return send_outreq(req);
}
static struct command_result *psbt_error(struct command *aux_cmd,
const char *methodname,
const char *buf,
const jsmntok_t *result,
struct channel_id *cid)
{
plugin_log(aux_cmd->plugin, LOG_UNUSUAL,
"Failed %s for waiting channel %s: %.*s",
methodname,
fmt_channel_id(tmpctx, cid),
json_tok_full_len(result),
json_tok_full(buf, result));
return aux_command_done(aux_cmd);
}
static struct command_result *sendpsbt_done(struct command *aux_cmd,
const char *methodname,
const char *buf,
const jsmntok_t *result,
struct channel_id *cid)
{
plugin_log(aux_cmd->plugin, LOG_INFORM,
"Signed and sent psbt for waiting channel %s",
fmt_channel_id(tmpctx, cid));
return aux_command_done(aux_cmd);
}
static struct command_result *signpsbt_done(struct command *aux_cmd,
const char *methodname,
const char *buf,
const jsmntok_t *result,
struct channel_id *cid)
{
const jsmntok_t *psbttok = json_get_member(buf, result, "signed_psbt");
struct wally_psbt *psbt = json_to_psbt(tmpctx, buf, psbttok);
struct out_req *req;
req = jsonrpc_request_start(aux_cmd, "sendpsbt",
sendpsbt_done, psbt_error,
cid);
json_add_psbt(req->js, "psbt", psbt);
return send_outreq(req);
}
static void list_awaiting_channels(struct command *init_cmd)
{
const char *buf;
size_t i;
const jsmntok_t *resp, *t, *channels;
resp = jsonrpc_request_sync(tmpctx, init_cmd,
"listpeerchannels",
NULL, &buf);
channels = json_get_member(buf, resp, "channels");
json_for_each_arr(i, t, channels) {
struct out_req *req;
const char *state;
struct channel_id cid;
struct command *aux_cmd;
struct wally_psbt *psbt;
bool withheld;
if (json_scan(tmpctx, buf, t, "{state:%,channel_id:%,funding:{withheld:%,psbt:%}}",
JSON_SCAN_TAL(tmpctx, json_strdup, &state),
JSON_SCAN(json_tok_channel_id, &cid),
JSON_SCAN(json_to_bool, &withheld),
JSON_SCAN_TAL(tmpctx, json_to_psbt, &psbt)) != NULL)
continue;
if (!streq(state, "CHANNELD_AWAITING_LOCKIN")
&& !streq(state, "DUALOPEND_AWAITING_LOCKIN"))
continue;
if (withheld)
continue;
aux_cmd = aux_command(init_cmd);
req = jsonrpc_request_start(aux_cmd, "signpsbt",
signpsbt_done, psbt_error,
tal_dup(aux_cmd, struct channel_id, &cid));
json_add_psbt(req->js, "psbt", psbt);
send_outreq(req);
}
}
void openchannel_init(struct command *init_cmd, const char *b, const jsmntok_t *t)
{
list_head_init(&mfc_commands);
list_awaiting_channels(init_cmd);
}
const struct plugin_notification openchannel_notifs[] = {
{
"openchannel_peer_sigs",
json_peer_sigs,
}
};
const size_t num_openchannel_notifs = ARRAY_SIZE(openchannel_notifs);