Browse Source

close: add notification for slow closes.

For compatibility, we only do this if `allow-deprecated-apis` is false
for now.  Otherwise scripts parsing should use `grep -v '^# '` or
start using `-N none`.

Changelog-Added: JSON-RPC: `close` now sends notifications for slow closes (if `allow-deprecated-apis`=false)
Changelog-Deprecated: cli: scripts should filter out '^# ' or use `-N none`, as commands will start returning notifications soon
Fixes: #3925
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
travis-experimental
Rusty Russell 4 years ago
parent
commit
1e5789d421
  1. 8
      doc/lightning-close.7
  2. 6
      doc/lightning-close.7.md
  3. 11
      lightningd/peer_control.c
  4. 6
      lightningd/test/run-invoice-select-inchan.c
  5. 22
      tests/test_closing.py
  6. 2
      wallet/db_postgres_sqlgen.c
  7. 2
      wallet/db_sqlite3_sqlgen.c
  8. 4
      wallet/statements_gettextgen.po
  9. 6
      wallet/test/run-wallet.c

8
doc/lightning-close.7

@ -66,6 +66,12 @@ Prior to 0\.7\.2, \fBclose\fR took two parameters: \fIforce\fR and \fItimeout\fR
an RPC error (default)\. Even after the timeout, the channel would be an RPC error (default)\. Even after the timeout, the channel would be
closed if the peer reconnected\. closed if the peer reconnected\.
.SH NOTIFICATIONS
If \fBallow-deprecated-apis\fR is false, notifications may be returned
indicating what is going on, especially if the peer is offline and we
are waiting\. This will be enabled by default in future!
.SH RETURN VALUE .SH RETURN VALUE
On success, an object with fields \fItx\fR and \fItxid\fR containing the closing On success, an object with fields \fItx\fR and \fItxid\fR containing the closing
@ -95,4 +101,4 @@ ZmnSCPxj \fI<ZmnSCPxj@protonmail.com\fR> is mainly responsible\.
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
\" SHA256STAMP:3763db99c82aebedf40e1ef39407f2970d0408601f9250ec9c52995956da621b \" SHA256STAMP:d16e185f9a781f23987dfb65aaa1eae8dab19796975433c69e16f1f6b18751c5

6
doc/lightning-close.7.md

@ -57,6 +57,12 @@ Prior to 0.7.2, **close** took two parameters: *force* and *timeout*.
an RPC error (default). Even after the timeout, the channel would be an RPC error (default). Even after the timeout, the channel would be
closed if the peer reconnected. closed if the peer reconnected.
NOTIFICATIONS
-------------
If `allow-deprecated-apis` is false, notifications may be returned
indicating what is going on, especially if the peer is offline and we
are waiting. This will be enabled by default in future!
RETURN VALUE RETURN VALUE
------------ ------------

11
lightningd/peer_control.c

