Skip to content

Commit 83e654a

Browse files
committedAug 9, 2019
close: change to a unilateraltimeout argument.
`close` takes two optional arguments: `force` and `timeout`. `timeout` doesn't timeout the close (there's no way to do that), just the JSON call. `force` (default `false`) if set, means we unilaterally close at the timeout, instead of just failing. Timing out JSON calls is generally deprecated: that's the job of the client. And the semantics of this are confusing, even to me! A better API is a timeout which, if non-zero, is the time at which we give up and unilaterally close. The transition code is awkward, but we'll manage for the three releases until we can remove it. The new defaults are to unilaterally close after 48 hours. Fixes: ElementsProject#2791 Signed-off-by: Rusty Russell <[email protected]>
1 parent b35dc46 commit 83e654a

File tree

6 files changed

+156
-47
lines changed

6 files changed

+156
-47
lines changed
 

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Changed
1818

19+
- JSON API: `close` optional arguments have changed: it now defaults to unilateral close after 48 hours.
1920
- build: now requires `python3-mako` to be installed, i.e. `sudo apt-get install python3-mako`
2021
- plugins: if the config directory has a `plugins` subdirectory, those are loaded.
2122
- plugins: a new notification type `invoice_payment` (sent when an invoice is paid) has been added

‎contrib/pylightning/lightning/lightning.py

+33-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
from math import floor, log10
55
import socket
6+
import warnings
67

78
__version__ = "0.0.7.3"
89

@@ -309,16 +310,43 @@ def check(self, command_to_check, **kwargs):
309310
payload.update({k: v for k, v in kwargs.items()})
310311
return self.call("check", payload)
311312

312-
def close(self, peer_id, force=None, timeout=None):
313+
def _deprecated_close(self, peer_id, force=None, timeout=None):
314+
warnings.warn("close now takes unilateraltimeout arg: expect removal"
315+
" in early 2020",
316+
DeprecationWarning)
317+
payload = {
318+
"id": peer_id,
319+
"force": force,
320+
"timeout": timeout
321+
}
322+
return self.call("close", payload)
323+
324+
def close(self, peer_id, *args, **kwargs):
313325
"""
314326
Close the channel with peer {id}, forcing a unilateral
315-
close if {force} is True, and timing out with {timeout}
316-
seconds.
327+
close after {unilateraltimeout} seconds if non-zero.
328+
329+
Deprecated usage has {force} and {timeout} args.
317330
"""
331+
unilateraltimeout = None
332+
333+
if 'force' in kwargs or 'timeout' in kwargs:
334+
return self._deprecated_close(peer_id, *args, **kwargs)
335+
336+
# Single arg is ambigious.
337+
if len(args) == 1:
338+
if isinstance(args[0], bool):
339+
return self._deprecated_close(peer_id, *args, **kwargs)
340+
unilateraltimeout = args[0]
341+
elif len(args) > 1:
342+
return self._deprecated_close(peer_id, *args, **kwargs)
343+
344+
if 'unilateraltimeout' in kwargs:
345+
unilateraltimeout = kwargs['unilateraltimeout']
346+
318347
payload = {
319348
"id": peer_id,
320-
"force": force,
321-
"timeout": timeout
349+
"unilateraltimeout": unilateraltimeout
322350
}
323351
return self.call("close", payload)
324352

‎doc/lightning-close.7

