Browse Source

lightningd: allow multiple cancels on a single fundchannel command.

Instead of taking over the ->cmd pointer, append ourselves to a list
of cancels.  This fixes the test_funding_cancel_race.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
pull/2938/head
Rusty Russell 6 years ago
committed by neil saitug
parent
commit
280bd60988
  1. 34
      lightningd/opening_control.c
  2. 1
      tests/test_connection.py

34
lightningd/opening_control.c

@ -88,6 +88,9 @@ struct funding_channel {
/* Whether or not this is in the middle of getting funded */ /* Whether or not this is in the middle of getting funded */
bool inflight; bool inflight;
/* Any commands trying to cancel us. */
struct command **cancels;
}; };
static void uncommitted_channel_disconnect(struct uncommitted_channel *uc, static void uncommitted_channel_disconnect(struct uncommitted_channel *uc,
@ -265,6 +268,11 @@ static void funding_success(struct channel *channel)
struct funding_channel *fc = channel->peer->uncommitted_channel->fc; struct funding_channel *fc = channel->peer->uncommitted_channel->fc;
struct command *cmd = fc->cmd; struct command *cmd = fc->cmd;
/* Well, those cancels didn't work! */
for (size_t i = 0; i < tal_count(fc->cancels); i++)
was_pending(command_fail(fc->cancels[i], LIGHTNINGD,
"Funding succeeded before cancel"));
response = json_stream_success(cmd); response = json_stream_success(cmd);
json_add_string(response, "channel_id", json_add_string(response, "channel_id",
type_to_string(tmpctx, struct channel_id, &fc->cid)); type_to_string(tmpctx, struct channel_id, &fc->cid));
@ -672,8 +680,6 @@ static void opening_funder_failed(struct subd *openingd, const u8 *msg,
char *desc; char *desc;
bool is_err; bool is_err;
struct json_stream *response;
if (!fromwire_opening_funder_failed(msg, msg, &desc, &is_err)) { if (!fromwire_opening_funder_failed(msg, msg, &desc, &is_err)) {
log_broken(uc->log, log_broken(uc->log,
"bad OPENING_FUNDER_FAILED %s", "bad OPENING_FUNDER_FAILED %s",
@ -685,14 +691,26 @@ static void opening_funder_failed(struct subd *openingd, const u8 *msg,
return; return;
} }
/* Tell anyone who was trying to cancel */
for (size_t i = 0; i < tal_count(uc->fc->cancels); i++) {
if (is_err) if (is_err)
was_pending(command_fail(uc->fc->cmd, LIGHTNINGD, "%s", desc)); was_pending(command_fail(uc->fc->cancels[i], LIGHTNINGD,
"Funding failed anyway: %s",
desc));
else { else {
response = json_stream_success(uc->fc->cmd); struct json_stream *response;
response = json_stream_success(uc->fc->cancels[i]);
json_add_string(response, "cancelled", desc); json_add_string(response, "cancelled", desc);
was_pending(command_success(uc->fc->cmd, response)); was_pending(command_success(uc->fc->cancels[i],
response));
}
} }
/* Tell any fundchannel_complete or fundchannel command */
if (uc->fc->cmd)
was_pending(command_fail(uc->fc->cmd, LIGHTNINGD, "%s", desc));
/* Clear uc->fc, so we can try again, and so we don't fail twice /* Clear uc->fc, so we can try again, and so we don't fail twice
* if they close. */ * if they close. */
uc->fc = tal_free(uc->fc); uc->fc = tal_free(uc->fc);
@ -1200,8 +1218,8 @@ static struct command_result *json_fund_channel_cancel(struct command *cmd,
* question about 'how long cancelable'. * question about 'how long cancelable'.
*/ */
/* Update the cmd to the new cmd */ /* Make sure this gets notified if we succeed or cancel */
peer->uncommitted_channel->fc->cmd = cmd; tal_arr_expand(&peer->uncommitted_channel->fc->cancels, cmd);
msg = towire_opening_funder_cancel(NULL); msg = towire_opening_funder_cancel(NULL);
subd_send_msg(peer->uncommitted_channel->openingd, take(msg)); subd_send_msg(peer->uncommitted_channel->openingd, take(msg));
return command_still_pending(cmd); return command_still_pending(cmd);
@ -1227,6 +1245,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd,
max_funding_satoshi = get_chainparams(cmd->ld)->max_funding; max_funding_satoshi = get_chainparams(cmd->ld)->max_funding;
fc->cmd = cmd; fc->cmd = cmd;
fc->cancels = tal_arr(fc, struct command *, 0);
fc->uc = NULL; fc->uc = NULL;
fc->inflight = false; fc->inflight = false;
if (!param(fc->cmd, buffer, params, if (!param(fc->cmd, buffer, params,
@ -1321,6 +1340,7 @@ static struct command_result *json_fund_channel(struct command *cmd,
max_funding_satoshi = get_chainparams(cmd->ld)->max_funding; max_funding_satoshi = get_chainparams(cmd->ld)->max_funding;
fc->cmd = cmd; fc->cmd = cmd;
fc->cancels = tal_arr(fc, struct command *, 0);
fc->uc = NULL; fc->uc = NULL;
fc->inflight = false; fc->inflight = false;
fc->wtx = tal(fc, struct wallet_tx); fc->wtx = tal(fc, struct wallet_tx);

1
tests/test_connection.py

@ -853,7 +853,6 @@ def test_funding_external_wallet_corners(node_factory, bitcoind):
l1.rpc.fundchannel_start(l2.info['id'], amount) l1.rpc.fundchannel_start(l2.info['id'], amount)
@pytest.mark.xfail(strict=True)
def test_funding_cancel_race(node_factory, bitcoind, executor): def test_funding_cancel_race(node_factory, bitcoind, executor):
l1 = node_factory.get_node() l1 = node_factory.get_node()
nodes = node_factory.get_nodes(100) nodes = node_factory.get_nodes(100)

Loading…
Cancel
Save