Skip to content

Commit 8d8ab1b

Browse files
committed
chanbackup: make getemergencyrecoverdata rpc more verbose
Adding more information to geremergencyrecoverdata, to let users know if they are using legacy file format and the list of all the backed up channel ids. Key Changes: - Added: 1. can_create_penalty: To let user know if they need to update the file. 2. backed_up_channel_ids: List of all the backed up channels Changelog-Changed: Made getemergencyrecoverdata more verbose.
1 parent 88ad903 commit 8d8ab1b

10 files changed

Lines changed: 1140 additions & 1095 deletions

File tree

.msggen.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,8 @@
19011901
"FundPsbt.reservations[]": 6
19021902
},
19031903
"GetemergencyrecoverdataResponse": {
1904+
"GetEmergencyRecoverData.backed_up_channel_ids[]": 3,
1905+
"GetEmergencyRecoverData.can_create_penalty": 2,
19041906
"GetEmergencyRecoverData.filedata": 1
19051907
},
19061908
"GetinfoAddress": {
@@ -7844,6 +7846,14 @@
78447846
"added": "v24.11",
78457847
"deprecated": null
78467848
},
7849+
"GetEmergencyRecoverData.backed_up_channel_ids[]": {
7850+
"added": "v24.11",
7851+
"deprecated": null
7852+
},
7853+
"GetEmergencyRecoverData.can_create_penalty": {
7854+
"added": "v24.11",
7855+
"deprecated": null
7856+
},
78477857
"GetEmergencyRecoverData.filedata": {
78487858
"added": "v24.11",
78497859
"deprecated": null

cln-grpc/proto/node.proto

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cln-grpc/src/convert.rs

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cln-rpc/src/model.rs

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/msggen/msggen/schema.json

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14355,7 +14355,9 @@
1435514355
},
1435614356
"response": {
1435714357
"required": [
14358-
"filedata"
14358+
"filedata",
14359+
"can_create_penalty",
14360+
"backed_up_channel_ids"
1435914361
],
1436014362
"additionalProperties": false,
1436114363
"properties": {
@@ -14364,6 +14366,21 @@
1436414366
"description": [
1436514367
"The raw, hex-encoded, emergency.recover file"
1436614368
]
14369+
},
14370+
"can_create_penalty": {
14371+
"type": "boolean",
14372+
"description": [
14373+
"If false, you are using legacy file version, which can not create penalty transactions, kindly delete emergency.recover and restart the node!"
14374+
]
14375+
},
14376+
"backed_up_channel_ids": {
14377+
"type": "array",
14378+
"items": {
14379+
"type": "hex",
14380+
"description": [
14381+
"Channel IDs of channels backed up inside emergency.recover"
14382+
]
14383+
}
1436714384
}
1436814385
}
1436914386
},

contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py

Lines changed: 1020 additions & 1020 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/pyln-testing/pyln/testing/grpc2py.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,8 @@ def emergencyrecover2py(m):
456456

457457
def getemergencyrecoverdata2py(m):
458458
return remove_default({
459+
"backed_up_channel_ids": [hexlify(m.backed_up_channel_ids) for i in hexlify(m.backed_up_channel_ids)], # ArrayField[primitive] in generate_composite
460+
"can_create_penalty": m.can_create_penalty, # PrimitiveField in generate_composite
459461
"filedata": hexlify(m.filedata), # PrimitiveField in generate_composite
460462
})
461463

doc/schemas/getemergencyrecoverdata.json

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
},
1414
"response": {
1515
"required": [
16-
"filedata"
16+
"filedata",
17+
"can_create_penalty",
18+
"backed_up_channel_ids"
1719
],
1820
"additionalProperties": false,
1921
"properties": {
@@ -22,6 +24,21 @@
2224
"description": [
2325
"The raw, hex-encoded, emergency.recover file"
2426
]
27+
},
28+
"can_create_penalty": {
29+
"type": "boolean",
30+
"description": [
31+
"If false, you are using legacy file version, which can not create penalty transactions, kindly delete emergency.recover and restart the node!"
32+
]
33+
},
34+
"backed_up_channel_ids": {
35+
"type": "array",
36+
"items": {
37+
"type": "hex",
38+
"description": [
39+
"Channel IDs of channels backed up inside emergency.recover"
40+
]
41+
}
2542
}
2643
}
2744
},

plugins/chanbackup.c

Lines changed: 61 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,35 @@ static struct modern_scb_chan *convert_from_legacy(const tal_t *ctx, struct lega
320320
return modern_scb_tlv;
321321
}
322322

