Skip to content

Commit 7e32417

Browse files
niftyneicdecker
authored andcommitted
df-tests: simultaneous openchannel_init (while in progress)
Reject a peer's request to open a channel while we're already in progress
1 parent 2c9ce25 commit 7e32417

File tree

3 files changed

+79
-16
lines changed

3 files changed

+79
-16
lines changed

lightningd/dual_open_control.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ static void
361361
openchannel2_hook_cb(struct openchannel2_payload *payload STEALS)
362362
{
363363
struct subd *dualopend = payload->dualopend;
364+
struct uncommitted_channel *uc;
364365
u8 *msg;
365366

366367
/* Free payload regardless of what happens next */
@@ -370,6 +371,18 @@ openchannel2_hook_cb(struct openchannel2_payload *payload STEALS)
370371
if (!dualopend)
371372
return;
372373

374+
assert(dualopend->ctype == UNCOMMITTED);
375+
uc = dualopend->channel;
376+
377+
/* Channel open is currently in progress elsewhere! */
378+
if (uc->fc || uc->got_offer) {
379+
msg = towire_dualopend_fail(NULL, "Already initiated channel"
380+
" open");
381+
log_debug(dualopend->ld->log,
382+
"Our open in progress, denying their offer");
383+
return subd_send_msg(dualopend, take(msg));
384+
}
385+
373386
tal_del_destructor2(dualopend, openchannel2_remove_dualopend, payload);
374387

375388
if (payload->err_msg) {
@@ -407,6 +420,7 @@ openchannel2_hook_cb(struct openchannel2_payload *payload STEALS)
407420
}
408421
}
409422

