mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
lightningd/opening_control.c: fundchannel_cancel no longer requires a channel_id argument.
Fixes: #3785 Changelog-Changed: `fundchannel_cancel` no longer requires its undocumented `channel_id` argument after `fundchannel_complete`.
This commit is contained in:
committed by
ZmnSCPxj, ZmnSCPxj jxPCSmnZ
parent
2ab41af8e2
commit
deabab8934
@@ -49,6 +49,8 @@ static const errcode_t FUNDING_BROADCAST_FAIL = 303;
|
|||||||
static const errcode_t FUNDING_STILL_SYNCING_BITCOIN = 304;
|
static const errcode_t FUNDING_STILL_SYNCING_BITCOIN = 304;
|
||||||
static const errcode_t FUNDING_PEER_NOT_CONNECTED = 305;
|
static const errcode_t FUNDING_PEER_NOT_CONNECTED = 305;
|
||||||
static const errcode_t FUNDING_UNKNOWN_PEER = 306;
|
static const errcode_t FUNDING_UNKNOWN_PEER = 306;
|
||||||
|
static const errcode_t FUNDING_NOTHING_TO_CANCEL = 307;
|
||||||
|
static const errcode_t FUNDING_CANCEL_NOT_SAFE = 308;
|
||||||
|
|
||||||
/* `connect` errors */
|
/* `connect` errors */
|
||||||
static const errcode_t CONNECT_NO_KNOWN_ADDRESS = 400;
|
static const errcode_t CONNECT_NO_KNOWN_ADDRESS = 400;
|
||||||
|
|||||||
8
doc/lightning-fundchannel_cancel.7
generated
8
doc/lightning-fundchannel_cancel.7
generated
@@ -36,9 +36,13 @@ with \fBcode\fR being one of the following:
|
|||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
-32602: If the given parameters are wrong\.
|
-32602: If the given parameters are wrong\.
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
-1: Catchall nonspecific error\.
|
|
||||||
.IP \[bu]
|
|
||||||
306: Unknown peer id\.
|
306: Unknown peer id\.
|
||||||
|
.IP \[bu]
|
||||||
|
307: No channel currently being funded that can be cancelled\.
|
||||||
|
.IP \[bu]
|
||||||
|
308: It is unsafe to cancel the channel: the funding transaction
|
||||||
|
has been broadcast, or there are HTLCs already in the channel, or
|
||||||
|
the peer was the initiator and not us\.
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
|
|||||||
@@ -32,8 +32,11 @@ On error the returned object will contain `code` and `message` properties,
|
|||||||
with `code` being one of the following:
|
with `code` being one of the following:
|
||||||
|
|
||||||
- -32602: If the given parameters are wrong.
|
- -32602: If the given parameters are wrong.
|
||||||
- -1: Catchall nonspecific error.
|
|
||||||
- 306: Unknown peer id.
|
- 306: Unknown peer id.
|
||||||
|
- 307: No channel currently being funded that can be cancelled.
|
||||||
|
- 308: It is unsafe to cancel the channel: the funding transaction
|
||||||
|
has been broadcast, or there are HTLCs already in the channel, or
|
||||||
|
the peer was the initiator and not us.
|
||||||
|
|
||||||
AUTHOR
|
AUTHOR
|
||||||
------
|
------
|
||||||
|
|||||||
@@ -752,7 +752,8 @@ static void process_check_funding_broadcast(struct bitcoind *bitcoind,
|
|||||||
|
|
||||||
if (txout != NULL) {
|
if (txout != NULL) {
|
||||||
for (size_t i = 0; i < tal_count(cancel->forgets); i++)
|
for (size_t i = 0; i < tal_count(cancel->forgets); i++)
|
||||||
was_pending(command_fail(cancel->forgets[i], LIGHTNINGD,
|
was_pending(command_fail(cancel->forgets[i],
|
||||||
|
FUNDING_CANCEL_NOT_SAFE,
|
||||||
"The funding transaction has been broadcast, "
|
"The funding transaction has been broadcast, "
|
||||||
"please consider `close` or `dev-fail`! "));
|
"please consider `close` or `dev-fail`! "));
|
||||||
tal_free(cancel->forgets);
|
tal_free(cancel->forgets);
|
||||||
@@ -767,47 +768,41 @@ static void process_check_funding_broadcast(struct bitcoind *bitcoind,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct command_result *cancel_channel_before_broadcast(struct command *cmd,
|
struct command_result *cancel_channel_before_broadcast(struct command *cmd,
|
||||||
const char *buffer,
|
struct peer *peer)
|
||||||
struct peer *peer,
|
|
||||||
const jsmntok_t *cidtok)
|
|
||||||
{
|
{
|
||||||
struct channel *cancel_channel;
|
struct channel *cancel_channel;
|
||||||
struct channel_to_cancel *cc = tal(cmd, struct channel_to_cancel);
|
struct channel_to_cancel *cc = tal(cmd, struct channel_to_cancel);
|
||||||
|
struct channel *channel;
|
||||||
|
|
||||||
cc->peer = peer->id;
|
cc->peer = peer->id;
|
||||||
if (!cidtok) {
|
cancel_channel = NULL;
|
||||||
struct channel *channel;
|
list_for_each(&peer->channels, channel, list) {
|
||||||
|
/* After `fundchannel_complete`, channel is in
|
||||||
cancel_channel = NULL;
|
* `CHANNELD_AWAITING_LOCKIN` state.
|
||||||
list_for_each(&peer->channels, channel, list) {
|
*
|
||||||
if (cancel_channel) {
|
* TODO: This assumes only one channel at a time
|
||||||
return command_fail(cmd, LIGHTNINGD,
|
* can be in this state, which is true at the
|
||||||
"Multiple channels:"
|
* time of this writing, but may change *if* we
|
||||||
" please specify channel_id");
|
* ever implement multiple channels per peer.
|
||||||
}
|
*/
|
||||||
cancel_channel = channel;
|
if (channel->state != CHANNELD_AWAITING_LOCKIN)
|
||||||
}
|
continue;
|
||||||
if (!cancel_channel)
|
cancel_channel = channel;
|
||||||
return command_fail(cmd, LIGHTNINGD,
|
break;
|
||||||
"No channels matching that peer_id");
|
|
||||||
derive_channel_id(&cc->cid,
|
|
||||||
&cancel_channel->funding_txid,
|
|
||||||
cancel_channel->funding_outnum);
|
|
||||||
} else {
|
|
||||||
if (!json_tok_channel_id(buffer, cidtok, &cc->cid))
|
|
||||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
||||||
"Invalid channel_id parameter.");
|
|
||||||
|
|
||||||
cancel_channel = find_channel_by_id(peer, &cc->cid);
|
|
||||||
if (!cancel_channel)
|
|
||||||
return command_fail(cmd, LIGHTNINGD,
|
|
||||||
"Channel ID not found: '%.*s'",
|
|
||||||
cidtok->end - cidtok->start,
|
|
||||||
buffer + cidtok->start);
|
|
||||||
}
|
}
|
||||||
|
if (!cancel_channel)
|
||||||
|
return command_fail(cmd, FUNDING_NOTHING_TO_CANCEL,
|
||||||
|
"No channels being opened or "
|
||||||
|
"awaiting lock-in for "
|
||||||
|
"peer_id %s",
|
||||||
|
type_to_string(tmpctx, struct node_id,
|
||||||
|
&peer->id));
|
||||||
|
derive_channel_id(&cc->cid,
|
||||||
|
&cancel_channel->funding_txid,
|
||||||
|
cancel_channel->funding_outnum);
|
||||||
|
|
||||||
if (cancel_channel->opener == REMOTE)
|
if (cancel_channel->opener == REMOTE)
|
||||||
return command_fail(cmd, LIGHTNINGD,
|
return command_fail(cmd, FUNDING_CANCEL_NOT_SAFE,
|
||||||
"Cannot cancel channel that was "
|
"Cannot cancel channel that was "
|
||||||
"initiated by peer");
|
"initiated by peer");
|
||||||
|
|
||||||
@@ -817,13 +812,13 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd,
|
|||||||
if (wallet_transaction_type(cmd->ld->wallet,
|
if (wallet_transaction_type(cmd->ld->wallet,
|
||||||
&cancel_channel->funding_txid,
|
&cancel_channel->funding_txid,
|
||||||
&type))
|
&type))
|
||||||
return command_fail(cmd, LIGHTNINGD,
|
return command_fail(cmd, FUNDING_CANCEL_NOT_SAFE,
|
||||||
"Has the funding transaction been broadcast? "
|
"Has the funding transaction been broadcast? "
|
||||||
"Please use `close` or `dev-fail` instead.");
|
"Please use `close` or `dev-fail` instead.");
|
||||||
|
|
||||||
if (channel_has_htlc_out(cancel_channel) ||
|
if (channel_has_htlc_out(cancel_channel) ||
|
||||||
channel_has_htlc_in(cancel_channel)) {
|
channel_has_htlc_in(cancel_channel)) {
|
||||||
return command_fail(cmd, LIGHTNINGD,
|
return command_fail(cmd, FUNDING_CANCEL_NOT_SAFE,
|
||||||
"This channel has HTLCs attached and it is "
|
"This channel has HTLCs attached and it is "
|
||||||
"not safe to cancel. Has the funding transaction "
|
"not safe to cancel. Has the funding transaction "
|
||||||
"been broadcast? Please use `close` or `dev-fail` "
|
"been broadcast? Please use `close` or `dev-fail` "
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ void channel_notify_new_block(struct lightningd *ld,
|
|||||||
/* Cancel the channel after `fundchannel_complete` succeeds
|
/* Cancel the channel after `fundchannel_complete` succeeds
|
||||||
* but before funding broadcasts. */
|
* but before funding broadcasts. */
|
||||||
struct command_result *cancel_channel_before_broadcast(struct command *cmd,
|
struct command_result *cancel_channel_before_broadcast(struct command *cmd,
|
||||||
const char *buffer,
|
struct peer *peer);
|
||||||
struct peer *peer,
|
|
||||||
const jsmntok_t *cidtok);
|
|
||||||
|
|
||||||
/* Forget a channel. Deletes the channel and handles all
|
/* Forget a channel. Deletes the channel and handles all
|
||||||
* associated waiting commands, if present. Notifies peer if available */
|
* associated waiting commands, if present. Notifies peer if available */
|
||||||
|
|||||||
@@ -308,29 +308,7 @@ static void
|
|||||||
cancel_after_fundchannel_complete_success(struct command *cmd,
|
cancel_after_fundchannel_complete_success(struct command *cmd,
|
||||||
struct channel *channel)
|
struct channel *channel)
|
||||||
{
|
{
|
||||||
struct peer *peer;
|
was_pending(cancel_channel_before_broadcast(cmd, channel->peer));
|
||||||
struct channel_id cid;
|
|
||||||
/* Fake these to adapt to the existing
|
|
||||||
* cancel_channel_before_broadcast
|
|
||||||
* interface.
|
|
||||||
*/
|
|
||||||
const char *buffer;
|
|
||||||
jsmntok_t cidtok;
|
|
||||||
|
|
||||||
peer = channel->peer;
|
|
||||||
derive_channel_id(&cid,
|
|
||||||
&channel->funding_txid, channel->funding_outnum);
|
|
||||||
|
|
||||||
buffer = type_to_string(tmpctx, struct channel_id, &cid);
|
|
||||||
cidtok.type = JSMN_STRING;
|
|
||||||
cidtok.start = 0;
|
|
||||||
cidtok.end = strlen(buffer);
|
|
||||||
cidtok.size = 0;
|
|
||||||
|
|
||||||
was_pending(cancel_channel_before_broadcast(cmd,
|
|
||||||
buffer,
|
|
||||||
peer,
|
|
||||||
&cidtok));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void funding_success(struct channel *channel)
|
static void funding_success(struct channel *channel)
|
||||||
@@ -1150,12 +1128,10 @@ static struct command_result *json_fund_channel_cancel(struct command *cmd,
|
|||||||
|
|
||||||
struct node_id *id;
|
struct node_id *id;
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
const jsmntok_t *cidtok;
|
|
||||||
u8 *msg;
|
u8 *msg;
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
if (!param(cmd, buffer, params,
|
||||||
p_req("id", param_node_id, &id),
|
p_req("id", param_node_id, &id),
|
||||||
p_opt("channel_id", param_tok, &cidtok),
|
|
||||||
NULL))
|
NULL))
|
||||||
return command_param_failed();
|
return command_param_failed();
|
||||||
|
|
||||||
@@ -1166,7 +1142,8 @@ static struct command_result *json_fund_channel_cancel(struct command *cmd,
|
|||||||
|
|
||||||
if (peer->uncommitted_channel) {
|
if (peer->uncommitted_channel) {
|
||||||
if (!peer->uncommitted_channel->fc || !peer->uncommitted_channel->fc->inflight)
|
if (!peer->uncommitted_channel->fc || !peer->uncommitted_channel->fc->inflight)
|
||||||
return command_fail(cmd, LIGHTNINGD, "No channel funding in progress.");
|
return command_fail(cmd, FUNDING_NOTHING_TO_CANCEL,
|
||||||
|
"No channel funding in progress.");
|
||||||
|
|
||||||
/* Make sure this gets notified if we succeed or cancel */
|
/* Make sure this gets notified if we succeed or cancel */
|
||||||
tal_arr_expand(&peer->uncommitted_channel->fc->cancels, cmd);
|
tal_arr_expand(&peer->uncommitted_channel->fc->cancels, cmd);
|
||||||
@@ -1175,7 +1152,8 @@ static struct command_result *json_fund_channel_cancel(struct command *cmd,
|
|||||||
return command_still_pending(cmd);
|
return command_still_pending(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cancel_channel_before_broadcast(cmd, buffer, peer, cidtok);
|
/* Handle `fundchannel_cancel` after `fundchannel_complete`. */
|
||||||
|
return cancel_channel_before_broadcast(cmd, peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1162,8 +1162,8 @@ def test_funding_close_upfront(node_factory, bitcoind):
|
|||||||
|
|
||||||
@unittest.skipIf(TEST_NETWORK != 'regtest', "External wallet support doesn't work with elements yet.")
|
@unittest.skipIf(TEST_NETWORK != 'regtest', "External wallet support doesn't work with elements yet.")
|
||||||
def test_funding_external_wallet(node_factory, bitcoind):
|
def test_funding_external_wallet(node_factory, bitcoind):
|
||||||
l1 = node_factory.get_node()
|
l1 = node_factory.get_node(options={'funding-confirms': 2})
|
||||||
l2 = node_factory.get_node()
|
l2 = node_factory.get_node(options={'funding-confirms': 2})
|
||||||
l3 = node_factory.get_node()
|
l3 = node_factory.get_node()
|
||||||
|
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||||
@@ -1197,20 +1197,23 @@ def test_funding_external_wallet(node_factory, bitcoind):
|
|||||||
|
|
||||||
assert l1.rpc.fundchannel_complete(l2.info['id'], txid, txout)['commitments_secured']
|
assert l1.rpc.fundchannel_complete(l2.info['id'], txid, txout)['commitments_secured']
|
||||||
|
|
||||||
# Broadcast the transaction manually and confirm that channel locks in
|
# Broadcast the transaction manually
|
||||||
signed_tx = bitcoind.rpc.signrawtransactionwithwallet(raw_funded_tx)['hex']
|
signed_tx = bitcoind.rpc.signrawtransactionwithwallet(raw_funded_tx)['hex']
|
||||||
assert txid == bitcoind.rpc.decoderawtransaction(signed_tx)['txid']
|
assert txid == bitcoind.rpc.decoderawtransaction(signed_tx)['txid']
|
||||||
|
|
||||||
bitcoind.rpc.sendrawtransaction(signed_tx)
|
bitcoind.rpc.sendrawtransaction(signed_tx)
|
||||||
bitcoind.generate_block(1)
|
bitcoind.generate_block(1)
|
||||||
|
|
||||||
l1.daemon.wait_for_log(r'Funding tx {} depth 1 of 1'.format(txid))
|
l1.daemon.wait_for_log(r'Funding tx {} depth 1 of 2'.format(txid))
|
||||||
|
|
||||||
# Check that tx is broadcast by a third party can be catched.
|
# Check that tx is broadcast by a third party can be catched.
|
||||||
# Only when the transaction (broadcast by a third pary) is onchain, we can catch it.
|
# Only when the transaction (broadcast by a third pary) is onchain, we can catch it.
|
||||||
with pytest.raises(RpcError, match=r'.* been broadcast.*'):
|
with pytest.raises(RpcError, match=r'.* been broadcast.*'):
|
||||||
l1.rpc.fundchannel_cancel(l2.info['id'])
|
l1.rpc.fundchannel_cancel(l2.info['id'])
|
||||||
|
|
||||||
|
# Confirm that channel locks in
|
||||||
|
bitcoind.generate_block(1)
|
||||||
|
|
||||||
for node in [l1, l2]:
|
for node in [l1, l2]:
|
||||||
node.daemon.wait_for_log(r'State changed from CHANNELD_AWAITING_LOCKIN to CHANNELD_NORMAL')
|
node.daemon.wait_for_log(r'State changed from CHANNELD_AWAITING_LOCKIN to CHANNELD_NORMAL')
|
||||||
channel = node.rpc.listpeers()['peers'][0]['channels'][0]
|
channel = node.rpc.listpeers()['peers'][0]['channels'][0]
|
||||||
|
|||||||
Reference in New Issue
Block a user