mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-21 14:24:09 +01:00
opening: add fundchannel_cancel command
Provide the option to cancel a funding-opening with a peer. Must either call `fundchannel_cancel` or `fundchannel_continue`
This commit is contained in:
parent
478762dbd2
commit
5aad642c59
5 changed files with 101 additions and 0 deletions
|
@ -499,6 +499,15 @@ class LightningRpc(UnixDomainSocketRpc):
|
|||
}
|
||||
return self.call("fundchannel_start", payload)
|
||||
|
||||
def fundchannel_cancel(self, node_id):
|
||||
"""
|
||||
Cancel a 'started' fundchannel with node {id}.
|
||||
"""
|
||||
payload = {
|
||||
"id": node_id,
|
||||
}
|
||||
return self.call("fundchannel_cancel", payload)
|
||||
|
||||
def fundchannel_continue(self, node_id, funding_txid, funding_txout):
|
||||
"""
|
||||
Complete channel establishment with {id}, using {funding_txid} at {funding_txout}
|
||||
|
|
|
@ -1021,6 +1021,7 @@ static unsigned int openingd_msg(struct subd *openingd,
|
|||
case WIRE_OPENING_FUNDER:
|
||||
case WIRE_OPENING_FUNDER_START:
|
||||
case WIRE_OPENING_FUNDER_CONTINUE:
|
||||
case WIRE_OPENING_FUNDER_CANCEL:
|
||||
case WIRE_OPENING_GOT_OFFER_REPLY:
|
||||
case WIRE_OPENING_DEV_MEMLEAK:
|
||||
/* Replies never get here */
|
||||
|
@ -1148,6 +1149,68 @@ static struct command_result *json_fund_channel_continue(struct command *cmd,
|
|||
return command_still_pending(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* json_fund_channel_cancel - Entrypoint for cancelling an in flight channel-funding
|
||||
*/
|
||||
static struct command_result *json_fund_channel_cancel(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *obj UNNEEDED,
|
||||
const jsmntok_t *params)
|
||||
{
|
||||
|
||||
struct node_id *id;
|
||||
struct peer *peer;
|
||||
u8 *msg;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("id", param_node_id, &id),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
peer = peer_by_id(cmd->ld, id);
|
||||
if (!peer) {
|
||||
return command_fail(cmd, LIGHTNINGD, "Unknown peer");
|
||||
}
|
||||
|
||||
if (!peer->uncommitted_channel) {
|
||||
return command_fail(cmd, LIGHTNINGD, "Peer not connected");
|
||||
}
|
||||
|
||||
if (!peer->uncommitted_channel->fc || !peer->uncommitted_channel->fc->inflight)
|
||||
return command_fail(cmd, LIGHTNINGD, "No channel funding in progress.");
|
||||
|
||||
/**
|
||||
* there's a question of 'state machinery' here. as is, we're not checking
|
||||
* to see if you've already called `continue` -- we expect you
|
||||
* the caller to EITHER pick 'continue' or 'cancel'.
|
||||
* but if for some reason you've decided to test your luck, how much
|
||||
* 'handling' can we do for that case? the easiest thing to do is to
|
||||
* say "sorry you've already called continue", we can't cancel this.
|
||||
*
|
||||
* there's also the state you might end up in where you've called
|
||||
* continue (and it's completed and been passed off to channeld) but
|
||||
* you've decided (for whatever reason) not to broadcast the transaction
|
||||
* so your channels have ended up in this 'waiting' state. neither of us
|
||||
* are actually out any amount of cash, but it'd be nice if there's a way
|
||||
* to signal to c-lightning (+ your peer) that this channel is dead on arrival.
|
||||
* ... but also if you then broadcast this tx you'd be in trouble cuz we're
|
||||
* both going to forget about it. the meta question here is how 'undoable'
|
||||
* should we make any of this. how much tools do we give you, reader?
|
||||
*
|
||||
* for now, let's settle for the EITHER / OR case and disregard the larger
|
||||
* question about 'how long cancelable'.
|
||||
*/
|
||||
|
||||
/* Update the cmd to the new cmd */
|
||||
peer->uncommitted_channel->fc->cmd = cmd;
|
||||
msg = towire_opening_funder_cancel(NULL);
|
||||
subd_send_msg(peer->uncommitted_channel->openingd, take(msg));
|
||||
return command_still_pending(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* json_fund_channel_start - Entrypoint for funding an externally funded channel
|
||||
*/
|
||||
static struct command_result *json_fund_channel_start(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *obj UNNEEDED,
|
||||
|
@ -1367,6 +1430,14 @@ static const struct json_command fund_channel_start_command = {
|
|||
};
|
||||
AUTODATA(json_command, &fund_channel_start_command);
|
||||
|
||||
static const struct json_command fund_channel_cancel_command = {
|
||||
"fundchannel_cancel",
|
||||
"channels",
|
||||
json_fund_channel_cancel,
|
||||
"Cancel inflight channel establishment with peer {id}."
|
||||
};
|
||||
AUTODATA(json_command, &fund_channel_cancel_command);
|
||||
|
||||
static const struct json_command fund_channel_continue_command = {
|
||||
"fundchannel_continue",
|
||||
"channels",
|
||||
|
|
|
@ -98,6 +98,9 @@ opening_funder_continue,6012
|
|||
opening_funder_continue,,funding_txid,struct bitcoin_txid
|
||||
opening_funder_continue,,funding_txout,u16
|
||||
|
||||
#master->openingd: cancel channel establishment for a funding
|
||||
opening_funder_cancel,6013
|
||||
|
||||
# Openingd->master: we failed to negotiation channel
|
||||
opening_funder_failed,6004
|
||||
opening_funder_failed,,reason,wirestring
|
||||
|
|
|
|
@ -1683,6 +1683,16 @@ static u8 *handle_master_in(struct state *state)
|
|||
state->funding_txid = funding_txid;
|
||||
state->funding_txout = funding_txout;
|
||||
return funder_channel_continue(state);
|
||||
case WIRE_OPENING_FUNDER_CANCEL:
|
||||
/* We're aborting this, simple */
|
||||
if (!fromwire_opening_funder_cancel(msg))
|
||||
master_badmsg(WIRE_OPENING_FUNDER_CANCEL, msg);
|
||||
|
||||
msg = towire_errorfmt(NULL, &state->channel_id, "Channel open canceled by us");
|
||||
sync_crypto_write(state->pps, take(msg));
|
||||
negotiation_aborted(state, true,
|
||||
"Channel open canceled by RPC", false);
|
||||
return NULL;
|
||||
case WIRE_OPENING_DEV_MEMLEAK:
|
||||
#if DEVELOPER
|
||||
handle_dev_memleak(state, msg);
|
||||
|
|
|
@ -844,6 +844,14 @@ def test_funding_external_wallet_corners(node_factory, bitcoind):
|
|||
with pytest.raises(RpcError, match=r'No channel funding in progress.'):
|
||||
l1.rpc.fundchannel_continue(l2.info['id'], fake_txid, fake_txout)
|
||||
|
||||
l1.rpc.fundchannel_start(l2.info['id'], amount)
|
||||
with pytest.raises(RpcError, match=r'Already funding channel'):
|
||||
l1.rpc.fundchannel(l2.info['id'], amount)
|
||||
|
||||
l1.rpc.fundchannel_cancel(l2.info['id'])
|
||||
# Should be able to 'restart' after canceling
|
||||
l1.rpc.fundchannel_start(l2.info['id'], amount)
|
||||
|
||||
|
||||
def test_funding_external_wallet(node_factory, bitcoind):
|
||||
l1 = node_factory.get_node()
|
||||
|
|
Loading…
Add table
Reference in a new issue