423+
uc->got_offer = true;
410424
msg = towire_dualopend_got_offer_reply(NULL, payload->accepter_funding,
411425
payload->funding_feerate_per_kw,
412426
payload->psbt,
@@ -1146,6 +1160,7 @@ static void open_failed(struct subd *dualopend, const u8 *msg)
11461160

11471161
assert(dualopend->ctype == UNCOMMITTED);
11481162
uc = dualopend->channel;
1163+
uc->got_offer = false;
11491164

11501165
if (!fromwire_dualopend_failed(msg, msg, &desc)) {
11511166
log_broken(uc->log,
@@ -1427,7 +1442,15 @@ static void accepter_got_offer(struct subd *dualopend,
14271442

14281443
if (peer_active_channel(uc->peer)) {
14291444
subd_send_msg(dualopend,
1430-
take(towire_dualopend_fail(NULL, "Already have active channel")));
1445+
take(towire_dualopend_fail(NULL,
1446+
"Already have active channel")));
1447+
return;
1448+
}
1449+
1450+
if (uc->fc) {
1451+
subd_send_msg(dualopend,
1452+
take(towire_dualopend_fail(NULL,
1453+
"Already initiated channel open")));
14311454
return;
14321455
}
14331456

@@ -1773,6 +1796,11 @@ static struct command_result *json_openchannel_init(struct command *cmd,
17731796
return command_fail(cmd, LIGHTNINGD, "Already funding channel");
17741797
}
17751798

1799+
if (peer->uncommitted_channel->got_offer) {
1800+
return command_fail(cmd, LIGHTNINGD,
1801+
"Channel open in progress");
1802+
}
1803+
17761804
#if EXPERIMENTAL_FEATURES
17771805
if (!feature_negotiated(cmd->ld->our_features,
17781806
peer->their_features,

openingd/dualopend.c

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -277,16 +277,13 @@ static void negotiation_aborted(struct state *state, const char *why)
277277
memset(&state->channel_id, 0, sizeof(state->channel_id));
278278
state->channel = tal_free(state->channel);
279279
state->changeset = tal_free(state->changeset);
280-
if (state->psbt)
281-
tal_free(state->psbt);
282280

283281
for (size_t i = 0; i < NUM_TX_MSGS; i++)
284282
state->tx_msg_count[i] = 0;
285283
}
286284

287-
/*~ For negotiation failures: we tell them the parameter we didn't like. */
288-
static void negotiation_failed(struct state *state,
289-
const char *fmt, ...)
285+
static void open_error(struct state *state,
286+
const char *fmt, ...)
290287
{
291288
va_list ap;
292289
const char *errmsg;
@@ -297,12 +294,27 @@ static void negotiation_failed(struct state *state,
297294
va_end(ap);
298295

299296
msg = towire_errorfmt(NULL, &state->channel_id,
300-
"You gave bad parameters: %s", errmsg);
297+
"%s", errmsg);
301298
sync_crypto_write(state->pps, take(msg));
302299

303300
negotiation_aborted(state, errmsg);
304301
}
305302

303+
304+
/*~ For negotiation failures: we tell them the parameter we didn't like. */
305+
static void negotiation_failed(struct state *state,
306+
const char *fmt, ...)
307+
{
308+
va_list ap;
309+
const char *errmsg;
310+
311+
va_start(ap, fmt);
312+
errmsg = tal_vfmt(tmpctx, fmt, ap);
313+
va_end(ap);
314+
315+
open_error(state, "You gave bad parameters: %s", errmsg);
316+
}
317+
306318
static void billboard_update(struct state *state)
307319
{
308320
const char *update = billboard_message(tmpctx, state->funding_locked,
@@ -885,9 +897,9 @@ fetch_psbt_changes(struct state *state, const struct wally_psbt *psbt)
885897
wire_sync_write(REQ_FD, take(msg));
886898
msg = wire_sync_read(tmpctx, REQ_FD);
887899

888-
if (fromwire_dualopend_fail(msg, msg, &err))
889-
status_failed(STATUS_FAIL_MASTER_IO, "%s", err);
890-
else if (fromwire_dualopend_psbt_updated(state, msg, &updated_psbt)) {
900+
if (fromwire_dualopend_fail(msg, msg, &err)) {
901+
open_error(state, "%s", err);
902+
} else if (fromwire_dualopend_psbt_updated(state, msg, &updated_psbt)) {
891903
return updated_psbt;
892904
#if DEVELOPER
893905
} else if (fromwire_dualopend_dev_memleak(msg)) {
@@ -1507,7 +1519,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg)
15071519
if (!fromwire_dualopend_fail(msg, msg, &err_reason))
15081520
master_badmsg(msg_type, msg);
15091521

1510-
negotiation_failed(state, "%s", err_reason);
1522+
open_error(state, "%s", err_reason);
15111523
return;
15121524
}
15131525

@@ -1927,7 +1939,7 @@ static void opener_start(struct state *state, u8 *msg)
19271939
if (!msg)
19281940
return;
19291941

1930-
a_tlv = tlv_accept_tlvs_new(state);
1942+
a_tlv = notleak(tlv_accept_tlvs_new(state));
19311943
if (!fromwire_accept_channel2(msg, &cid,
19321944
&state->accepter_funding,
19331945
&state->feerate_per_kw_funding,
@@ -2017,9 +2029,11 @@ static void opener_start(struct state *state, u8 *msg)
20172029
* - MUST send at least one `tx_add_output`, the channel
20182030
* funding output.
20192031
*/
2020-
wscript = bitcoin_redeem_2of2(state,
2021-
&state->our_funding_pubkey,
2022-
&state->their_funding_pubkey);
2032+
/* If fails before returning from `send_next`, this will
2033+
* be marked as a memleak */
2034+
wscript = notleak(bitcoin_redeem_2of2(state,
2035+
&state->our_funding_pubkey,
2036+
&state->their_funding_pubkey));
20232037
funding_out = psbt_append_output(state->psbt,
20242038
scriptpubkey_p2wsh(tmpctx,
20252039
wscript),
@@ -2052,7 +2066,7 @@ static void opener_start(struct state *state, u8 *msg)
20522066

20532067
/* Send our first message, we're opener we initiate here */
20542068
if (!send_next(state, &state->psbt))
2055-
negotiation_failed(state, "Peer error, no updates to send");
2069+
open_error(state, "Peer error, no updates to send");
20562070

20572071
/* Figure out what the funding transaction looks like! */
20582072
if (!run_tx_interactive(state, &state->psbt, TX_INITIATOR))

tests/test_connection.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3026,3 +3026,24 @@ def test_fundchannel_start_alternate(node_factory, executor):
30263026
fut = executor.submit(l2.rpc.fundchannel_start, l1.info['id'], 100000)
30273027
with pytest.raises(RpcError):
30283028
fut.result(10)
3029+
3030+
3031+
@unittest.skipIf(not EXPERIMENTAL_DUAL_FUND, "openchannel_init not available")
3032+
def test_openchannel_init_alternate(node_factory, executor):
3033+
''' Test to see what happens if two nodes start channeling to
3034+
each other alternately.
3035+
'''
3036+
l1, l2 = node_factory.get_nodes(2)
3037+
3038+
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
3039+
3040+
l1.fundwallet(2000000)
3041+
l2.fundwallet(2000000)
3042+
3043+
psbt1 = l1.rpc.fundpsbt('1000000msat', '253perkw', 250)['psbt']
3044+
psbt2 = l2.rpc.fundpsbt('1000000msat', '253perkw', 250)['psbt']
3045+
l1.rpc.openchannel_init(l2.info['id'], 100000, psbt1)
3046+
3047+
fut = executor.submit(l2.rpc.openchannel_init, l1.info['id'], '1000000msat', psbt2)
3048+
with pytest.raises(RpcError):
3049+
fut.result(10)

0 commit comments

Comments
 (0)