Skip to content

Commit 32d4ada

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 bf6703a commit 32d4ada

File tree

10 files changed

+1098
-1063
lines changed

10 files changed

+1098
-1063
lines changed

.msggen.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,8 @@
17781778
"FundPsbt.reservations[]": 6
17791779
},
17801780
"GetemergencyrecoverdataResponse": {
1781+
"GetEmergencyRecoverData.backed_up_channel_ids[]": 3,
1782+
"GetEmergencyRecoverData.can_create_penalty": 2,
17811783
"GetEmergencyRecoverData.filedata": 1
17821784
},
17831785
"GetinfoAddress": {
@@ -7405,6 +7407,14 @@
74057407
"added": "v24.11",
74067408
"deprecated": null
74077409
},
7410+
"GetEmergencyRecoverData.backed_up_channel_ids[]": {
7411+
"added": "v24.11",
7412+
"deprecated": null
7413+
},
7414+
"GetEmergencyRecoverData.can_create_penalty": {
7415+
"added": "v24.11",
7416+
"deprecated": null
7417+
},
74087418
"GetEmergencyRecoverData.filedata": {
74097419
"added": "v24.11",
74107420
"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
@@ -14058,7 +14058,9 @@
1405814058
},
1405914059
"response": {
1406014060
"required": [
14061-
"filedata"
14061+
"filedata",
14062+
"can_create_penalty",
14063+
"backed_up_channel_ids"
1406214064
],
1406314065
"additionalProperties": false,
1406414066
"properties": {
@@ -14067,6 +14069,21 @@
1406714069
"description": [
1406814070
"The raw, hex-encoded, emergency.recover file"
1406914071
]
14072+
},
14073+
"can_create_penalty": {
14074+
"type": "boolean",
14075+
"description": [
14076+
"If false, you are using legacy file version, which can not create penalty transactions, kindly delete emergency.recover and restart the node!"
14077+
]
14078+
},
14079+
"backed_up_channel_ids": {
14080+
"type": "array",
14081+
"items": {
14082+
"type": "hex",
14083+
"description": [
14084+
"Channel IDs of channels backed up inside emergency.recover"
14085+
]
14086+
}
1407014087
}
1407114088
}
1407214089
},

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

Lines changed: 977 additions & 987 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
@@ -443,6 +443,8 @@ def emergencyrecover2py(m):
443443

444444
def getemergencyrecoverdata2py(m):
445445
return remove_default({
446+
"backed_up_channel_ids": [hexlify(m.backed_up_channel_ids) for i in hexlify(m.backed_up_channel_ids)], # ArrayField[primitive] in generate_composite
447+
"can_create_penalty": m.can_create_penalty, # PrimitiveField in generate_composite
446448
"filedata": hexlify(m.filedata), # PrimitiveField in generate_composite
447449
})
448450

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: 62 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,35 @@ static struct modern_scb_chan *convert_from_legacy(const tal_t *ctx, struct lega
316316
return modern_scb_tlv;
317317
}
318318

