From e711f6c589edff821ee54b5a8218d8b5867c4706 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 25 Aug 2021 12:20:13 +0930 Subject: [PATCH] datastore: allow strings. It's common, and the simplest case. Signed-off-by: Rusty Russell --- doc/lightning-datastore.7 | 6 ++-- doc/lightning-datastore.7.md | 5 +-- doc/lightning-deldatastore.7 | 4 ++- doc/lightning-deldatastore.7.md | 3 +- doc/lightning-listdatastore.7 | 4 ++- doc/lightning-listdatastore.7.md | 3 +- doc/schemas/datastore.schema.json | 4 +++ doc/schemas/deldatastore.schema.json | 4 +++ doc/schemas/listdatastore.schema.json | 4 +++ lightningd/datastore.c | 22 ++++++++++-- tests/test_misc.py | 52 +++++++++++++-------------- 11 files changed, 74 insertions(+), 37 deletions(-) diff --git a/doc/lightning-datastore.7 b/doc/lightning-datastore.7 index f91d9f614..08bc1deb7 100644 --- a/doc/lightning-datastore.7 +++ b/doc/lightning-datastore.7 @@ -3,7 +3,7 @@ lightning-datastore - Command for storing (plugin) data .SH SYNOPSIS -\fBdatastore\fR \fIkey\fR \fIhex\fR +\fBdatastore\fR \fIkey\fR [\fIstring\fR|\fIhex\fR] .SH DESCRIPTION @@ -23,6 +23,8 @@ On success, an object is returned, containing: \fBkey\fR (string): The key which has been added to the datastore .IP \[bu] \fBhex\fR (hex): The hex data which has been added to the datastore +.IP \[bu] +\fBstring\fR (string, optional): The data as a string, if it's valid utf-8 .RE @@ -48,4 +50,4 @@ Rusty Russell \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:1972be4c054c35bf2e0fdbf2e7bb9a3870b3322a008ae29e6a84207c7b527458 +\" SHA256STAMP:e0ea91fb846859bc22af6e4beacd5fb726d6c4ffefea5cc4e3a1250b81665317 diff --git a/doc/lightning-datastore.7.md b/doc/lightning-datastore.7.md index 157013da7..02d2b6464 100644 --- a/doc/lightning-datastore.7.md +++ b/doc/lightning-datastore.7.md @@ -4,7 +4,7 @@ lightning-datastore -- Command for storing (plugin) data SYNOPSIS -------- -**datastore** *key* *hex* +**datastore** *key* [*string*|*hex*] DESCRIPTION ----------- @@ -22,6 +22,7 @@ RETURN VALUE On success, an object is returned, containing: - **key** (string): The key which has been added to the datastore - **hex** (hex): The hex data which has been added to the datastore +- **string** (string, optional): The data as a string, if it's valid utf-8 [comment]: # (GENERATE-FROM-SCHEMA-END) The main cause of failure is an already-existing entry. @@ -44,4 +45,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:692c74ea1dea25266d8d562bc23e5c3c14223f62c9152a223cbd9c2de4d01efb) +[comment]: # ( SHA256STAMP:5eda4592b0a5e893853ea15ce7e800bb94e3a26ebd932507c2a55890f56fee14) diff --git a/doc/lightning-deldatastore.7 b/doc/lightning-deldatastore.7 index c3470d6a3..a1da1ef40 100644 --- a/doc/lightning-deldatastore.7 +++ b/doc/lightning-deldatastore.7 @@ -22,6 +22,8 @@ On success, an object is returned, containing: \fBkey\fR (string): The key which has been removed from the datastore .IP \[bu] \fBhex\fR (hex): The hex data which has removed from the datastore +.IP \[bu] +\fBstring\fR (string, optional): The data as a string, if it's valid utf-8 .RE @@ -47,4 +49,4 @@ Rusty Russell \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:61af040ae88b08a8cc0e5f0d510a9613fbdc89e6e8d5b7dfebedcd134a91fb4b +\" SHA256STAMP:8e1a383ed176a0b7f8b849bf2bb05f5caaaf0de4f375afd38cbc668f1f17d9a2 diff --git a/doc/lightning-deldatastore.7.md b/doc/lightning-deldatastore.7.md index 52f749916..898d64fcf 100644 --- a/doc/lightning-deldatastore.7.md +++ b/doc/lightning-deldatastore.7.md @@ -21,6 +21,7 @@ RETURN VALUE On success, an object is returned, containing: - **key** (string): The key which has been removed from the datastore - **hex** (hex): The hex data which has removed from the datastore +- **string** (string, optional): The data as a string, if it's valid utf-8 [comment]: # (GENERATE-FROM-SCHEMA-END) The main cause of failure is an non-existing entry. @@ -43,4 +44,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:8e732382fa499ed98dc015a1525b4fa07a2d20d5009c305945f06dae84b408c7) +[comment]: # ( SHA256STAMP:cc1dedfded4902f59879665e95a1a877c8c72c0e217a3db3de3ae8dde859e67a) diff --git a/doc/lightning-listdatastore.7 b/doc/lightning-listdatastore.7 index 7dfb6b173..3dc225224 100644 --- a/doc/lightning-listdatastore.7 +++ b/doc/lightning-listdatastore.7 @@ -23,6 +23,8 @@ On success, an object containing \fBdatastore\fR is returned\. It is an array o \fBkey\fR (string): The key which from the datastore .IP \[bu] \fBhex\fR (hex): The hex data from the datastore +.IP \[bu] +\fBstring\fR (string, optional): The data as a string, if it's valid utf-8 .RE @@ -45,4 +47,4 @@ Rusty Russell \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:a501f1c8a7517726a49e48180c5d20966df7158f1af3afdd1654a435473efb5d +\" SHA256STAMP:bcc83095fc1695b0c81a2763109e280d711e29edbc395672314d052f9d99a72c diff --git a/doc/lightning-listdatastore.7.md b/doc/lightning-listdatastore.7.md index 6530110ad..f460f9784 100644 --- a/doc/lightning-listdatastore.7.md +++ b/doc/lightning-listdatastore.7.md @@ -22,6 +22,7 @@ RETURN VALUE On success, an object containing **datastore** is returned. It is an array of objects, where each object contains: - **key** (string): The key which from the datastore - **hex** (hex): The hex data from the datastore +- **string** (string, optional): The data as a string, if it's valid utf-8 [comment]: # (GENERATE-FROM-SCHEMA-END) The following error codes may occur: @@ -42,4 +43,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:660d1723bcea3d4800db72a9204ed577426e7b3ab99f491145e633df89a46fac) +[comment]: # ( SHA256STAMP:b93d725952e9ac5134dc25711d9bfbbd8b719e8ee8592f27bd1becbb56f89971) diff --git a/doc/schemas/datastore.schema.json b/doc/schemas/datastore.schema.json index 849637ddc..22edcbeba 100644 --- a/doc/schemas/datastore.schema.json +++ b/doc/schemas/datastore.schema.json @@ -11,6 +11,10 @@ "hex": { "type": "hex", "description": "The hex data which has been added to the datastore" + }, + "string": { + "type": "string", + "description": "The data as a string, if it's valid utf-8" } } } diff --git a/doc/schemas/deldatastore.schema.json b/doc/schemas/deldatastore.schema.json index 0e28aff2d..d58873663 100644 --- a/doc/schemas/deldatastore.schema.json +++ b/doc/schemas/deldatastore.schema.json @@ -11,6 +11,10 @@ "hex": { "type": "hex", "description": "The hex data which has removed from the datastore" + }, + "string": { + "type": "string", + "description": "The data as a string, if it's valid utf-8" } } } diff --git a/doc/schemas/listdatastore.schema.json b/doc/schemas/listdatastore.schema.json index 2b200e546..8ecccc642 100644 --- a/doc/schemas/listdatastore.schema.json +++ b/doc/schemas/listdatastore.schema.json @@ -18,6 +18,10 @@ "hex": { "type": "hex", "description": "The hex data from the datastore" + }, + "string": { + "type": "string", + "description": "The data as a string, if it's valid utf-8" } } } diff --git a/lightningd/datastore.c b/lightningd/datastore.c index e9187f67f..6553e4f52 100644 --- a/lightningd/datastore.c +++ b/lightningd/datastore.c @@ -7,8 +7,12 @@ static void json_add_datastore(struct json_stream *response, const char *key, const u8 *data) { + const char *str; json_add_string(response, "key", key); json_add_hex(response, "hex", data, tal_bytelen(data)); + str = utf8_str(response, data, tal_bytelen(data)); + if (str) + json_add_string(response, "string", str); } static struct command_result *json_datastore(struct command *cmd, @@ -17,15 +21,27 @@ static struct command_result *json_datastore(struct command *cmd, const jsmntok_t *params) { struct json_stream *response; - const char *key; + const char *key, *strdata; u8 *data; if (!param(cmd, buffer, params, p_req("key", param_string, &key), - p_req("hex", param_bin_from_hex, &data), + p_opt("string", param_string, &strdata), + p_opt("hex", param_bin_from_hex, &data), NULL)) return command_param_failed(); + if (strdata) { + if (data) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Cannot have both hex and string"); + data = tal_dup_arr(cmd, u8, (u8 *)strdata, strlen(strdata), 0); + } else { + if (!data) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Must have either hex or string"); + } + if (!wallet_datastore_add(cmd->ld->wallet, key, data)) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Key already exists"); @@ -103,7 +119,7 @@ static const struct json_command datastore_command = { "datastore", "utility", json_datastore, - "Add a {key} and {hex} data to the data store", + "Add a {key} and {hex}/{string} data to the data store", }; AUTODATA(json_command, &datastore_command); diff --git a/tests/test_misc.py b/tests/test_misc.py index 41b3dbf08..9a39c6774 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -2635,45 +2635,45 @@ def test_datastore(node_factory): # Add entries. somedata = b'somedata'.hex() - assert l1.rpc.datastore('somekey', somedata) == {'key': 'somekey', - 'hex': somedata} + somedata_expect = {'key': 'somekey', + 'hex': somedata, + 'string': 'somedata'} + assert l1.rpc.datastore(key='somekey', hex=somedata) == somedata_expect - assert l1.rpc.listdatastore() == {'datastore': [{'key': 'somekey', - 'hex': somedata}]} - assert l1.rpc.listdatastore('somekey') == {'datastore': [{'key': 'somekey', - 'hex': somedata}]} + assert l1.rpc.listdatastore() == {'datastore': [somedata_expect]} + assert l1.rpc.listdatastore('somekey') == {'datastore': [somedata_expect]} assert l1.rpc.listdatastore('otherkey') == {'datastore': []} otherdata = b'otherdata'.hex() - assert l1.rpc.datastore('otherkey', otherdata) == {'key': 'otherkey', - 'hex': otherdata} + otherdata_expect = {'key': 'otherkey', + 'hex': otherdata, + 'string': 'otherdata'} + assert l1.rpc.datastore(key='otherkey', string='otherdata') == otherdata_expect - assert l1.rpc.listdatastore('somekey') == {'datastore': [{'key': 'somekey', - 'hex': somedata}]} - assert l1.rpc.listdatastore('otherkey') == {'datastore': [{'key': 'otherkey', - 'hex': otherdata}]} + assert l1.rpc.listdatastore('somekey') == {'datastore': [somedata_expect]} + assert l1.rpc.listdatastore('otherkey') == {'datastore': [otherdata_expect]} assert l1.rpc.listdatastore('badkey') == {'datastore': []} ds = l1.rpc.listdatastore() # Order is undefined! - assert (ds == {'datastore': [{'key': 'somekey', 'hex': somedata}, - {'key': 'otherkey', 'hex': otherdata}]} - or ds == {'datastore': [{'key': 'otherkey', 'hex': otherdata}, - {'key': 'somekey', 'hex': somedata}]}) + assert (ds == {'datastore': [somedata_expect, otherdata_expect]} + or ds == {'datastore': [otherdata_expect, somedata_expect]}) - assert l1.rpc.deldatastore('somekey') == {'key': 'somekey', - 'hex': somedata} - assert l1.rpc.listdatastore() == {'datastore': [{'key': 'otherkey', - 'hex': otherdata}]} + assert l1.rpc.deldatastore('somekey') == somedata_expect + assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]} assert l1.rpc.listdatastore('somekey') == {'datastore': []} - assert l1.rpc.listdatastore('otherkey') == {'datastore': [{'key': 'otherkey', - 'hex': otherdata}]} + assert l1.rpc.listdatastore('otherkey') == {'datastore': [otherdata_expect]} assert l1.rpc.listdatastore('badkey') == {'datastore': []} - assert l1.rpc.listdatastore() == {'datastore': [{'key': 'otherkey', - 'hex': otherdata}]} + assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]} + + # if it's not a string, won't print + badstring_expect = {'key': 'badstring', + 'hex': '00'} + assert l1.rpc.datastore(key='badstring', hex='00') == badstring_expect + assert l1.rpc.listdatastore('badstring') == {'datastore': [badstring_expect]} + assert l1.rpc.deldatastore('badstring') == badstring_expect # It's persistent l1.restart() - assert l1.rpc.listdatastore() == {'datastore': [{'key': 'otherkey', - 'hex': otherdata}]} + assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]}