From a34425abd162684a81dfa8d022c8fc4d7bc5dda2 Mon Sep 17 00:00:00 2001 From: niftynei Date: Thu, 22 Oct 2020 14:29:28 -0500 Subject: [PATCH] mfc-df: after sigs are collected, go sign the psbt --- plugins/spender/multifundchannel.c | 10 ++-- plugins/spender/multifundchannel.h | 6 ++ plugins/spender/openchannel.c | 91 +++++++++++------------------- plugins/spender/openchannel.h | 3 + 4 files changed, 48 insertions(+), 62 deletions(-) diff --git a/plugins/spender/multifundchannel.c b/plugins/spender/multifundchannel.c index 3d58ac789..079517ab6 100644 --- a/plugins/spender/multifundchannel.c +++ b/plugins/spender/multifundchannel.c @@ -1467,9 +1467,6 @@ fundchannel_complete_done(struct multifundchannel_destination *dest) return command_still_pending(mfc->cmd); } -static struct command_result * -perform_signpsbt(struct multifundchannel_command *mfc); - static struct command_result * after_fundchannel_complete(struct multifundchannel_command *mfc) { @@ -1515,14 +1512,17 @@ after_signpsbt(struct command *cmd, const jsmntok_t *result, struct multifundchannel_command *mfc); -static struct command_result * +struct command_result * perform_signpsbt(struct multifundchannel_command *mfc) { struct out_req *req; + /* Now we sign our inputs. You do remember which inputs + * are yours, right? */ plugin_log(mfc->cmd->plugin, LOG_DBG, "mfc %"PRIu64": signpsbt.", mfc->id); + /* FIXME: indicate our inputs with signonly */ req = jsonrpc_request_start(mfc->cmd->plugin, mfc->cmd, "signpsbt", &after_signpsbt, @@ -1911,6 +1911,8 @@ json_multifundchannel(struct command *cmd, mfc->final_tx = NULL; mfc->final_txid = NULL; + mfc->sigs_collected = false; + return perform_multifundchannel(mfc); } diff --git a/plugins/spender/multifundchannel.h b/plugins/spender/multifundchannel.h index 56cd13b3e..ff6e53138 100644 --- a/plugins/spender/multifundchannel.h +++ b/plugins/spender/multifundchannel.h @@ -229,6 +229,9 @@ struct multifundchannel_command { /* V2 things */ struct list_node list; + + /* V2 channel opens use this flag to gate PSBT signing */ + bool sigs_collected; }; /* Use this instead of forward_error. */ @@ -256,6 +259,9 @@ after_channel_start(struct multifundchannel_command *mfc); struct command_result * perform_fundchannel_complete(struct multifundchannel_command *mfc); +struct command_result * +perform_signpsbt(struct multifundchannel_command *mfc); + struct command_result * redo_multifundchannel(struct multifundchannel_command *mfc, const char *failing_method); diff --git a/plugins/spender/openchannel.c b/plugins/spender/openchannel.c index fa7d6f067..9c287b97d 100644 --- a/plugins/spender/openchannel.c +++ b/plugins/spender/openchannel.c @@ -477,7 +477,7 @@ openchannel_signed_dest(struct multifundchannel_destination *dest) send_outreq(cmd->plugin, req); } -static struct command_result * +struct command_result * perform_openchannel_signed(struct multifundchannel_command *mfc) { plugin_log(mfc->cmd->plugin, LOG_DBG, @@ -514,47 +514,17 @@ perform_openchannel_signed(struct multifundchannel_command *mfc) return command_still_pending(mfc->cmd); } -static struct command_result * -after_psbt_signed(struct command *cmd, - const char *buf, - const jsmntok_t *result, - struct multifundchannel_command *mfc) -{ - const jsmntok_t *field; - struct wally_psbt *signed_psbt; - - plugin_log(mfc->cmd->plugin, LOG_DBG, - "mfc %"PRIu64": `signpsbt` completed", - mfc->id); - - field = json_get_member(buf, result, "signed_psbt"); - if (!field) - plugin_err(mfc->cmd->plugin, - "`signpsbt` did not return 'signed_psbt'? %.*s", - json_tok_full_len(result), - json_tok_full(buf, result)); - if (!json_to_psbt(tmpctx, buf, field, &signed_psbt)) - plugin_err(mfc->cmd->plugin, - "`signpsbt` returned invalid 'signed_psbt' %.*s", - json_tok_full_len(field), - json_tok_full(buf, field)); - - tal_free(mfc->psbt); - mfc->psbt = tal_steal(mfc, signed_psbt); - - return perform_openchannel_signed(mfc); -} - static struct command_result * collect_sigs(struct multifundchannel_command *mfc) { - /* We need to sign the PSBT, we also need to - * wait for all of the sigs to come in */ - struct out_req *req; - struct bitcoin_txid mfc_txid; - psbt_txid(NULL, mfc->psbt, &mfc_txid, NULL); - + /* There's a very small chance that we'll get a + * race condition between when a signature arrives + * and all of the fundchannel_completes return. + * This flag helps us avoid invoking this twice.*/ + if (mfc->sigs_collected) + return NULL; + mfc->sigs_collected = true; /* But first! we sanity check that everyone's * expecting the same funding txid */ for (size_t i = 0; i < tal_count(mfc->destinations); i++) { @@ -562,37 +532,42 @@ collect_sigs(struct multifundchannel_command *mfc) struct bitcoin_txid dest_txid; dest = &mfc->destinations[i]; - assert(dest->state == MULTIFUNDCHANNEL_SECURED || - dest->state == MULTIFUNDCHANNEL_SIGNED); + if (dest->protocol == FUND_CHANNEL) { + /* Since we're here, double check that + * every v1 has their commitment txs */ + 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)); + assert(bitcoin_txid_eq(mfc->txid, &dest_txid)); } - /* Now we sign our inputs. You do remember which inputs - * are yours, right? */ - plugin_log(mfc->cmd->plugin, LOG_DBG, - "mfc %"PRIu64": signpsbt.", mfc->id); - - req = jsonrpc_request_start(mfc->cmd->plugin, mfc->cmd, - "signpsbt", - &after_psbt_signed, - &mfc_forward_error, - mfc); - json_add_psbt(req->js, "psbt", mfc->psbt); - return send_outreq(mfc->cmd->plugin, req); + 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++) - ready &= mfc->destinations[i].state == - MULTIFUNDCHANNEL_SIGNED; - if (ready) - collect_sigs(mfc); + for (size_t i = 0; i < tal_count(mfc->destinations); i++) { + enum multifundchannel_state state = + mfc->destinations[i].protocol == OPEN_CHANNEL ? + 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); } diff --git a/plugins/spender/openchannel.h b/plugins/spender/openchannel.h index a6191ff33..bd2957b14 100644 --- a/plugins/spender/openchannel.h +++ b/plugins/spender/openchannel.h @@ -24,4 +24,7 @@ perform_openchannel_update(struct multifundchannel_command *mfc); struct command_result * check_sigs_ready(struct multifundchannel_command *mfc); +struct command_result * +perform_openchannel_signed(struct multifundchannel_command *mfc); + #endif /* LIGHTNING_PLUGINS_SPENDER_OPENCHANNEL_H */