+13-10
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
.\" Title: lightning-close
33
.\" Author: [see the "AUTHOR" section]
44
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
5-
.\" Date: 04/30/2018
5+
.\" Date: 08/08/2019
66
.\" Manual: \ \&
77
.\" Source: \ \&
88
.\" Language: English
99
.\"
10-
.TH "LIGHTNING\-CLOSE" "7" "04/30/2018" "\ \&" "\ \&"
10+
.TH "LIGHTNING\-CLOSE" "7" "08/08/2019" "\ \&" "\ \&"
1111
.\" -----------------------------------------------------------------
1212
.\" * Define some portability stuff
1313
.\" -----------------------------------------------------------------
@@ -31,29 +31,32 @@
3131
lightning-close \- Command for closing channels with direct peers
3232
.SH "SYNOPSIS"
3333
.sp
34-
\fBclose\fR \fIid\fR [\fIforce\fR] [\fItimeout\fR]
34+
\fBclose\fR \fIid\fR [\fIunilateraltimeout\fR]
3535
.SH "DESCRIPTION"
3636
.sp
37-
The \fBclose\fR RPC command attempts to close the channel cooperatively with the peer\&. If the given \fIid\fR is a peer ID (66 hex digits as a string), then it applies to the active channel of the direct peer corresponding to the given peer ID\&. If the given \fIid\fR is a channel ID (64 hex digits as a string, or the short channel ID \fIblockheight:txindex:outindex\fR form), then it applies to that channel\&.
37+
The \fBclose\fR RPC command attempts to close the channel cooperatively with the peer, or unilaterally after \fIunilateraltimeout\fR\&.
3838
.sp
39-
The \fBclose\fR command will time out and return with an error when the number of seconds specified in \fItimeout\fR is reached\&. If unspecified, it times out in 30 seconds\&.
39+
If the given \fIid\fR is a peer ID (66 hex digits as a string), then it applies to the active channel of the direct peer corresponding to the given peer ID\&. If the given \fIid\fR is a channel ID (64 hex digits as a string, or the short channel ID \fIblockheight:txindex:outindex\fR form), then it applies to that channel\&.
4040
.sp
41-
The \fIforce\fR argument, if the JSON value \fItrue\fR, will cause the channel to be unilaterally closed when the timeout is reached\&. If so, timeout will not cause an error, but instead cause the channel to be failed and put onchain unilaterally\&. Unilateral closes will lead to your funds getting locked according to the \fIto_self_delay\fR parameter of the peer\&.
41+
If \fIunilateraltimeout\fR is not zero, the \fBclose\fR command will unilaterally close the channel when that number of seconds is reached\&. If \fIunilateraltimeout\fR is zero, then the \fBclose\fR command will wait indefinitely until the peer is online and can negotiate a mutual close\&. The default is 2 days (172800 seconds)\&.
4242
.sp
43-
Normally the peer needs to be live and connected in order to negotiate a mutual close\&. Forcing a unilateral close can be used if you suspect you can no longer contact the peer\&.
43+
The peer needs to be live and connected in order to negotiate a mutual close\&. The default of unilaterally closing after 48 hours is usually a reasonable indication that you can no longer contact the peer\&.
44+
.SH "NOTES"
45+
.sp
46+
Prior to 0\&.7\&.2, \fBclose\fR took two parameters: \fIforce\fR and \fItimeout\fR\&. \fItimeout\fR was the number of seconds before \fIforce\fR took effect (default, 30), and \fIforce\fR determined whether the result was a unilateral close or an RPC error (default)\&. Even after the timeout, the channel would be closed if the peer reconnected\&.
4447
.SH "RETURN VALUE"
4548
.sp
4649
On success, an object with fields \fItx\fR and \fItxid\fR containing the closing transaction are returned\&. It will also have a field \fItype\fR which is either the JSON string \fImutual\fR or the JSON string \fIunilateral\fR\&. A \fImutual\fR close means that we could negotiate a close with the peer, while a \fIunilateral\fR close means that the \fIforce\fR flag was set and we had to close the channel without waiting for the counterparty\&.
4750
.sp
48-
A unilateral close may still occur with \fIforce\fR set to \fIfalse\fR if the peer did not behave correctly during the close negotiation\&.
51+
A unilateral close may still occur at any time if the peer did not behave correctly during the close negotiation\&.
4952
.sp
5053
Unilateral closes will return your funds after a delay\&. The delay will vary based on the peer \fIto_self_delay\fR setting, not your own setting\&.
51-
.sp
52-
On failure, if \fBclose\fR failed due to timing out with \fIforce\fR argument \fIfalse\fR, the channel will still eventually close once we have contacted the peer\&.
5354
.SH "AUTHOR"
5455
.sp
5556
ZmnSCPxj <ZmnSCPxj@protonmail\&.com> is mainly responsible\&.
5657
.SH "SEE ALSO"
58+
.sp
59+
lightning\-disconnect(7), lightning\-fundchannel(7)
5760
.SH "RESOURCES"
5861
.sp
5962
Main web site: https://github\&.com/ElementsProject/lightning

‎doc/lightning-close.7.txt

+22-21
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,41 @@ lightning-close - Command for closing channels with direct peers
88

99
SYNOPSIS
1010
--------
11-
*close* 'id' ['force'] ['timeout']
11+
*close* 'id' ['unilateraltimeout']
1212

1313
DESCRIPTION
1414
-----------
1515

