Skip to content

Commit

Permalink
openingd/: Fail fundchannel_start if we already are, or will become…
Browse files Browse the repository at this point in the history
…, the fundee.

Fixes: #4108
  • Loading branch information
ZmnSCPxj committed Oct 8, 2020
1 parent a491746 commit 50a6f0c
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 4 deletions.
2 changes: 2 additions & 0 deletions lightningd/opening_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ new_uncommitted_channel(struct peer *peer)
uc->peer->uncommitted_channel = uc;
tal_add_destructor(uc, destroy_uncommitted_channel);

uc->is_fundee = false;

return uc;
}

Expand Down
5 changes: 5 additions & 0 deletions lightningd/opening_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ struct uncommitted_channel {
/* Public key for funding tx. */
struct pubkey local_funding_pubkey;

/* If true, we are already in fundee-mode and any future
* `fundchannel_start` on our end should fail.
*/
bool is_fundee;

/* These are *not* filled in by new_uncommitted_channel: */

/* Minimum funding depth (if opener == REMOTE). */
Expand Down
41 changes: 40 additions & 1 deletion lightningd/opening_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ wallet_commit_channel(struct lightningd *ld,
bool option_static_remotekey;
bool option_anchor_outputs;

/* We cannot both be the fundee *and* have a `fundchannel_start`
* command running!
*/
assert(!(uc->is_fundee && uc->fc));

/* Get a key to use for closing outputs from this tx */
final_key_idx = wallet_get_newindex(ld);
if (final_key_idx == -1) {
Expand Down Expand Up @@ -415,6 +420,17 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp,
tal_free(fc->uc);
}

static void
opening_funder_failed_cancel_commands(struct uncommitted_channel *uc,
const char *desc);
static void opening_fundee_started(struct subd *openingd UNUSED,
struct uncommitted_channel *uc)
{
/* Cancel any pending funder-side commands: we are the fundee. */
opening_funder_failed_cancel_commands(uc, "We are the fundee");
uc->is_fundee = true;
}

static void opening_fundee_finished(struct subd *openingd,
const u8 *reply,
const int *fds,
Expand Down Expand Up @@ -551,6 +567,17 @@ static void opening_funder_failed(struct subd *openingd, const u8 *msg,
return;
}

opening_funder_failed_cancel_commands(uc, desc);
}

static void
opening_funder_failed_cancel_commands(struct uncommitted_channel *uc,
const char *desc)
{
/* If no funding command(s) pending, do nothing. */
if (!uc->fc)
return;

/* Tell anyone who was trying to cancel */
for (size_t i = 0; i < tal_count(uc->fc->cancels); i++) {
struct json_stream *response;
Expand All @@ -565,7 +592,11 @@ static void opening_funder_failed(struct subd *openingd, const u8 *msg,
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
* if they close. */
* if they close.
* This code is also used in the case where we turn out to already
* be the fundee, in which case we should not have any `fc` at all,
* so we definitely should clear this.
*/
uc->fc = tal_free(uc->fc);
}

Expand Down Expand Up @@ -797,6 +828,10 @@ static unsigned int openingd_msg(struct subd *openingd,
opening_funder_failed(openingd, msg, uc);
return 0;

case WIRE_OPENINGD_WILL_BE_FUNDEE:
opening_fundee_started(openingd, uc);
return 0;

case WIRE_OPENINGD_FUNDEE:
if (tal_count(fds) != 3)
return 3;
Expand Down Expand Up @@ -1086,6 +1121,10 @@ static struct command_result *json_fund_channel_start(struct command *cmd,
return command_fail(cmd, LIGHTNINGD, "Already funding channel");
}

if (peer->uncommitted_channel->is_fundee) {
return command_fail(cmd, LIGHTNINGD, "We are the fundee");
}

/* BOLT #2:
* - if both nodes advertised `option_support_large_channel`:
* - MAY set `funding_satoshis` greater than or equal to 2^24 satoshi.
Expand Down
9 changes: 9 additions & 0 deletions openingd/openingd.c
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,14 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg)
if (!state->upfront_shutdown_script[LOCAL])
state->upfront_shutdown_script[LOCAL] = no_upfront_shutdown_script(state, state);

/* Just before we accept, we tell the master that we are now
* going to be a fundee, so it should fail any pending
* `fundchannel_start` on this peer, and fail all future ones
* as well.
*/
msg = towire_openingd_will_be_fundee(NULL);
wire_sync_write(REQ_FD, take(msg));

/* OK, we accept! */
accept_tlvs = tlv_accept_channel_tlvs_new(tmpctx);
accept_tlvs->upfront_shutdown_script
Expand Down Expand Up @@ -1333,6 +1341,7 @@ static u8 *handle_master_in(struct state *state)
case WIRE_OPENINGD_INIT:
case WIRE_OPENINGD_FUNDER_REPLY:
case WIRE_OPENINGD_FUNDER_START_REPLY:
case WIRE_OPENINGD_WILL_BE_FUNDEE:
case WIRE_OPENINGD_FUNDEE:
case WIRE_OPENINGD_FUNDER_FAILED:
case WIRE_OPENINGD_GOT_OFFER:
Expand Down
4 changes: 4 additions & 0 deletions openingd/openingd_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ msgtype,openingd_funder_cancel,6013
msgtype,openingd_funder_failed,6004
msgdata,openingd_funder_failed,reason,wirestring,

# Openingd->master: we will enter into fundee route
# and ignore all subsequent master->openingd messsages.
msgtype,openingd_will_be_fundee,6023

# Openingd->master: they offered channel.
# This gives their txid and info, means we can send funding_signed: we're done.
msgtype,openingd_fundee,6003
Expand Down
25 changes: 24 additions & 1 deletion openingd/openingd_wiregen.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion openingd/openingd_wiregen.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion tests/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2653,7 +2653,6 @@ def test_connection_timeout(node_factory):
l1.daemon.wait_for_log('conn timed out')


@pytest.mark.xfail(strict=True)
def test_fundchannel_start_alternate(node_factory, executor):
''' Test to see what happens if two nodes start channeling to
each other alternately.
Expand Down

0 comments on commit 50a6f0c

Please sign in to comment.