Skip to content

Commit

Permalink
lightningd: expose last_stable_connection in RPC.
Browse files Browse the repository at this point in the history
This isuseful to find completely dead channels which are worthy of
closing.

Changelog-Added: JSON-RPC: `listpeerchannels` field `last_stable_connection` showing when we last held an established channel for a minute or more.
Changelog-Added: JSON-RPC: `listclosedchannels` field `last_stable_connection` showing when we last held an established channel for a minute or more.
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Dec 13, 2023
1 parent 09689fe commit fec73cd
Show file tree
Hide file tree
Showing 15 changed files with 274 additions and 192 deletions.
10 changes: 10 additions & 0 deletions .msggen.json
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@
"ListClosedChannels.closedchannels[].funding_txid": 12,
"ListClosedChannels.closedchannels[].last_commitment_fee_msat": 23,
"ListClosedChannels.closedchannels[].last_commitment_txid": 22,
"ListClosedChannels.closedchannels[].last_stable_connection": 25,
"ListClosedChannels.closedchannels[].leased": 14,
"ListClosedChannels.closedchannels[].max_to_us_msat": 21,
"ListClosedChannels.closedchannels[].min_to_us_msat": 20,
Expand Down Expand Up @@ -1141,6 +1142,7 @@
"ListPeerChannels.channels[].inflight[]": 16,
"ListPeerChannels.channels[].initial_feerate": 12,
"ListPeerChannels.channels[].last_feerate": 13,
"ListPeerChannels.channels[].last_stable_connection": 56,
"ListPeerChannels.channels[].max_accepted_htlcs": 40,
"ListPeerChannels.channels[].max_to_us_msat": 25,
"ListPeerChannels.channels[].max_total_htlc_in_msat": 30,
Expand Down Expand Up @@ -3654,6 +3656,10 @@
"added": "pre-v0.10.1",
"deprecated": false
},
"ListClosedChannels.closedchannels[].last_stable_connection": {
"added": "v24.02",
"deprecated": false
},
"ListClosedChannels.closedchannels[].leased": {
"added": "pre-v0.10.1",
"deprecated": false
Expand Down Expand Up @@ -4386,6 +4392,10 @@
"added": "v23.02",
"deprecated": false
},
"ListPeerChannels.channels[].last_stable_connection": {
"added": "v24.02",
"deprecated": false
},
"ListPeerChannels.channels[].max_accepted_htlcs": {
"added": "v23.02",
"deprecated": false
Expand Down
2 changes: 2 additions & 0 deletions cln-grpc/proto/node.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions cln-grpc/src/convert.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions cln-rpc/src/model.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

376 changes: 188 additions & 188 deletions contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions contrib/pyln-testing/pyln/testing/grpc2py.py
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,7 @@ def listpeerchannels_channels2py(m):
"out_offered_msat": amount2msat(m.out_offered_msat), # PrimitiveField in generate_composite
"out_payments_fulfilled": m.out_payments_fulfilled, # PrimitiveField in generate_composite
"out_fulfilled_msat": amount2msat(m.out_fulfilled_msat), # PrimitiveField in generate_composite
"last_stable_connection": m.last_stable_connection, # PrimitiveField in generate_composite
"htlcs": [listpeerchannels_channels_htlcs2py(i) for i in m.htlcs], # ArrayField[composite] in generate_composite
"close_to_addr": m.close_to_addr, # PrimitiveField in generate_composite
})
Expand Down Expand Up @@ -968,6 +969,7 @@ def listclosedchannels_closedchannels2py(m):
"last_commitment_txid": hexlify(m.last_commitment_txid), # PrimitiveField in generate_composite
"last_commitment_fee_msat": amount2msat(m.last_commitment_fee_msat), # PrimitiveField in generate_composite
"close_cause": str(m.close_cause), # EnumField in generate_composite
"last_stable_connection": m.last_stable_connection, # PrimitiveField in generate_composite
})


Expand Down
3 changes: 2 additions & 1 deletion doc/lightning-listclosedchannels.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ On success, an object containing **closedchannels** is returned. It is an array
- **funding\_pushed\_msat** (msat, optional): How much `opener` pushed immediate (if non-zero)
- **last\_commitment\_txid** (hash, optional): The final commitment tx's txid (or mutual close, if we accepted it). Not present for some very old, small channels pre-0.7.0.
- **last\_commitment\_fee\_msat** (msat, optional): The fee on `last_commitment_txid`
- **last\_stable\_connection** (u64, optional): Last time we reestablished the open channel and stayed connected for 1 minute *(added v24.02)*