1616
The *close* RPC command attempts to close the channel cooperatively
17-
with the peer.
17+
with the peer, or unilaterally after 'unilateraltimeout'.
18+
1819
If the given 'id' is a peer ID (66 hex digits as a string), then
1920
it applies to the active channel of the direct peer corresponding to
2021
the given peer ID.
2122
If the given 'id' is a channel ID (64 hex digits as a string, or
2223
the short channel ID 'blockheight:txindex:outindex' form), then it
2324
applies to that channel.
2425

25-
The *close* command will time out and return with an error when the
26-
number of seconds specified in 'timeout' is reached.
27-
If unspecified, it times out in 30 seconds.
28-
29-
The 'force' argument, if the JSON value 'true', will cause the
30-
channel to be unilaterally closed when the timeout is reached.
31-
If so, timeout will not cause an error, but instead cause the
32-
channel to be failed and put onchain unilaterally.
33-
Unilateral closes will lead to your funds getting locked according
34-
to the 'to_self_delay' parameter of the peer.
26+
If 'unilateraltimeout' is not zero, the *close* command will
27+
unilaterally close the channel when that number of seconds is reached.
28+
If 'unilateraltimeout' is zero, then the *close* command will wait
29+
indefinitely until the peer is online and can negotiate a mutual
30+
close. The default is 2 days (172800 seconds).
3531

36-
Normally the peer needs to be live and connected in order to negotiate
37-
a mutual close.
38-
Forcing a unilateral close can be used if you suspect you can no longer
32+
The peer needs to be live and connected in order to negotiate
33+
a mutual close. The default of unilaterally closing after 48 hours
34+
is usually a reasonable indication that you can no longer
3935
contact the peer.
4036

37+
NOTES
38+
-----
39+
40+
Prior to 0.7.2, *close* took two parameters: 'force' and 'timeout'.
41+
'timeout' was the number of seconds before 'force' took effect
42+
(default, 30), and 'force' determined whether the result was a
43+
unilateral close or an RPC error (default). Even after
44+
the timeout, the channel would be closed if the peer reconnected.
45+
4146
RETURN VALUE
4247
------------
4348

@@ -50,24 +55,20 @@ peer, while a 'unilateral' close means that the 'force' flag was
5055
set and we had to close the channel without waiting for the
5156
counterparty.
5257

53-
A unilateral close may still occur with 'force' set to 'false' if
58+
A unilateral close may still occur at any time if
5459
the peer did not behave correctly during the close negotiation.
5560

5661
Unilateral closes will return your funds after a delay.
5762
The delay will vary based on the peer 'to_self_delay' setting, not
5863
your own setting.
5964

60-
On failure, if *close* failed due to timing out with 'force'
61-
argument 'false', the channel will still eventually close once
62-
we have contacted the peer.
63-
6465
AUTHOR
6566
------
6667
ZmnSCPxj <ZmnSCPxj@protonmail.com> is mainly responsible.
6768

6869
SEE ALSO
6970
--------
70-
71+
lightning-disconnect(7), lightning-fundchannel(7)
7172

7273
RESOURCES
7374
---------

‎lightningd/peer_control.c