@ -284,6 +284,9 @@ close_command_timeout(struct close_command *cc)
/* This will trigger drop_to_chain, which will trigger /* This will trigger drop_to_chain, which will trigger
* resolution of the command and destruction of the * resolution of the command and destruction of the
* close_command. */ * close_command. */
if (!deprecated_apis)
json_notify_fmt(cc->cmd, LOG_INFORM,
"Timed out, forcing close.");
channel_fail_permanent(cc->channel, channel_fail_permanent(cc->channel,
"Forcibly closed by 'close' command timeout"); "Forcibly closed by 'close' command timeout");
} }
@ -306,6 +309,14 @@ register_close_command(struct lightningd *ld,
tal_add_destructor2(channel, tal_add_destructor2(channel,
&destroy_close_command_on_channel_destroy, &destroy_close_command_on_channel_destroy,
cc); cc);
if (!deprecated_apis && !channel->owner) {
char *msg = tal_strdup(tmpctx, "peer is offline, will negotiate once they reconnect");
if (timeout)
tal_append_fmt(&msg, " (%u seconds before unilateral close)",
timeout);
json_notify_fmt(cmd, LOG_INFORM, "%s.", msg);
}
log_debug(ld->log, "close_command: timeout = %u", timeout); log_debug(ld->log, "close_command: timeout = %u", timeout);
if (timeout) if (timeout)
new_reltimer(ld->timers, cc, time_from_sec(timeout), new_reltimer(ld->timers, cc, time_from_sec(timeout),

6
lightningd/test/run-invoice-select-inchan.c

@ -277,6 +277,12 @@ void json_array_start(struct json_stream *js UNNEEDED, const char *fieldname UNN
char *json_member_direct(struct json_stream *js UNNEEDED, char *json_member_direct(struct json_stream *js UNNEEDED,
const char *fieldname UNNEEDED, size_t extra UNNEEDED) const char *fieldname UNNEEDED, size_t extra UNNEEDED)
{ fprintf(stderr, "json_member_direct called!\n"); abort(); } { fprintf(stderr, "json_member_direct called!\n"); abort(); }
/* Generated stub for json_notify_fmt */
void json_notify_fmt(struct command *cmd UNNEEDED,
enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "json_notify_fmt called!\n"); abort(); }
/* Generated stub for json_object_end */ /* Generated stub for json_object_end */
void json_object_end(struct json_stream *js UNNEEDED) void json_object_end(struct json_stream *js UNNEEDED)
{ fprintf(stderr, "json_object_end called!\n"); abort(); } { fprintf(stderr, "json_object_end called!\n"); abort(); }

22
tests/test_closing.py

@ -4,13 +4,14 @@ from pyln.client import RpcError
from shutil import copyfile from shutil import copyfile
from utils import ( from utils import (
only_one, sync_blockheight, wait_for, DEVELOPER, TIMEOUT, only_one, sync_blockheight, wait_for, DEVELOPER, TIMEOUT,
account_balance, first_channel_id, basic_fee account_balance, first_channel_id, basic_fee, TEST_NETWORK,
) )
import os import os
import queue import queue
import pytest import pytest
import re import re
import subprocess
import threading import threading
import unittest import unittest
@ -126,6 +127,25 @@ def test_closing_while_disconnected(node_factory, bitcoind, executor):
wait_for(lambda: len(l2.rpc.listchannels()['channels']) == 0) wait_for(lambda: len(l2.rpc.listchannels()['channels']) == 0)
def test_closing_disconnected_notify(node_factory, bitcoind, executor):
l1, l2 = node_factory.line_graph(2)
l1.pay(l2, 200000000)
l2.stop()
wait_for(lambda: not only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'])
out = subprocess.check_output(['cli/lightning-cli',
'--network={}'.format(TEST_NETWORK),
'--lightning-dir={}'
.format(l1.daemon.lightning_dir),
'close',
l2.info['id'],
'5']).decode('utf-8').splitlines()
assert out[0] == '# peer is offline, will negotiate once they reconnect (5 seconds before unilateral close).'
assert out[1] == '# Timed out, forcing close.'
assert not any([line.startswith('#') for line in out[2:]])
def test_closing_id(node_factory): def test_closing_id(node_factory):
"""Test closing using peer ID and full channel ID """Test closing using peer ID and full channel ID
""" """

2
wallet/db_postgres_sqlgen.c

@ -1660,4 +1660,4 @@ struct db_query db_postgres_queries[] = {
#endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */
// SHA256STAMP:17fb4d8f180303fb57e28b5b5ac5a9a326826297933461030e9c4f85e02723f9 // SHA256STAMP:8a260050ced7606fcad6e15df51a42a442f3119ad82d8e86fa2d348a2a45ee1a

2
wallet/db_sqlite3_sqlgen.c

@ -1660,4 +1660,4 @@ struct db_query db_sqlite3_queries[] = {
#endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */
// SHA256STAMP:17fb4d8f180303fb57e28b5b5ac5a9a326826297933461030e9c4f85e02723f9 // SHA256STAMP:8a260050ced7606fcad6e15df51a42a442f3119ad82d8e86fa2d348a2a45ee1a

4
wallet/statements_gettextgen.po

@ -1090,7 +1090,7 @@ msgstr ""
msgid "not a valid SQL statement" msgid "not a valid SQL statement"
msgstr "" msgstr ""
#: wallet/test/run-wallet.c:1359 #: wallet/test/run-wallet.c:1365
msgid "INSERT INTO channels (id) VALUES (1);" msgid "INSERT INTO channels (id) VALUES (1);"
msgstr "" msgstr ""
# SHA256STAMP:13b6fd428b7832d7122e64b76c7833788472fdaacf521ef9cb2d0890f65b8db8 # SHA256STAMP:9d0158f039940ef277ed6fc3a27b3695dec7f9869ea11e0f9eea8313a5849f08

6
wallet/test/run-wallet.c

@ -347,6 +347,12 @@ void json_array_start(struct json_stream *js UNNEEDED, const char *fieldname UNN
const jsmntok_t *json_get_member(const char *buffer UNNEEDED, const jsmntok_t tok[] UNNEEDED, const jsmntok_t *json_get_member(const char *buffer UNNEEDED, const jsmntok_t tok[] UNNEEDED,
const char *label UNNEEDED) const char *label UNNEEDED)
{ fprintf(stderr, "json_get_member called!\n"); abort(); } { fprintf(stderr, "json_get_member called!\n"); abort(); }
/* Generated stub for json_notify_fmt */
void json_notify_fmt(struct command *cmd UNNEEDED,
enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "json_notify_fmt called!\n"); abort(); }
/* Generated stub for json_object_end */ /* Generated stub for json_object_end */
void json_object_end(struct json_stream *js UNNEEDED) void json_object_end(struct json_stream *js UNNEEDED)
{ fprintf(stderr, "json_object_end called!\n"); abort(); } { fprintf(stderr, "json_object_end called!\n"); abort(); }

Loading…
Cancel
Save