319+
/* Reads WIRE_STATIC_CHAN_BACKUP and converts from legacy_scb_chan to modern_scb_chan, if required. */
320+
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) {
321+
bool is_tlvs = false;
322+
struct legacy_scb_chan **scb;
323+
324+
if(!fromwire_static_chan_backup(cmd,
325+
blob,
326+
version,
327+
timestamp,
328+
&scb)) {
329+
is_tlvs = true;
330+
if (!fromwire_static_chan_backup_with_tlvs(cmd,
331+
blob,
332+
version,
333+
timestamp,
334+
scb_tlvs)) {
335+
plugin_err(cmd->plugin, "Corrupted SCB!");
336+
}
337+
}
338+
*is_converted = !is_tlvs;
339+
if (!is_tlvs) {
340+
*scb_tlvs = tal_count(scb) ? tal_arr(cmd, struct modern_scb_chan *, tal_count(scb)): NULL;
341+
for (size_t i=0; i < tal_count(scb); i++){
342+
(*scb_tlvs)[i] = convert_from_legacy(cmd, scb[i]);
343+
}
344+
}
345+
return;
346+
}
347+
319348
/* Recovers the channels by making RPC to `recoverchannel` */
320349
static struct command_result *json_emergencyrecover(struct command *cmd,
321350
const char *buf,
@@ -324,28 +353,14 @@ static struct command_result *json_emergencyrecover(struct command *cmd,
324353
struct out_req *req;
325354
u64 version;
326355
u32 timestamp;
327-
struct legacy_scb_chan **scb;
356+
bool is_converted;
328357
struct modern_scb_chan **scb_tlvs;
329358

330359
if (!param(cmd, buf, params, NULL))
331360
return command_param_failed();
332361

333362
u8 *res = decrypt_scb(cmd->plugin);
334-
bool is_tlvs = false;
335-
if (!fromwire_static_chan_backup(cmd,
336-
res,
337-
&version,
338-
&timestamp,
339-
&scb)) {
340-
if(!fromwire_static_chan_backup_with_tlvs(cmd,
341-
res,
342-
&version,
343-
&timestamp,
344-
&scb_tlvs)) {
345-
plugin_err(cmd->plugin, "Corrupted SCB!");
346-
}
347-
is_tlvs = true;
348-
}
363+
read_static_chan_backup(cmd, res, &version, &timestamp, &scb_tlvs, &is_converted);
349364

350365
if ((version & 0x5555555555555555ULL) != (VERSION & 0x5555555555555555ULL)) {
351366
plugin_err(cmd->plugin,
@@ -356,26 +371,18 @@ static struct command_result *json_emergencyrecover(struct command *cmd,
356371
after_recover_rpc,
357372
forward_error, NULL);
358373

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

380+
json_array_start(req->js, "scb");
381+
for (size_t i=0; i<tal_count(scb_tlvs); i++) {
382+
u8 *scb_hex = tal_arr(cmd, u8, 0);
383+
towire_modern_scb_chan(&scb_hex, scb_tlvs[i]);
384+
json_add_hex_talarr(req->js, NULL, scb_hex);
385+
}
379386
json_array_end(req->js);
380387

381388
return send_outreq(req);
@@ -834,7 +841,7 @@ static struct command_result *store_latest_scb(struct command *cmd,
834841
store_data:
835842
return jsonrpc_set_datastore_binary(cmd,
836843
"chanbackup/latestscb",
837-
received_scb,
844+
received_scb, recvd_scb_len,
838845
"create-or-replace",
839846
datastore_success,
840847
datastore_failed,
@@ -946,8 +953,8 @@ static struct command_result *after_latestscb(struct command *cmd,
946953
{
947954
u64 version;
948955
u32 timestamp;
956+
bool is_converted;
949957
struct modern_scb_chan **scb_tlvs;
950-
struct legacy_scb_chan **scb;
951958
struct json_stream *response;
952959
struct out_req *req;
953960

@@ -959,21 +966,7 @@ static struct command_result *after_latestscb(struct command *cmd,
959966
return command_finished(cmd, response);
960967
}
961968

962-
bool is_tlvs = false;
963-
if (!fromwire_static_chan_backup(cmd,
964-
res,
965-
&version,
966-
&timestamp,
967-
&scb)) {
968-
if(!fromwire_static_chan_backup_with_tlvs(cmd,
969-
res,
970-
&version,
971-
&timestamp,
972-
&scb_tlvs)) {
973-
plugin_err(cmd->plugin, "Corrupted SCB!");
974-
}
975-
is_tlvs = true;
976-
}
969+
read_static_chan_backup(cmd, res, &version, &timestamp, &scb_tlvs, &is_converted);
977970

978971
if ((version & 0x5555555555555555ULL) != (VERSION & 0x5555555555555555ULL)) {
979972
plugin_err(cmd->plugin,
@@ -985,28 +978,11 @@ static struct command_result *after_latestscb(struct command *cmd,
985978
&forward_error, NULL);
986979

987980
json_array_start(req->js, "scb");
988-
if (is_tlvs) {
989-
for (size_t i=0; i<tal_count(scb_tlvs); i++) {
990-
u8 *scb_hex = tal_arr(cmd, u8, 0);
991-
towire_modern_scb_chan(&scb_hex,scb_tlvs[i]);
992-
json_add_hex_talarr(req->js, NULL, scb_hex);
993-
}
994-
} else {
995-
for (size_t i=0; i<tal_count(scb); i++) {
996-
u8 *scb_hex = tal_arr(cmd, u8, 0);
997-
struct modern_scb_chan *tmp_scb_tlv = tal(cmd, struct modern_scb_chan);
998-
tmp_scb_tlv->id = scb[i]->id;
999-
tmp_scb_tlv->addr = scb[i]->addr;
1000-
tmp_scb_tlv->cid = scb[i]->cid;
1001-
tmp_scb_tlv->funding = scb[i]->funding;
1002-
tmp_scb_tlv->funding_sats = scb[i]->funding_sats;
1003-
tmp_scb_tlv->type = scb[i]->type;
1004-
tmp_scb_tlv->tlvs = tlv_scb_tlvs_new(cmd);
1005-
towire_modern_scb_chan(&scb_hex, tmp_scb_tlv);
1006-
json_add_hex_talarr(req->js, NULL, scb_hex);
1007-
}
981+
for (size_t i=0; i<tal_count(scb_tlvs); i++) {
982+
u8 *scb_hex = tal_arr(cmd, u8, 0);
983+
towire_modern_scb_chan(&scb_hex, scb_tlvs[i]);
984+
json_add_hex_talarr(req->js, NULL, scb_hex);
1008985
}
1009-
1010986
json_array_end(req->js);
1011987

1012988
return send_outreq(req);
@@ -1040,7 +1016,21 @@ static struct command_result *json_getemergencyrecoverdata(struct command *cmd,
10401016
response = jsonrpc_stream_success(cmd);
10411017
json_add_hex_talarr(response, "filedata", filedata);
10421018

1043-
1019+
// Add details about the SCB.
1020+
const u8 *decrypted_filedata = decrypt_scb(cmd->plugin);
1021+
u64 version;
1022+
u32 timestamp;
1023+
struct modern_scb_chan **scb_tlvs;
1024+
bool is_converted;
1025+
read_static_chan_backup(cmd, decrypted_filedata, &version, &timestamp, &scb_tlvs, &is_converted);
1026+
1027+
// If false, update the emergency.recover file immediately!
1028+
json_add_bool(response, "can_create_penalty", !is_converted);
1029+
json_array_start(response, "backed_up_channel_ids");
1030+
for (int i = 0; i < tal_count(scb_tlvs); i++) {
1031+
json_add_channel_id(response, NULL, &scb_tlvs[i]->cid);
1032+
}
1033+
json_array_end(response);
10441034
return command_finished(cmd, response);
10451035
}
10461036

tests/test_misc.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2973,8 +2973,10 @@ def test_getemergencyrecoverdata(node_factory):
29732973
Test getemergencyrecoverdata
29742974
"""
29752975
l1 = node_factory.get_node()
2976-
filedata = l1.rpc.getemergencyrecoverdata()['filedata']
2977-
2976+
rpc = l1.rpc.getemergencyrecoverdata()
2977+
filedata = rpc['filedata']
2978+
assert rpc['can_create_penalty'] is True
2979+
assert len(rpc['backed_up_channel_ids']) == 0
29782980
with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "emergency.recover"), "rb") as f:
29792981
lines = f.read().hex()
29802982
assert lines == filedata

0 commit comments

Comments
 (0)