+84-11
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ static void
320320
register_close_command(struct lightningd *ld,
321321
struct command *cmd,
322322
struct channel *channel,
323-
unsigned int timeout,
323+
unsigned int *timeout,
324324
bool force)
325325
{
326326
struct close_command *cc;
@@ -335,8 +335,11 @@ register_close_command(struct lightningd *ld,
335335
tal_add_destructor2(channel,
336336
&destroy_close_command_on_channel_destroy,
337337
cc);
338-
new_reltimer(ld->timers, cc, time_from_sec(timeout),
339-
&close_command_timeout, cc);
338+
log_debug(ld->log, "close_command: force = %u, timeout = %i",
339+
force, timeout ? *timeout : -1);
340+
if (timeout)
341+
new_reltimer(ld->timers, cc, time_from_sec(*timeout),
342+
&close_command_timeout, cc);
340343
}
341344

342345
static bool invalid_last_tx(const struct bitcoin_tx *tx)
@@ -1225,14 +1228,83 @@ static struct command_result *json_close(struct command *cmd,
12251228
struct peer *peer;
12261229
struct channel *channel COMPILER_WANTS_INIT("gcc 7.3.0 fails, 8.3 OK");
12271230
unsigned int *timeout;
1228-
bool *force;
1231+
bool force = true;
1232+
bool do_timeout;
1233+
1234+
/* For generating help, give new-style. */
1235+
if (!params || !deprecated_apis) {
1236+
if (!param(cmd, buffer, params,
1237+
p_req("id", param_tok, &idtok),
1238+
p_opt_def("unilateraltimeout", param_number,
1239+
&timeout, 48 * 3600),
1240+
NULL))
1241+
return command_param_failed();
1242+
do_timeout = (*timeout != 0);
1243+
} else if (params->type == JSMN_ARRAY) {
1244+
const jsmntok_t *tok;
1245+
1246+
/* Could be new or old style; get as tok. */
1247+
if (!param(cmd, buffer, params,
1248+
p_req("id", param_tok, &idtok),
1249+
p_opt("unilateraltimeout_or_force", param_tok, &tok),
1250+
p_opt("timeout", param_number, &timeout),
1251+
NULL))
1252+
return command_param_failed();
1253+
1254+
if (tok) {
1255+
/* old-style force bool? */
1256+
if (json_to_bool(buffer, tok, &force)) {
1257+
/* Old default timeout */
1258+
if (!timeout) {
1259+
timeout = tal(cmd, unsigned int);
1260+
*timeout = 30;
1261+
}
1262+
/* New-style timeout */
1263+
} else {
1264+
timeout = tal(cmd, unsigned int);
1265+
if (!json_to_number(buffer, tok, timeout)) {
1266+
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
1267+
"Expected unilerataltimeout to be a number");
1268+
}
1269+
}
1270+
}
12291271

1230-
if (!param(cmd, buffer, params,
1231-
p_req("id", param_tok, &idtok),
1232-
p_opt_def("force", param_bool, &force, false),
1233-
p_opt_def("timeout", param_number, &timeout, 30),
1234-
NULL))
1235-
return command_param_failed();
1272+
/* If they didn't specify timeout, it's the (new) default */
1273+
if (!timeout) {
1274+
timeout = tal(cmd, unsigned int);
1275+
*timeout = 48 * 3600;
1276+
}
1277+
do_timeout = true;
1278+
} else {
1279+
unsigned int *old_timeout;
1280+
bool *old_force;
1281+
1282+
/* Named parameters are easy to distinguish */
1283+
if (!param(cmd, buffer, params,
1284+
p_req("id", param_tok, &idtok),
1285+
p_opt_def("unilateraltimeout", param_number,
1286+
&timeout, 48 * 3600),
1287+
p_opt("force", param_bool, &old_force),
1288+
p_opt("timeout", param_number, &old_timeout),
1289+
NULL))
1290+
return command_param_failed();
1291+
/* Old style. */
1292+
if (old_timeout) {
1293+
*timeout = *old_timeout;
1294+
}
1295+
if (old_force) {
1296+
/* Use old default */
1297+
if (!old_timeout)
1298+
*timeout = 30;
1299+
force = *old_force;
1300+
}
1301+
1302+
/* New style: do_timeout unless it's 0 */
1303+
if (!old_timeout && !old_force)
1304+
do_timeout = (*timeout != 0);
1305+
else
1306+
do_timeout = true;
1307+
}
12361308

12371309
peer = peer_from_json(cmd->ld, buffer, idtok);
12381310
if (peer)
@@ -1283,7 +1355,8 @@ static struct command_result *json_close(struct command *cmd,
12831355
}
12841356

12851357
/* Register this command for later handling. */
1286-
register_close_command(cmd->ld, cmd, channel, *timeout, *force);
1358+
register_close_command(cmd->ld, cmd, channel,
1359+
do_timeout ? timeout : NULL, force);
12871360

12881361
/* Wait until close drops down to chain. */
12891362
return command_still_pending(cmd);

‎wallet/test/run-wallet.c

+3
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@ char *json_strdup(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const
325325
/* Generated stub for json_stream_success */
326326
struct json_stream *json_stream_success(struct command *cmd UNNEEDED)
327327
{ fprintf(stderr, "json_stream_success called!\n"); abort(); }
328+
/* Generated stub for json_to_bool */
329+
bool json_to_bool(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, bool *b UNNEEDED)
330+
{ fprintf(stderr, "json_to_bool called!\n"); abort(); }
328331
/* Generated stub for json_tok_bin_from_hex */
329332
u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED)
330333
{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); }

0 commit comments

Comments
 (0)
Please sign in to comment.