323+
/* Reads WIRE_STATIC_CHAN_BACKUP and converts from legacy_scb_chan to modern_scb_chan, if required. */
324+
static void read_static_chan_backup(struct command *cmd, const u8 *blob, u64 *version, u32 *timestamp, struct modern_scb_chan ***scb_tlvs, bool *is_converted) {
325+
bool is_tlvs = false;
326+
struct legacy_scb_chan **scb;
327+
328+
if(!fromwire_static_chan_backup(cmd,
329+
blob,
330+
version,
331+
timestamp,
332+
&scb)) {
333+
is_tlvs = true;
334+
if (!fromwire_static_chan_backup_with_tlvs(cmd,
335+
blob,
336+
version,
337+
timestamp,
338+
scb_tlvs)) {
339+
plugin_err(cmd->plugin, "Corrupted SCB!");
340+
}
341+
}
342+
*is_converted = !is_tlvs;
343+
if (!is_tlvs) {
344+
*scb_tlvs = tal_count(scb) ? tal_arr(cmd, struct modern_scb_chan *, tal_count(scb)): NULL;
345+
for (size_t i=0; i < tal_count(scb); i++){
346+
(*scb_tlvs)[i] = convert_from_legacy(cmd, scb[i]);
347+
}
348+
}
349+
return;
350+
}
351+
323352
/* Recovers the channels by making RPC to `recoverchannel` */
324353
static struct command_result *json_emergencyrecover(struct command *cmd,
325354
const char *buf,
@@ -328,28 +357,14 @@ static struct command_result *json_emergencyrecover(struct command *cmd,
328357
struct out_req *req;
329358
u64 version;
330359
u32 timestamp;
331-
struct legacy_scb_chan **scb;
360+
bool is_converted;
332361
struct modern_scb_chan **scb_tlvs;
333362

334363
if (!param(cmd, buf, params, NULL))
335364
return command_param_failed();
336365

337366
u8 *res = decrypt_scb(cmd->plugin);
338-
bool is_tlvs = false;
339-
if (!fromwire_static_chan_backup(cmd,
340-
res,
341-
&version,
342-
&timestamp,
343-
&scb)) {
344-
if(!fromwire_static_chan_backup_with_tlvs(cmd,
345-
res,
346-
&version,
347-
&timestamp,
348-
&scb_tlvs)) {
349-
plugin_err(cmd->plugin, "Corrupted SCB!");
350-
}
351-
is_tlvs = true;
352-
}
367+
read_static_chan_backup(cmd, res, &version, &timestamp, &scb_tlvs, &is_converted);
353368

354369
if ((version & 0x5555555555555555ULL) != (VERSION & 0x5555555555555555ULL)) {
355370
plugin_err(cmd->plugin,
@@ -360,26 +375,18 @@ static struct command_result *json_emergencyrecover(struct command *cmd,
360375
after_recover_rpc,
361376
forward_error, NULL);
362377

363-
json_array_start(req->js, "scb");
364-
if (is_tlvs) {
365-
for (size_t i=0; i<tal_count(scb_tlvs); i++) {
366-
u8 *scb_hex = tal_arr(cmd, u8, 0);
367-
towire_modern_scb_chan(&scb_hex,scb_tlvs[i]);
368-
json_add_hex_talarr(req->js, NULL, scb_hex);
369-
}
370-
} else {
378+
if (is_converted) {
371379
plugin_notify_message(cmd, LOG_DBG, "Processing legacy emergency.recover file format. "
372-
"Please migrate to the latest file format for improved "
373-
"compatibility and fund recovery.");
374-
375-
for (size_t i=0; i<tal_count(scb); i++) {
376-
u8 *scb_hex = tal_arr(cmd, u8, 0);
377-
struct modern_scb_chan *tmp_scb = convert_from_legacy(cmd, scb[i]);
378-
towire_modern_scb_chan(&scb_hex, tmp_scb);
379-
json_add_hex_talarr(req->js, NULL, scb_hex);
380-
}
380+
"Please migrate to the latest file format for improved "
381+
"compatibility and fund recovery.");
381382
}
382383

384+
json_array_start(req->js, "scb");
385+
for (size_t i=0; i<tal_count(scb_tlvs); i++) {
386+
u8 *scb_hex = tal_arr(cmd, u8, 0);
387+
towire_modern_scb_chan(&scb_hex, scb_tlvs[i]);
388+
json_add_hex_talarr(req->js, NULL, scb_hex);
389+
}
383390
json_array_end(req->js);
384391

385392
return send_outreq(req);
@@ -828,7 +835,7 @@ static struct command_result *store_latest_scb(struct command *cmd,
828835

829836
return jsonrpc_set_datastore_binary(cmd,
830837
"chanbackup/latestscb",
831-
received_scb,
838+
received_scb, recvd_scb_len,
832839
"create-or-replace",
833840
datastore_success,
834841
datastore_failed,
@@ -936,8 +943,8 @@ static struct command_result *after_latestscb(struct command *cmd,
936943
{
937944
u64 version;
938945
u32 timestamp;
946+
bool is_converted;
939947
struct modern_scb_chan **scb_tlvs;
940-
struct legacy_scb_chan **scb;
941948
struct json_stream *response;
942949
struct out_req *req;
943950

@@ -949,21 +956,7 @@ static struct command_result *after_latestscb(struct command *cmd,
949956
return command_finished(cmd, response);
950957
}
951958

952-
bool is_tlvs = false;
953-
if (!fromwire_static_chan_backup(cmd,
954-
res,
955-
&version,
956-
&timestamp,
957-
&scb)) {
958-
if(!fromwire_static_chan_backup_with_tlvs(cmd,
959-
res,
960-
&version,
961-
&timestamp,
962-
&scb_tlvs)) {
963-
plugin_err(cmd->plugin, "Corrupted SCB!");
964-
}
965-
is_tlvs = true;
966-
}
959+
read_static_chan_backup(cmd, res, &version, &timestamp, &scb_tlvs, &is_converted);
967960

968961
if ((version & 0x5555555555555555ULL) != (VERSION & 0x5555555555555555ULL)) {
969962
plugin_err(cmd->plugin,
@@ -975,28 +968,11 @@ static struct command_result *after_latestscb(struct command *cmd,
975968
&forward_error, NULL);
976969

977970
json_array_start(req->js, "scb");
978-
if (is_tlvs) {
979-
for (size_t i=0; i<tal_count(scb_tlvs); i++) {
980-
u8 *scb_hex = tal_arr(cmd, u8, 0);
981-
towire_modern_scb_chan(&scb_hex,scb_tlvs[i]);
982-
json_add_hex_talarr(req->js, NULL, scb_hex);
983-
}
984-
} else {
985-
for (size_t i=0; i<tal_count(scb); i++) {
986-
u8 *scb_hex = tal_arr(cmd, u8, 0);
987-
struct modern_scb_chan *tmp_scb_tlv = tal(cmd, struct modern_scb_chan);
988-
tmp_scb_tlv->id = scb[i]->id;
989-
tmp_scb_tlv->addr = scb[i]->addr;
990-
tmp_scb_tlv->cid = scb[i]->cid;
991-
tmp_scb_tlv->funding = scb[i]->funding;
992-
tmp_scb_tlv->funding_sats = scb[i]->funding_sats;
993-
tmp_scb_tlv->type = scb[i]->type;
994-
tmp_scb_tlv->tlvs = tlv_scb_tlvs_new(cmd);
995-
towire_modern_scb_chan(&scb_hex, tmp_scb_tlv);
996-
json_add_hex_talarr(req->js, NULL, scb_hex);
997-
}
971+
for (size_t i=0; i<tal_count(scb_tlvs); i++) {
972+
u8 *scb_hex = tal_arr(cmd, u8, 0);
973+
towire_modern_scb_chan(&scb_hex, scb_tlvs[i]);
974+
json_add_hex_talarr(req->js, NULL, scb_hex);
998975
}
999-
1000976
json_array_end(req->js);
1001977

1002978
return send_outreq(req);
@@ -1030,7 +1006,21 @@ static struct command_result *json_getemergencyrecoverdata(struct command *cmd,
10301006
response = jsonrpc_stream_success(cmd);
10311007
json_add_hex_talarr(response, "filedata", filedata);
10321008

1009+
// Add details about the SCB.
1010+
const u8 *decrypted_filedata = decrypt_scb(cmd->plugin);
1011+
u64 version;
1012+
u32 timestamp;
1013+
struct modern_scb_chan **scb_tlvs;
1014+
bool is_converted;
1015+
read_static_chan_backup(cmd, decrypted_filedata, &version, &timestamp, &scb_tlvs, &is_converted);
10331016

1017+
// If false, update the emergency.recover file immediately!
1018+
json_add_bool(response, "can_create_penalty", !is_converted);
1019+
json_array_start(response, "backed_up_channel_ids");
1020+
for (int i = 0; i < tal_count(scb_tlvs); i++) {
1021+
json_add_channel_id(response, NULL, &scb_tlvs[i]->cid);
1022+
}
1023+
json_array_end(response);
10341024
return command_finished(cmd, response);
10351025
}
10361026

tests/test_misc.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3038,8 +3038,10 @@ def test_getemergencyrecoverdata(node_factory):
30383038
Test getemergencyrecoverdata
30393039
"""
30403040
l1 = node_factory.get_node()
3041-
filedata = l1.rpc.getemergencyrecoverdata()['filedata']
3042-
3041+
rpc = l1.rpc.getemergencyrecoverdata()
3042+
filedata = rpc['filedata']
3043+
assert rpc['can_create_penalty'] is True
3044+
assert len(rpc['backed_up_channel_ids']) == 0
30433045
with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "emergency.recover"), "rb") as f:
30443046
lines = f.read().hex()
30453047
assert lines == filedata

0 commit comments

Comments
 (0)