[comment]: # (GENERATE-FROM-SCHEMA-END)

Expand All @@ -76,4 +77,4 @@ RESOURCES

Main web site: <https://github.com/ElementsProject/lightning> Lightning

[comment]: # ( SHA256STAMP:3020e068d48a43494983df1a902d7483a52d0c41faef85e6d858dcf7c64c188d)
[comment]: # ( SHA256STAMP:4d3a2d030c820c5443ef0832d7d9cb01984420b45405298f1e25c7034497f716)
3 changes: 2 additions & 1 deletion doc/lightning-listpeerchannels.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ On success, an object containing **channels** is returned. It is an array of ob
- **out\_offered\_msat** (msat, optional): Total amount of outgoing payment attempts
- **out\_payments\_fulfilled** (u64, optional): Number of successful outgoing payment attempts
- **out\_fulfilled\_msat** (msat, optional): Total amount of successful outgoing payment attempts
- **last\_stable\_connection** (u64, optional): Last time we reestablished the open channel and stayed connected for 1 minute *(added v24.02)*
- **htlcs** (array of objects, optional): current HTLCs in this channel:
- **direction** (string): Whether it came from peer, or is going to peer (one of "in", "out")
- **id** (u64): Unique ID for this htlc on this channel in this direction
Expand Down Expand Up @@ -219,4 +220,4 @@ Main web site: <https://github.com/ElementsProject/lightning> Lightning
RFC site (BOLT \#9):
<https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md>

[comment]: # ( SHA256STAMP:3bea250fd96d16f58a0f1552862787b2dce1372ba9fbf3396b1817694a7aef84)
[comment]: # ( SHA256STAMP:5c68942d7f3bc27a368e82d3a0a21547ceb46cce4fe9a61dc0b30113a5d1cc44)
4 changes: 3 additions & 1 deletion doc/lightning-sql.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ The following tables are currently supported:
- `last_commitment_txid` (type `hash`, sqltype `BLOB`)
- `last_commitment_fee_msat` (type `msat`, sqltype `INTEGER`)
- `close_cause` (type `string`, sqltype `TEXT`)
- `last_stable_connection` (type `u64`, sqltype `INTEGER`)

- `forwards` indexed by `in_channel and in_htlc_id` (see lightning-listforwards(7))
- `created_index` (type `u64`, sqltype `INTEGER`)
Expand Down Expand Up @@ -341,6 +342,7 @@ The following tables are currently supported:
- `out_offered_msat` (type `msat`, sqltype `INTEGER`)
- `out_payments_fulfilled` (type `u64`, sqltype `INTEGER`)
- `out_fulfilled_msat` (type `msat`, sqltype `INTEGER`)
- `last_stable_connection` (type `u64`, sqltype `INTEGER`)
- related table `peerchannels_htlcs`
- `row` (reference to `peerchannels.rowid`, sqltype `INTEGER`)
- `arrindex` (index within array, sqltype `INTEGER`)
Expand Down Expand Up @@ -531,4 +533,4 @@ RESOURCES
---------

Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:f17b33523de930b61d6397a730c40b2254929cf38930629b9be66f3d52947d0e)
[comment]: # ( SHA256STAMP:299446e88b1f847a82ae63c2087ce28a36b7c8fea2b102d4e3d87c420a9268e9)
5 changes: 5 additions & 0 deletions doc/schemas/listclosedchannels.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@
"onchain"
],
"description": "What caused the channel to close"
},
"last_stable_connection": {
"type": "u64",
"added": "v24.02",
"description": "Last time we reestablished the open channel and stayed connected for 1 minute"
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions doc/schemas/listpeerchannels.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,11 @@
"type": "msat",
"description": "Total amount of successful outgoing payment attempts"
},
"last_stable_connection": {
"type": "u64",
"added": "v24.02",
"description": "Last time we reestablished the open channel and stayed connected for 1 minute"
},
"htlcs": {
"type": "array",
"description": "current HTLCs in this channel",
Expand Down Expand Up @@ -802,6 +807,7 @@
"out_payments_fulfilled": {},
"out_fulfilled_msat": {},
"out_msatoshi_fulfilled": {},
"last_stable_connection": {},
"htlcs": {},
"initial_feerate": {},
"last_feerate": {},
Expand Down Expand Up @@ -895,6 +901,7 @@
"out_payments_fulfilled": {},
"out_fulfilled_msat": {},
"out_msatoshi_fulfilled": {},
"last_stable_connection": {},
"htlcs": {},
"initial_feerate": {},
"last_feerate": {},
Expand Down Expand Up @@ -987,6 +994,7 @@
"out_payments_fulfilled": {},
"out_fulfilled_msat": {},
"out_msatoshi_fulfilled": {},
"last_stable_connection": {},
"htlcs": {},
"initial_feerate": {},
"last_feerate": {},
Expand Down Expand Up @@ -1080,6 +1088,7 @@
"out_payments_fulfilled": {},
"out_fulfilled_msat": {},
"out_msatoshi_fulfilled": {},
"last_stable_connection": {},
"htlcs": {},
"inflight": {},
"close_to_addr": {},
Expand Down
4 changes: 4 additions & 0 deletions lightningd/closed_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ static void json_add_closed_channel(struct json_stream *response,
}
json_add_string(response, "close_cause",
channel_change_state_reason_str(channel->state_change_cause));
if (channel->last_stable_connection != 0) {
json_add_u64(response, "last_stable_connection",
channel->last_stable_connection);
}
json_object_end(response);
}

Expand Down
5 changes: 5 additions & 0 deletions lightningd/peer_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,11 @@ static void json_add_channel(struct lightningd *ld,
json_object_end(response);
}
json_object_end(response);

if (channel->last_stable_connection != 0) {
json_add_u64(response, "last_stable_connection",
channel->last_stable_connection);
}
}

json_add_string(response, "state", channel_state_name(channel));
Expand Down
31 changes: 31 additions & 0 deletions tests/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -4412,3 +4412,34 @@ def test_offline_fd_check(node_factory):
# if get_node starts it, it'll expect an address, so do it manually.
l1 = node_factory.get_node(options={"offline": None}, start=False)
l1.daemon.start()


def test_last_stable_connection(node_factory):
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True})

# We wait a minute to be stable.
STABLE_TIME = 60
assert 'last_stable_connection' not in only_one(l1.rpc.listpeerchannels()['channels'])
assert 'last_stable_connection' not in only_one(l2.rpc.listpeerchannels()['channels'])

recon_time = time.time()

# This take a minute, so don't fail if TIMEOUT is set to 10.
wait_for(lambda: 'last_stable_connection' in only_one(l1.rpc.listpeerchannels()['channels']), timeout=STABLE_TIME + 15)
l1stable = only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection']
wait_for(lambda: 'last_stable_connection' in only_one(l2.rpc.listpeerchannels()['channels']))
l2stable = only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection']

# Disconnect, and/or restart then reconnect.
l1.rpc.disconnect(l2.info['id'], force=True)
recon_time = time.time()
l2.restart()
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)

assert only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] == l1stable
assert only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] == l2stable
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] != l1stable, timeout=STABLE_TIME + 15)
wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] != l2stable)

assert only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] > recon_time + STABLE_TIME
assert only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] > recon_time + STABLE_TIME
6 changes: 5 additions & 1 deletion tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3506,7 +3506,9 @@ def test_sql(node_factory, bitcoind):
{'name': 'last_commitment_fee_msat',
'type': 'msat'},
{'name': 'close_cause',
'type': 'string'}]},
'type': 'string'},
{'name': 'last_stable_connection',
'type': 'u64'}]},
'closedchannels_channel_type_bits': {
'columns': [{'name': 'row',
'type': 'u64'},
Expand Down Expand Up @@ -3840,6 +3842,8 @@ def test_sql(node_factory, bitcoind):
'type': 'u64'},
{'name': 'out_fulfilled_msat',
'type': 'msat'},
{'name': 'last_stable_connection',
'type': 'u64'},
{'name': 'reestablished',
'type': 'boolean'},
{'name': 'close_to_addr',
Expand Down

0 comments on commit fec73cd

Please sign in to comment.