mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
datastore: add generation, simple atomicity.
We add a generation counter, and allow update or del conditional on a given generation. Formalizes error codes, too, since we have more now. Suggested-by: @shesek Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
432508e65e
commit
533571a655
@@ -86,6 +86,13 @@ static const errcode_t OFFER_ROUTE_NOT_FOUND = 1003;
|
|||||||
static const errcode_t OFFER_BAD_INVREQ_REPLY = 1004;
|
static const errcode_t OFFER_BAD_INVREQ_REPLY = 1004;
|
||||||
static const errcode_t OFFER_TIMEOUT = 1005;
|
static const errcode_t OFFER_TIMEOUT = 1005;
|
||||||
|
|
||||||
|
/* Errors from datastore command */
|
||||||
|
static const errcode_t DATASTORE_DEL_DOES_NOT_EXIST = 1200;
|
||||||
|
static const errcode_t DATASTORE_DEL_WRONG_GENERATION = 1201;
|
||||||
|
static const errcode_t DATASTORE_UPDATE_ALREADY_EXISTS = 1202;
|
||||||
|
static const errcode_t DATASTORE_UPDATE_DOES_NOT_EXIST = 1203;
|
||||||
|
static const errcode_t DATASTORE_UPDATE_WRONG_GENERATION = 1204;
|
||||||
|
|
||||||
/* Errors from wait* commands */
|
/* Errors from wait* commands */
|
||||||
static const errcode_t WAIT_TIMEOUT = 2000;
|
static const errcode_t WAIT_TIMEOUT = 2000;
|
||||||
|
|
||||||
|
|||||||
23
doc/lightning-datastore.7
generated
23
doc/lightning-datastore.7
generated
@@ -3,7 +3,7 @@
|
|||||||
lightning-datastore - Command for storing (plugin) data
|
lightning-datastore - Command for storing (plugin) data
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
|
||||||
\fBdatastore\fR \fIkey\fR [\fIstring\fR] [\fIhex\fR] [\fImode\fR]
|
\fBdatastore\fR \fIkey\fR [\fIstring\fR] [\fIhex\fR] [\fImode\fR] [\fIgeneration\fR]
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
|
|
||||||
@@ -21,6 +21,12 @@ plugin name (e\.g\. \fBsummary.\fR) is recommended\.
|
|||||||
append this to what's already there) or "create-or-append" (append if
|
append this to what's already there) or "create-or-append" (append if
|
||||||
anything is there, otherwise create)\.
|
anything is there, otherwise create)\.
|
||||||
|
|
||||||
|
|
||||||
|
\fIgeneration\fR, if specified, means that the update will fail if the
|
||||||
|
previously-existing data is not exactly that generation\. This allows
|
||||||
|
for simple atomicity\. This is only legal with \fImode\fR "must-replace"
|
||||||
|
or "must-append"\.
|
||||||
|
|
||||||
.SH RETURN VALUE
|
.SH RETURN VALUE
|
||||||
|
|
||||||
On success, an object is returned, containing:
|
On success, an object is returned, containing:
|
||||||
@@ -29,20 +35,25 @@ On success, an object is returned, containing:
|
|||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
\fBkey\fR (string): The key which has been added to the datastore
|
\fBkey\fR (string): The key which has been added to the datastore
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
|
\fBgeneration\fR (u64): The number of times this has been updated
|
||||||
|
.IP \[bu]
|
||||||
\fBhex\fR (hex): The hex data which has been added to the datastore
|
\fBhex\fR (hex): The hex data which has been added to the datastore
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
\fBstring\fR (string, optional): The data as a string, if it's valid utf-8
|
\fBstring\fR (string, optional): The data as a string, if it's valid utf-8
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
The main cause of failure is an already-existing entry\.
|
|
||||||
|
|
||||||
|
|
||||||
The following error codes may occur:
|
The following error codes may occur:
|
||||||
|
|
||||||
.RS
|
.RS
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
-32602: invalid parameters, including already-existing/not-existing key\.
|
1202: The key already exists (and mode said it must not)
|
||||||
|
.IP \[bu]
|
||||||
|
1203: The key does not exist (and mode said it must)
|
||||||
|
.IP \[bu]
|
||||||
|
1204: The generation was wrong (and generation was specified)
|
||||||
|
.IP \[bu]
|
||||||
|
-32602: invalid parameters
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
@@ -57,4 +68,4 @@ Rusty Russell \fI<rusty@rustcorp.com.au\fR> is mainly responsible\.
|
|||||||
|
|
||||||
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
|
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
|
||||||
|
|
||||||
\" SHA256STAMP:4bb1369465ffb76e8e1962bd9e242159e579bb3af6e01c9d1461e519d8721769
|
\" SHA256STAMP:0ef09e6f98d7e34e7d8339351c29ffc70be71fbf9f05f581488e3c7f603d3721
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ lightning-datastore -- Command for storing (plugin) data
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
|
|
||||||
**datastore** *key* [*string*] [*hex*] [*mode*]
|
**datastore** *key* [*string*] [*hex*] [*mode*] [*generation*]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@@ -21,20 +21,27 @@ plugin name (e.g. `summary.`) is recommended.
|
|||||||
append this to what's already there) or "create-or-append" (append if
|
append this to what's already there) or "create-or-append" (append if
|
||||||
anything is there, otherwise create).
|
anything is there, otherwise create).
|
||||||
|
|
||||||
|
*generation*, if specified, means that the update will fail if the
|
||||||
|
previously-existing data is not exactly that generation. This allows
|
||||||
|
for simple atomicity. This is only legal with *mode* "must-replace"
|
||||||
|
or "must-append".
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
------------
|
------------
|
||||||
|
|
||||||
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
||||||
On success, an object is returned, containing:
|
On success, an object is returned, containing:
|
||||||
- **key** (string): The key which has been added to the datastore
|
- **key** (string): The key which has been added to the datastore
|
||||||
|
- **generation** (u64): The number of times this has been updated
|
||||||
- **hex** (hex): The hex data 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
|
- **string** (string, optional): The data as a string, if it's valid utf-8
|
||||||
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
||||||
|
|
||||||
The main cause of failure is an already-existing entry.
|
|
||||||
|
|
||||||
The following error codes may occur:
|
The following error codes may occur:
|
||||||
- -32602: invalid parameters, including already-existing/not-existing key.
|
- 1202: The key already exists (and mode said it must not)
|
||||||
|
- 1203: The key does not exist (and mode said it must)
|
||||||
|
- 1204: The generation was wrong (and generation was specified)
|
||||||
|
- -32602: invalid parameters
|
||||||
|
|
||||||
AUTHOR
|
AUTHOR
|
||||||
------
|
------
|
||||||
@@ -51,4 +58,4 @@ RESOURCES
|
|||||||
|
|
||||||
Main web site: <https://github.com/ElementsProject/lightning>
|
Main web site: <https://github.com/ElementsProject/lightning>
|
||||||
|
|
||||||
[comment]: # ( SHA256STAMP:5eda4592b0a5e893853ea15ce7e800bb94e3a26ebd932507c2a55890f56fee14)
|
[comment]: # ( SHA256STAMP:0867f9910b75ef66e640a92aad55dbab7ce0b3278fd1fb200f91c2a1a6164409)
|
||||||
|
|||||||
18
doc/lightning-deldatastore.7
generated
18
doc/lightning-deldatastore.7
generated
@@ -3,7 +3,7 @@
|
|||||||
lightning-deldatastore - Command for removing (plugin) data
|
lightning-deldatastore - Command for removing (plugin) data
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
|
||||||
\fBdeldatastore\fR \fIkey\fR
|
\fBdeldatastore\fR \fIkey\fR [\fIgeneration\fR]
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
|
|
||||||
@@ -11,7 +11,8 @@ The \fBdeldatastore\fR RPC command allows plugins to delete data it has
|
|||||||
stored in the c-lightning database\.
|
stored in the c-lightning database\.
|
||||||
|
|
||||||
|
|
||||||
The command fails if the \fIkey\fR isn't present\.
|
The command fails if the \fIkey\fR isn't present, or if \fIgeneration\fR
|
||||||
|
is specified and the generation of the data does not exactly match\.
|
||||||
|
|
||||||
.SH RETURN VALUE
|
.SH RETURN VALUE
|
||||||
|
|
||||||
@@ -21,20 +22,23 @@ On success, an object is returned, containing:
|
|||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
\fBkey\fR (string): The key which has been removed from the datastore
|
\fBkey\fR (string): The key which has been removed from the datastore
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
|
\fBgeneration\fR (u64): The number of times this has been updated
|
||||||
|
.IP \[bu]
|
||||||
\fBhex\fR (hex): The hex data which has removed from the datastore
|
\fBhex\fR (hex): The hex data which has removed from the datastore
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
\fBstring\fR (string, optional): The data as a string, if it's valid utf-8
|
\fBstring\fR (string, optional): The data as a string, if it's valid utf-8
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
The main cause of failure is an non-existing entry\.
|
|
||||||
|
|
||||||
|
|
||||||
The following error codes may occur:
|
The following error codes may occur:
|
||||||
|
|
||||||
.RS
|
.RS
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
-32602: invalid parameters, including non-existing key\.
|
1200: the key does not exist
|
||||||
|
.IP \[bu]
|
||||||
|
1201: the key does exist, but the generation is wrong
|
||||||
|
.IP \[bu]
|
||||||
|
-32602: invalid parameters
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
@@ -49,4 +53,4 @@ Rusty Russell \fI<rusty@rustcorp.com.au\fR> is mainly responsible\.
|
|||||||
|
|
||||||
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
|
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
|
||||||
|
|
||||||
\" SHA256STAMP:8e1a383ed176a0b7f8b849bf2bb05f5caaaf0de4f375afd38cbc668f1f17d9a2
|
\" SHA256STAMP:784f58fc76fc32b92d043b67b0b7efb88534dd29a7fabda2d705cdc0611e3c11
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ lightning-deldatastore -- Command for removing (plugin) data
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
|
|
||||||
**deldatastore** *key*
|
**deldatastore** *key* [*generation*]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@@ -12,7 +12,8 @@ DESCRIPTION
|
|||||||
The **deldatastore** RPC command allows plugins to delete data it has
|
The **deldatastore** RPC command allows plugins to delete data it has
|
||||||
stored in the c-lightning database.
|
stored in the c-lightning database.
|
||||||
|
|
||||||
The command fails if the *key* isn't present.
|
The command fails if the *key* isn't present, or if *generation*
|
||||||
|
is specified and the generation of the data does not exactly match.
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
------------
|
------------
|
||||||
@@ -20,14 +21,15 @@ RETURN VALUE
|
|||||||
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
||||||
On success, an object is returned, containing:
|
On success, an object is returned, containing:
|
||||||
- **key** (string): The key which has been removed from the datastore
|
- **key** (string): The key which has been removed from the datastore
|
||||||
|
- **generation** (u64): The number of times this has been updated
|
||||||
- **hex** (hex): The hex data which has 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
|
- **string** (string, optional): The data as a string, if it's valid utf-8
|
||||||
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
||||||
|
|
||||||
The main cause of failure is an non-existing entry.
|
|
||||||
|
|
||||||
The following error codes may occur:
|
The following error codes may occur:
|
||||||
- -32602: invalid parameters, including non-existing key.
|
- 1200: the key does not exist
|
||||||
|
- 1201: the key does exist, but the generation is wrong
|
||||||
|
- -32602: invalid parameters
|
||||||
|
|
||||||
AUTHOR
|
AUTHOR
|
||||||
------
|
------
|
||||||
@@ -44,4 +46,4 @@ RESOURCES
|
|||||||
|
|
||||||
Main web site: <https://github.com/ElementsProject/lightning>
|
Main web site: <https://github.com/ElementsProject/lightning>
|
||||||
|
|
||||||
[comment]: # ( SHA256STAMP:cc1dedfded4902f59879665e95a1a877c8c72c0e217a3db3de3ae8dde859e67a)
|
[comment]: # ( SHA256STAMP:ca2b7b8f45b3ecd6332978599c803e38c4f80945119a777cb8ae346cbf063b10)
|
||||||
|
|||||||
4
doc/lightning-listdatastore.7
generated
4
doc/lightning-listdatastore.7
generated
@@ -22,6 +22,8 @@ On success, an object containing \fBdatastore\fR is returned\. It is an array o
|
|||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
\fBkey\fR (string): The key which from the datastore
|
\fBkey\fR (string): The key which from the datastore
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
|
\fBgeneration\fR (u64): The number of times this has been updated
|
||||||
|
.IP \[bu]
|
||||||
\fBhex\fR (hex): The hex data from the datastore
|
\fBhex\fR (hex): The hex data from the datastore
|
||||||
.IP \[bu]
|
.IP \[bu]
|
||||||
\fBstring\fR (string, optional): The data as a string, if it's valid utf-8
|
\fBstring\fR (string, optional): The data as a string, if it's valid utf-8
|
||||||
@@ -47,4 +49,4 @@ Rusty Russell \fI<rusty@rustcorp.com.au\fR> is mainly responsible\.
|
|||||||
|
|
||||||
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
|
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
|
||||||
|
|
||||||
\" SHA256STAMP:bcc83095fc1695b0c81a2763109e280d711e29edbc395672314d052f9d99a72c
|
\" SHA256STAMP:b4128fc60690b3161eb76295e98f042c7be0142342bffa461c4f50f223c10684
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ RETURN VALUE
|
|||||||
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
||||||
On success, an object containing **datastore** is returned. It is an array of objects, where each object contains:
|
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
|
- **key** (string): The key which from the datastore
|
||||||
|
- **generation** (u64): The number of times this has been updated
|
||||||
- **hex** (hex): The hex data 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
|
- **string** (string, optional): The data as a string, if it's valid utf-8
|
||||||
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
||||||
@@ -43,4 +44,4 @@ RESOURCES
|
|||||||
|
|
||||||
Main web site: <https://github.com/ElementsProject/lightning>
|
Main web site: <https://github.com/ElementsProject/lightning>
|
||||||
|
|
||||||
[comment]: # ( SHA256STAMP:b93d725952e9ac5134dc25711d9bfbbd8b719e8ee8592f27bd1becbb56f89971)
|
[comment]: # ( SHA256STAMP:a6503e3d2da8f9a35a0d461b5b93248f3fea306371ad62f98df613efea51959d)
|
||||||
|
|||||||
@@ -2,12 +2,16 @@
|
|||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [ "key", "hex" ],
|
"required": [ "key", "hex", "generation" ],
|
||||||
"properties": {
|
"properties": {
|
||||||
"key": {
|
"key": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The key which has been added to the datastore"
|
"description": "The key which has been added to the datastore"
|
||||||
},
|
},
|
||||||
|
"generation": {
|
||||||
|
"type": "u64",
|
||||||
|
"description": "The number of times this has been updated"
|
||||||
|
},
|
||||||
"hex": {
|
"hex": {
|
||||||
"type": "hex",
|
"type": "hex",
|
||||||
"description": "The hex data which has been added to the datastore"
|
"description": "The hex data which has been added to the datastore"
|
||||||
|
|||||||
@@ -2,12 +2,16 @@
|
|||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [ "key", "hex" ],
|
"required": [ "key", "hex", "generation" ],
|
||||||
"properties": {
|
"properties": {
|
||||||
"key": {
|
"key": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The key which has been removed from the datastore"
|
"description": "The key which has been removed from the datastore"
|
||||||
},
|
},
|
||||||
|
"generation": {
|
||||||
|
"type": "u64",
|
||||||
|
"description": "The number of times this has been updated"
|
||||||
|
},
|
||||||
"hex": {
|
"hex": {
|
||||||
"type": "hex",
|
"type": "hex",
|
||||||
"description": "The hex data which has removed from the datastore"
|
"description": "The hex data which has removed from the datastore"
|
||||||
|
|||||||
@@ -9,12 +9,16 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [ "key", "hex" ],
|
"required": [ "key", "hex", "generation" ],
|
||||||
"properties": {
|
"properties": {
|
||||||
"key": {
|
"key": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The key which from the datastore"
|
"description": "The key which from the datastore"
|
||||||
},
|
},
|
||||||
|
"generation": {
|
||||||
|
"type": "u64",
|
||||||
|
"description": "The number of times this has been updated"
|
||||||
|
},
|
||||||
"hex": {
|
"hex": {
|
||||||
"type": "hex",
|
"type": "hex",
|
||||||
"description": "The hex data from the datastore"
|
"description": "The hex data from the datastore"
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
#include <wallet/wallet.h>
|
#include <wallet/wallet.h>
|
||||||
|
|
||||||
static void json_add_datastore(struct json_stream *response,
|
static void json_add_datastore(struct json_stream *response,
|
||||||
const char *key, const u8 *data)
|
const char *key, const u8 *data,
|
||||||
|
u64 generation)
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
json_add_string(response, "key", key);
|
json_add_string(response, "key", key);
|
||||||
|
json_add_u64(response, "generation", generation);
|
||||||
json_add_hex(response, "hex", data, tal_bytelen(data));
|
json_add_hex(response, "hex", data, tal_bytelen(data));
|
||||||
str = utf8_str(response, data, tal_bytelen(data));
|
str = utf8_str(response, data, tal_bytelen(data));
|
||||||
if (str)
|
if (str)
|
||||||
@@ -58,12 +60,14 @@ static struct command_result *json_datastore(struct command *cmd,
|
|||||||
const char *key, *strdata;
|
const char *key, *strdata;
|
||||||
u8 *data, *prevdata;
|
u8 *data, *prevdata;
|
||||||
enum ds_mode *mode;
|
enum ds_mode *mode;
|
||||||
|
u64 *generation, actual_gen;
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
if (!param(cmd, buffer, params,
|
||||||
p_req("key", param_string, &key),
|
p_req("key", param_string, &key),
|
||||||
p_opt("string", param_string, &strdata),
|
p_opt("string", param_string, &strdata),
|
||||||
p_opt("hex", param_bin_from_hex, &data),
|
p_opt("hex", param_bin_from_hex, &data),
|
||||||
p_opt_def("mode", param_mode, &mode, DS_MUST_NOT_EXIST),
|
p_opt_def("mode", param_mode, &mode, DS_MUST_NOT_EXIST),
|
||||||
|
p_opt("generation", param_u64, &generation),
|
||||||
NULL))
|
NULL))
|
||||||
return command_param_failed();
|
return command_param_failed();
|
||||||
|
|
||||||
@@ -78,15 +82,25 @@ static struct command_result *json_datastore(struct command *cmd,
|
|||||||
"Must have either hex or string");
|
"Must have either hex or string");
|
||||||
}
|
}
|
||||||
|
|
||||||
prevdata = wallet_datastore_fetch(cmd, cmd->ld->wallet, key);
|
if (generation && !(*mode & DS_MUST_EXIST))
|
||||||
if ((*mode & DS_MUST_NOT_EXIST) && prevdata)
|
|
||||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
|
"generation only valid with must-replace"
|
||||||
|
" or must-append");
|
||||||
|
|
||||||
|
prevdata = wallet_datastore_fetch(cmd, cmd->ld->wallet, key,
|
||||||
|
&actual_gen);
|
||||||
|
if ((*mode & DS_MUST_NOT_EXIST) && prevdata)
|
||||||
|
return command_fail(cmd, DATASTORE_UPDATE_ALREADY_EXISTS,
|
||||||
"Key already exists");
|
"Key already exists");
|
||||||
|
|
||||||
if ((*mode & DS_MUST_EXIST) && !prevdata)
|
if ((*mode & DS_MUST_EXIST) && !prevdata)
|
||||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
return command_fail(cmd, DATASTORE_UPDATE_DOES_NOT_EXIST,
|
||||||
"Key does not exist");
|
"Key does not exist");
|
||||||
|
|
||||||
|
if (generation && actual_gen != *generation)
|
||||||
|
return command_fail(cmd, DATASTORE_UPDATE_WRONG_GENERATION,
|
||||||
|
"generation is different");
|
||||||
|
|
||||||
if ((*mode & DS_APPEND) && prevdata) {
|
if ((*mode & DS_APPEND) && prevdata) {
|
||||||
size_t prevlen = tal_bytelen(prevdata);
|
size_t prevlen = tal_bytelen(prevdata);
|
||||||
tal_resize(&prevdata, prevlen + tal_bytelen(data));
|
tal_resize(&prevdata, prevlen + tal_bytelen(data));
|
||||||
@@ -94,13 +108,16 @@ static struct command_result *json_datastore(struct command *cmd,
|
|||||||
data = prevdata;
|
data = prevdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevdata)
|
if (prevdata) {
|
||||||
wallet_datastore_update(cmd->ld->wallet, key, data);
|
wallet_datastore_update(cmd->ld->wallet, key, data);
|
||||||
else
|
actual_gen++;
|
||||||
|
} else {
|
||||||
wallet_datastore_create(cmd->ld->wallet, key, data);
|
wallet_datastore_create(cmd->ld->wallet, key, data);
|
||||||
|
actual_gen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
response = json_stream_success(cmd);
|
response = json_stream_success(cmd);
|
||||||
json_add_datastore(response, key, data);
|
json_add_datastore(response, key, data, actual_gen);
|
||||||
return command_success(cmd, response);
|
return command_success(cmd, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +129,7 @@ static struct command_result *json_listdatastore(struct command *cmd,
|
|||||||
struct json_stream *response;
|
struct json_stream *response;
|
||||||
const char *key;
|
const char *key;
|
||||||
const u8 *data;
|
const u8 *data;
|
||||||
|
u64 generation;
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
if (!param(cmd, buffer, params,
|
||||||
p_opt("key", param_string, &key),
|
p_opt("key", param_string, &key),
|
||||||
@@ -121,22 +139,24 @@ static struct command_result *json_listdatastore(struct command *cmd,
|
|||||||
response = json_stream_success(cmd);
|
response = json_stream_success(cmd);
|
||||||
json_array_start(response, "datastore");
|
json_array_start(response, "datastore");
|
||||||
if (key) {
|
if (key) {
|
||||||
data = wallet_datastore_fetch(cmd, cmd->ld->wallet, key);
|
data = wallet_datastore_fetch(cmd, cmd->ld->wallet, key,
|
||||||
|
&generation);
|
||||||
if (data) {
|
if (data) {
|
||||||
json_object_start(response, NULL);
|
json_object_start(response, NULL);
|
||||||
json_add_datastore(response, key, data);
|
json_add_datastore(response, key, data, generation);
|
||||||
json_object_end(response);
|
json_object_end(response);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct db_stmt *stmt;
|
struct db_stmt *stmt;
|
||||||
|
|
||||||
for (stmt = wallet_datastore_first(cmd, cmd->ld->wallet,
|
for (stmt = wallet_datastore_first(cmd, cmd->ld->wallet,
|
||||||
&key, &data);
|
&key, &data, &generation);
|
||||||
stmt;
|
stmt;
|
||||||
stmt = wallet_datastore_next(cmd, cmd->ld->wallet,
|
stmt = wallet_datastore_next(cmd, cmd->ld->wallet,
|
||||||
stmt, &key, &data)) {
|
stmt, &key, &data,
|
||||||
|
&generation)) {
|
||||||
json_object_start(response, NULL);
|
json_object_start(response, NULL);
|
||||||
json_add_datastore(response, key, data);
|
json_add_datastore(response, key, data, generation);
|
||||||
json_object_end(response);
|
json_object_end(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,19 +172,29 @@ static struct command_result *json_deldatastore(struct command *cmd,
|
|||||||
struct json_stream *response;
|
struct json_stream *response;
|
||||||
const char *key;
|
const char *key;
|
||||||
u8 *data;
|
u8 *data;
|
||||||
|
u64 *generation;
|
||||||
|
u64 actual_gen;
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
if (!param(cmd, buffer, params,
|
||||||
p_req("key", param_string, &key),
|
p_req("key", param_string, &key),
|
||||||
|
p_opt("generation", param_u64, &generation),
|
||||||
NULL))
|
NULL))
|
||||||
return command_param_failed();
|
return command_param_failed();
|
||||||
|
|
||||||
data = wallet_datastore_remove(cmd, cmd->ld->wallet, key);
|
if (generation) {
|
||||||
|
data = wallet_datastore_fetch(cmd, cmd->ld->wallet, key,
|
||||||
|
&actual_gen);
|
||||||
|
if (data && actual_gen != *generation)
|
||||||
|
return command_fail(cmd, DATASTORE_DEL_WRONG_GENERATION,
|
||||||
|
"generation is different");
|
||||||
|
}
|
||||||
|
data = wallet_datastore_remove(cmd, cmd->ld->wallet, key, &actual_gen);
|
||||||
if (!data)
|
if (!data)
|
||||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
return command_fail(cmd, DATASTORE_DEL_DOES_NOT_EXIST,
|
||||||
"Key does not exist");
|
"Key does not exist");
|
||||||
|
|
||||||
response = json_stream_success(cmd);
|
response = json_stream_success(cmd);
|
||||||
json_add_datastore(response, key, data);
|
json_add_datastore(response, key, data, actual_gen);
|
||||||
return command_success(cmd, response);
|
return command_success(cmd, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2636,6 +2636,7 @@ def test_datastore(node_factory):
|
|||||||
# Add entries.
|
# Add entries.
|
||||||
somedata = b'somedata'.hex()
|
somedata = b'somedata'.hex()
|
||||||
somedata_expect = {'key': 'somekey',
|
somedata_expect = {'key': 'somekey',
|
||||||
|
'generation': 0,
|
||||||
'hex': somedata,
|
'hex': somedata,
|
||||||
'string': 'somedata'}
|
'string': 'somedata'}
|
||||||
assert l1.rpc.datastore(key='somekey', hex=somedata) == somedata_expect
|
assert l1.rpc.datastore(key='somekey', hex=somedata) == somedata_expect
|
||||||
@@ -2660,6 +2661,10 @@ def test_datastore(node_factory):
|
|||||||
l1.rpc.datastore(key='somekey', hex=somedata[-2:], mode="create-or-append")
|
l1.rpc.datastore(key='somekey', hex=somedata[-2:], mode="create-or-append")
|
||||||
assert only_one(l1.rpc.listdatastore('somekey')['datastore'])['hex'] == somedata
|
assert only_one(l1.rpc.listdatastore('somekey')['datastore'])['hex'] == somedata
|
||||||
|
|
||||||
|
# Generation will have increased due to three ops above.
|
||||||
|
somedata_expect['generation'] += 3
|
||||||
|
assert l1.rpc.listdatastore() == {'datastore': [somedata_expect]}
|
||||||
|
|
||||||
# Can't replace or append non-existing records if we say not to
|
# Can't replace or append non-existing records if we say not to
|
||||||
with pytest.raises(RpcError, match='does not exist'):
|
with pytest.raises(RpcError, match='does not exist'):
|
||||||
l1.rpc.datastore(key='otherkey', hex=somedata, mode="must-replace")
|
l1.rpc.datastore(key='otherkey', hex=somedata, mode="must-replace")
|
||||||
@@ -2669,6 +2674,7 @@ def test_datastore(node_factory):
|
|||||||
|
|
||||||
otherdata = b'otherdata'.hex()
|
otherdata = b'otherdata'.hex()
|
||||||
otherdata_expect = {'key': 'otherkey',
|
otherdata_expect = {'key': 'otherkey',
|
||||||
|
'generation': 0,
|
||||||
'hex': otherdata,
|
'hex': otherdata,
|
||||||
'string': 'otherdata'}
|
'string': 'otherdata'}
|
||||||
assert l1.rpc.datastore(key='otherkey', string='otherdata', mode="create-or-append") == otherdata_expect
|
assert l1.rpc.datastore(key='otherkey', string='otherdata', mode="create-or-append") == otherdata_expect
|
||||||
@@ -2691,6 +2697,7 @@ def test_datastore(node_factory):
|
|||||||
|
|
||||||
# if it's not a string, won't print
|
# if it's not a string, won't print
|
||||||
badstring_expect = {'key': 'badstring',
|
badstring_expect = {'key': 'badstring',
|
||||||
|
'generation': 0,
|
||||||
'hex': '00'}
|
'hex': '00'}
|
||||||
assert l1.rpc.datastore(key='badstring', hex='00') == badstring_expect
|
assert l1.rpc.datastore(key='badstring', hex='00') == badstring_expect
|
||||||
assert l1.rpc.listdatastore('badstring') == {'datastore': [badstring_expect]}
|
assert l1.rpc.listdatastore('badstring') == {'datastore': [badstring_expect]}
|
||||||
@@ -2700,3 +2707,27 @@ def test_datastore(node_factory):
|
|||||||
l1.restart()
|
l1.restart()
|
||||||
|
|
||||||
assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]}
|
assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]}
|
||||||
|
|
||||||
|
# We can insist generation match on update.
|
||||||
|
with pytest.raises(RpcError, match='generation is different'):
|
||||||
|
l1.rpc.datastore(key='otherkey', hex='00', mode='must-replace',
|
||||||
|
generation=otherdata_expect['generation'] + 1)
|
||||||
|
|
||||||
|
otherdata_expect['generation'] += 1
|
||||||
|
otherdata_expect['string'] += 'a'
|
||||||
|
otherdata_expect['hex'] += '61'
|
||||||
|
assert (l1.rpc.datastore(key='otherkey', string='otherdataa',
|
||||||
|
mode='must-replace',
|
||||||
|
generation=otherdata_expect['generation'] - 1)
|
||||||
|
== otherdata_expect)
|
||||||
|
assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]}
|
||||||
|
|
||||||
|
# We can insist generation match on delete.
|
||||||
|
with pytest.raises(RpcError, match='generation is different'):
|
||||||
|
l1.rpc.deldatastore(key='otherkey',
|
||||||
|
generation=otherdata_expect['generation'] + 1)
|
||||||
|
|
||||||
|
assert (l1.rpc.deldatastore(key='otherkey',
|
||||||
|
generation=otherdata_expect['generation'])
|
||||||
|
== otherdata_expect)
|
||||||
|
assert l1.rpc.listdatastore() == {'datastore': []}
|
||||||
|
|||||||
@@ -752,6 +752,7 @@ static struct migration dbmigrations[] = {
|
|||||||
{SQL("CREATE TABLE datastore ("
|
{SQL("CREATE TABLE datastore ("
|
||||||
" key TEXT,"
|
" key TEXT,"
|
||||||
" data BLOB,"
|
" data BLOB,"
|
||||||
|
" generation BIGINT,"
|
||||||
" PRIMARY KEY (key)"
|
" PRIMARY KEY (key)"
|
||||||
");"),
|
");"),
|
||||||
NULL},
|
NULL},
|
||||||
|
|||||||
22
wallet/db_postgres_sqlgen.c
generated
22
wallet/db_postgres_sqlgen.c
generated
@@ -1023,8 +1023,8 @@ struct db_query db_postgres_queries[] = {
|
|||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "CREATE TABLE datastore ( key TEXT, data BLOB, PRIMARY KEY (key));",
|
.name = "CREATE TABLE datastore ( key TEXT, data BLOB, generation BIGINT, PRIMARY KEY (key));",
|
||||||
.query = "CREATE TABLE datastore ( key TEXT, data BYTEA, PRIMARY KEY (key));",
|
.query = "CREATE TABLE datastore ( key TEXT, data BYTEA, generation BIGINT, PRIMARY KEY (key));",
|
||||||
.placeholders = 0,
|
.placeholders = 0,
|
||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
@@ -2007,14 +2007,14 @@ struct db_query db_postgres_queries[] = {
|
|||||||
.readonly = true,
|
.readonly = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "UPDATE datastore SET data=? WHERE key=?;",
|
.name = "UPDATE datastore SET data=?, generation=generation+1 WHERE key=?;",
|
||||||
.query = "UPDATE datastore SET data=$1 WHERE key=$2;",
|
.query = "UPDATE datastore SET data=$1, generation=generation+1 WHERE key=$2;",
|
||||||
.placeholders = 2,
|
.placeholders = 2,
|
||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "INSERT INTO datastore VALUES (?, ?);",
|
.name = "INSERT INTO datastore VALUES (?, ?, 0);",
|
||||||
.query = "INSERT INTO datastore VALUES ($1, $2);",
|
.query = "INSERT INTO datastore VALUES ($1, $2, 0);",
|
||||||
.placeholders = 2,
|
.placeholders = 2,
|
||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
@@ -2025,14 +2025,14 @@ struct db_query db_postgres_queries[] = {
|
|||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "SELECT data FROM datastore WHERE key = ?;",
|
.name = "SELECT data, generation FROM datastore WHERE key = ?;",
|
||||||
.query = "SELECT data FROM datastore WHERE key = $1;",
|
.query = "SELECT data, generation FROM datastore WHERE key = $1;",
|
||||||
.placeholders = 1,
|
.placeholders = 1,
|
||||||
.readonly = true,
|
.readonly = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "SELECT key, data FROM datastore;",
|
.name = "SELECT key, data, generation FROM datastore;",
|
||||||
.query = "SELECT key, data FROM datastore;",
|
.query = "SELECT key, data, generation FROM datastore;",
|
||||||
.placeholders = 0,
|
.placeholders = 0,
|
||||||
.readonly = true,
|
.readonly = true,
|
||||||
},
|
},
|
||||||
@@ -2068,4 +2068,4 @@ struct db_query db_postgres_queries[] = {
|
|||||||
|
|
||||||
#endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */
|
#endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */
|
||||||
|
|
||||||
// SHA256STAMP:5b2863e970ee24f2552e45224fed3f248badc9fd87ee3ab3ff0458fe3bcc0a83
|
// SHA256STAMP:247577c68e8e536ee1736ddce425efb58ff609c1d3d4fbb1148b5c65b8922741
|
||||||
|
|||||||
22
wallet/db_sqlite3_sqlgen.c
generated
22
wallet/db_sqlite3_sqlgen.c
generated
@@ -1023,8 +1023,8 @@ struct db_query db_sqlite3_queries[] = {
|
|||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "CREATE TABLE datastore ( key TEXT, data BLOB, PRIMARY KEY (key));",
|
.name = "CREATE TABLE datastore ( key TEXT, data BLOB, generation BIGINT, PRIMARY KEY (key));",
|
||||||
.query = "CREATE TABLE datastore ( key TEXT, data BLOB, PRIMARY KEY (key));",
|
.query = "CREATE TABLE datastore ( key TEXT, data BLOB, generation INTEGER, PRIMARY KEY (key));",
|
||||||
.placeholders = 0,
|
.placeholders = 0,
|
||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
@@ -2007,14 +2007,14 @@ struct db_query db_sqlite3_queries[] = {
|
|||||||
.readonly = true,
|
.readonly = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "UPDATE datastore SET data=? WHERE key=?;",
|
.name = "UPDATE datastore SET data=?, generation=generation+1 WHERE key=?;",
|
||||||
.query = "UPDATE datastore SET data=? WHERE key=?;",
|
.query = "UPDATE datastore SET data=?, generation=generation+1 WHERE key=?;",
|
||||||
.placeholders = 2,
|
.placeholders = 2,
|
||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "INSERT INTO datastore VALUES (?, ?);",
|
.name = "INSERT INTO datastore VALUES (?, ?, 0);",
|
||||||
.query = "INSERT INTO datastore VALUES (?, ?);",
|
.query = "INSERT INTO datastore VALUES (?, ?, 0);",
|
||||||
.placeholders = 2,
|
.placeholders = 2,
|
||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
@@ -2025,14 +2025,14 @@ struct db_query db_sqlite3_queries[] = {
|
|||||||
.readonly = false,
|
.readonly = false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "SELECT data FROM datastore WHERE key = ?;",
|
.name = "SELECT data, generation FROM datastore WHERE key = ?;",
|
||||||
.query = "SELECT data FROM datastore WHERE key = ?;",
|
.query = "SELECT data, generation FROM datastore WHERE key = ?;",
|
||||||
.placeholders = 1,
|
.placeholders = 1,
|
||||||
.readonly = true,
|
.readonly = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "SELECT key, data FROM datastore;",
|
.name = "SELECT key, data, generation FROM datastore;",
|
||||||
.query = "SELECT key, data FROM datastore;",
|
.query = "SELECT key, data, generation FROM datastore;",
|
||||||
.placeholders = 0,
|
.placeholders = 0,
|
||||||
.readonly = true,
|
.readonly = true,
|
||||||
},
|
},
|
||||||
@@ -2068,4 +2068,4 @@ struct db_query db_sqlite3_queries[] = {
|
|||||||
|
|
||||||
#endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */
|
#endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */
|
||||||
|
|
||||||
// SHA256STAMP:5b2863e970ee24f2552e45224fed3f248badc9fd87ee3ab3ff0458fe3bcc0a83
|
// SHA256STAMP:247577c68e8e536ee1736ddce425efb58ff609c1d3d4fbb1148b5c65b8922741
|
||||||
|
|||||||
62
wallet/statements_gettextgen.po
generated
62
wallet/statements_gettextgen.po
generated
@@ -675,94 +675,94 @@ msgid "ALTER TABLE outputs ADD csv_lock INTEGER DEFAULT 1;"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:752
|
#: wallet/db.c:752
|
||||||
msgid "CREATE TABLE datastore ( key TEXT, data BLOB, PRIMARY KEY (key));"
|
msgid "CREATE TABLE datastore ( key TEXT, data BLOB, generation BIGINT, PRIMARY KEY (key));"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:984
|
#: wallet/db.c:985
|
||||||
msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?"
|
msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1084
|
#: wallet/db.c:1085
|
||||||
msgid "SELECT version FROM version LIMIT 1"
|
msgid "SELECT version FROM version LIMIT 1"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1146
|
#: wallet/db.c:1147
|
||||||
msgid "UPDATE version SET version=?;"
|
msgid "UPDATE version SET version=?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1154
|
#: wallet/db.c:1155
|
||||||
msgid "INSERT INTO db_upgrades VALUES (?, ?);"
|
msgid "INSERT INTO db_upgrades VALUES (?, ?);"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1166
|
#: wallet/db.c:1167
|
||||||
msgid "SELECT intval FROM vars WHERE name = 'data_version'"
|
msgid "SELECT intval FROM vars WHERE name = 'data_version'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1193
|
#: wallet/db.c:1194
|
||||||
msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1"
|
msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1209
|
#: wallet/db.c:1210
|
||||||
msgid "UPDATE vars SET intval=? WHERE name=?;"
|
msgid "UPDATE vars SET intval=? WHERE name=?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1218
|
#: wallet/db.c:1219
|
||||||
msgid "INSERT INTO vars (name, intval) VALUES (?, ?);"
|
msgid "INSERT INTO vars (name, intval) VALUES (?, ?);"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1232
|
#: wallet/db.c:1233
|
||||||
msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;"
|
msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1253
|
#: wallet/db.c:1254
|
||||||
msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;"
|
msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1269
|
#: wallet/db.c:1270
|
||||||
msgid "SELECT type, keyindex, prev_out_tx, prev_out_index, channel_id, peer_id, commitment_point FROM outputs WHERE scriptpubkey IS NULL;"
|
msgid "SELECT type, keyindex, prev_out_tx, prev_out_index, channel_id, peer_id, commitment_point FROM outputs WHERE scriptpubkey IS NULL;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1331
|
#: wallet/db.c:1332
|
||||||
msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?"
|
msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1356
|
#: wallet/db.c:1357
|
||||||
msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;"
|
msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1375
|
#: wallet/db.c:1376
|
||||||
msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;"
|
msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1396
|
#: wallet/db.c:1397
|
||||||
msgid "SELECT channels.id, peers.node_id FROM channels JOIN peers ON (peers.id = channels.peer_id)"
|
msgid "SELECT channels.id, peers.node_id FROM channels JOIN peers ON (peers.id = channels.peer_id)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1429
|
#: wallet/db.c:1430
|
||||||
msgid "UPDATE channels SET revocation_basepoint_local = ?, payment_basepoint_local = ?, htlc_basepoint_local = ?, delayed_payment_basepoint_local = ?, funding_pubkey_local = ? WHERE id = ?;"
|
msgid "UPDATE channels SET revocation_basepoint_local = ?, payment_basepoint_local = ?, htlc_basepoint_local = ?, delayed_payment_basepoint_local = ?, funding_pubkey_local = ? WHERE id = ?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1462
|
#: wallet/db.c:1463
|
||||||
msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;"
|
msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1470
|
#: wallet/db.c:1471
|
||||||
msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;"
|
msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1482
|
#: wallet/db.c:1483
|
||||||
msgid "SELECT c.id, p.node_id, c.fundingkey_remote, inflight.last_tx, inflight.last_sig, inflight.funding_satoshi, inflight.funding_tx_id FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id LEFT OUTER JOIN channel_funding_inflights inflight ON c.id = inflight.channel_id WHERE inflight.last_tx IS NOT NULL;"
|
msgid "SELECT c.id, p.node_id, c.fundingkey_remote, inflight.last_tx, inflight.last_sig, inflight.funding_satoshi, inflight.funding_tx_id FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id LEFT OUTER JOIN channel_funding_inflights inflight ON c.id = inflight.channel_id WHERE inflight.last_tx IS NOT NULL;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1549
|
#: wallet/db.c:1550
|
||||||
msgid "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;"
|
msgid "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1573
|
#: wallet/db.c:1574
|
||||||
msgid "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;"
|
msgid "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/db.c:1640
|
#: wallet/db.c:1641
|
||||||
msgid "UPDATE channels SET last_tx = ? WHERE id = ?;"
|
msgid "UPDATE channels SET last_tx = ? WHERE id = ?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1331,23 +1331,23 @@ msgid "SELECT status FROM offers WHERE offer_id = ?;"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/wallet.c:4746
|
#: wallet/wallet.c:4746
|
||||||
msgid "UPDATE datastore SET data=? WHERE key=?;"
|
msgid "UPDATE datastore SET data=?, generation=generation+1 WHERE key=?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/wallet.c:4757
|
#: wallet/wallet.c:4757
|
||||||
msgid "INSERT INTO datastore VALUES (?, ?);"
|
msgid "INSERT INTO datastore VALUES (?, ?, 0);"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/wallet.c:4770
|
#: wallet/wallet.c:4771
|
||||||
msgid "DELETE FROM datastore WHERE key = ?"
|
msgid "DELETE FROM datastore WHERE key = ?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/wallet.c:4785
|
#: wallet/wallet.c:4787
|
||||||
msgid "SELECT data FROM datastore WHERE key = ?;"
|
msgid "SELECT data, generation FROM datastore WHERE key = ?;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/wallet.c:4806
|
#: wallet/wallet.c:4812
|
||||||
msgid "SELECT key, data FROM datastore;"
|
msgid "SELECT key, data, generation FROM datastore;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: wallet/test/run-db.c:126
|
#: wallet/test/run-db.c:126
|
||||||
@@ -1365,4 +1365,4 @@ msgstr ""
|
|||||||
#: wallet/test/run-wallet.c:1753
|
#: wallet/test/run-wallet.c:1753
|
||||||
msgid "INSERT INTO channels (id) VALUES (1);"
|
msgid "INSERT INTO channels (id) VALUES (1);"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
# SHA256STAMP:33c97b729f031ff86abf939de5571a7e5a9cf3d0795bf975189d90ace76d28a1
|
# SHA256STAMP:f68886ac022d1170ef8a4e137a6f4fedea23a7cd06a735418e5f635bb4224a58
|
||||||
|
|||||||
@@ -4743,7 +4743,7 @@ void wallet_datastore_update(struct wallet *w, const char *key, const u8 *data)
|
|||||||
struct db_stmt *stmt;
|
struct db_stmt *stmt;
|
||||||
|
|
||||||
stmt = db_prepare_v2(w->db,
|
stmt = db_prepare_v2(w->db,
|
||||||
SQL("UPDATE datastore SET data=? WHERE key=?;"));
|
SQL("UPDATE datastore SET data=?, generation=generation+1 WHERE key=?;"));
|
||||||
db_bind_talarr(stmt, 0, data);
|
db_bind_talarr(stmt, 0, data);
|
||||||
db_bind_text(stmt, 1, key);
|
db_bind_text(stmt, 1, key);
|
||||||
db_exec_prepared_v2(take(stmt));
|
db_exec_prepared_v2(take(stmt));
|
||||||
@@ -4754,16 +4754,17 @@ void wallet_datastore_create(struct wallet *w, const char *key, const u8 *data)
|
|||||||
struct db_stmt *stmt;
|
struct db_stmt *stmt;
|
||||||
|
|
||||||
stmt = db_prepare_v2(w->db,
|
stmt = db_prepare_v2(w->db,
|
||||||
SQL("INSERT INTO datastore VALUES (?, ?);"));
|
SQL("INSERT INTO datastore VALUES (?, ?, 0);"));
|
||||||
|
|
||||||
db_bind_text(stmt, 0, key);
|
db_bind_text(stmt, 0, key);
|
||||||
db_bind_talarr(stmt, 1, data);
|
db_bind_talarr(stmt, 1, data);
|
||||||
db_exec_prepared_v2(take(stmt));
|
db_exec_prepared_v2(take(stmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *wallet_datastore_remove(const tal_t *ctx, struct wallet *w, const char *key)
|
u8 *wallet_datastore_remove(const tal_t *ctx, struct wallet *w, const char *key,
|
||||||
|
u64 *generation)
|
||||||
{
|
{
|
||||||
u8 *data = wallet_datastore_fetch(ctx, w, key);
|
u8 *data = wallet_datastore_fetch(ctx, w, key, generation);
|
||||||
if (data) {
|
if (data) {
|
||||||
struct db_stmt *stmt;
|
struct db_stmt *stmt;
|
||||||
|
|
||||||
@@ -4776,21 +4777,24 @@ u8 *wallet_datastore_remove(const tal_t *ctx, struct wallet *w, const char *key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
u8 *wallet_datastore_fetch(const tal_t *ctx,
|
u8 *wallet_datastore_fetch(const tal_t *ctx,
|
||||||
struct wallet *w, const char *key)
|
struct wallet *w, const char *key,
|
||||||
|
u64 *generation)
|
||||||
{
|
{
|
||||||
struct db_stmt *stmt;
|
struct db_stmt *stmt;
|
||||||
u8 *data;
|
u8 *data;
|
||||||
|
|
||||||
/* Test if already exists. */
|
/* Test if already exists. */
|
||||||
stmt = db_prepare_v2(w->db, SQL("SELECT data"
|
stmt = db_prepare_v2(w->db, SQL("SELECT data, generation"
|
||||||
" FROM datastore"
|
" FROM datastore"
|
||||||
" WHERE key = ?;"));
|
" WHERE key = ?;"));
|
||||||
db_bind_text(stmt, 0, key);
|
db_bind_text(stmt, 0, key);
|
||||||
db_query_prepared(stmt);
|
db_query_prepared(stmt);
|
||||||
|
|
||||||
if (db_step(stmt))
|
if (db_step(stmt)) {
|
||||||
data = db_column_talarr(ctx, stmt, 0);
|
data = db_column_talarr(ctx, stmt, 0);
|
||||||
else
|
if (generation)
|
||||||
|
*generation = db_column_u64(stmt, 1);
|
||||||
|
} else
|
||||||
data = NULL;
|
data = NULL;
|
||||||
tal_free(stmt);
|
tal_free(stmt);
|
||||||
return data;
|
return data;
|
||||||
@@ -4799,27 +4803,31 @@ u8 *wallet_datastore_fetch(const tal_t *ctx,
|
|||||||
struct db_stmt *wallet_datastore_first(const tal_t *ctx,
|
struct db_stmt *wallet_datastore_first(const tal_t *ctx,
|
||||||
struct wallet *w,
|
struct wallet *w,
|
||||||
const char **key,
|
const char **key,
|
||||||
const u8 **data)
|
const u8 **data,
|
||||||
|
u64 *generation)
|
||||||
{
|
{
|
||||||
struct db_stmt *stmt;
|
struct db_stmt *stmt;
|
||||||
|
|
||||||
stmt = db_prepare_v2(w->db, SQL("SELECT key, data FROM datastore;"));
|
stmt = db_prepare_v2(w->db,
|
||||||
|
SQL("SELECT key, data, generation FROM datastore;"));
|
||||||
db_query_prepared(stmt);
|
db_query_prepared(stmt);
|
||||||
|
|
||||||
return wallet_datastore_next(ctx, w, stmt, key, data);
|
return wallet_datastore_next(ctx, w, stmt, key, data, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct db_stmt *wallet_datastore_next(const tal_t *ctx,
|
struct db_stmt *wallet_datastore_next(const tal_t *ctx,
|
||||||
struct wallet *w,
|
struct wallet *w,
|
||||||
struct db_stmt *stmt,
|
struct db_stmt *stmt,
|
||||||
const char **key,
|
const char **key,
|
||||||
const u8 **data)
|
const u8 **data,
|
||||||
|
u64 *generation)
|
||||||
{
|
{
|
||||||
if (!db_step(stmt))
|
if (!db_step(stmt))
|
||||||
return tal_free(stmt);
|
return tal_free(stmt);
|
||||||
|
|
||||||
*key = tal_strdup(ctx, (const char *)db_column_text(stmt, 0));
|
*key = tal_strdup(ctx, (const char *)db_column_text(stmt, 0));
|
||||||
*data = db_column_talarr(ctx, stmt, 1);
|
*data = db_column_talarr(ctx, stmt, 1);
|
||||||
|
*generation = db_column_u64(stmt, 2);
|
||||||
|
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1531,7 +1531,7 @@ void wallet_offer_mark_used(struct db *db, const struct sha256 *offer_id)
|
|||||||
NO_NULL_ARGS;
|
NO_NULL_ARGS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an new key/value to the datastore.
|
* Add an new key/value to the datastore (generation 0)
|
||||||
* @w: the wallet
|
* @w: the wallet
|
||||||
* @key: the first key (if returns non-NULL)
|
* @key: the first key (if returns non-NULL)
|
||||||
* @data: the first data (if returns non-NULL)
|
* @data: the first data (if returns non-NULL)
|
||||||
@@ -1551,21 +1551,25 @@ void wallet_datastore_update(struct wallet *w, const char *key, const u8 *data);
|
|||||||
* @ctx: the tal ctx to allocate return off
|
* @ctx: the tal ctx to allocate return off
|
||||||
* @w: the wallet
|
* @w: the wallet
|
||||||
* @key: the key
|
* @key: the key
|
||||||
|
* @generation: the generation of deleted record
|
||||||
*
|
*
|
||||||
* Returns NULL if the key was not in the store.
|
* Returns NULL if the key was not in the store.
|
||||||
*/
|
*/
|
||||||
u8 *wallet_datastore_remove(const tal_t *ctx, struct wallet *w, const char *key);
|
u8 *wallet_datastore_remove(const tal_t *ctx, struct wallet *w, const char *key,
|
||||||
|
u64 *generation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retreive a value from the datastore.
|
* Retrieve a value from the datastore.
|
||||||
* @ctx: the tal ctx to allocate return off
|
* @ctx: the tal ctx to allocate return off
|
||||||
* @w: the wallet
|
* @w: the wallet
|
||||||
* @key: the first key (if returns non-NULL)
|
* @key: the first key (if returns non-NULL)
|
||||||
|
* @generation: the generation (if returns non-NULL), or NULL.
|
||||||
*
|
*
|
||||||
* Returns NULL if the key is not in the store.
|
* Returns NULL if the key is not in the store.
|
||||||
*/
|
*/
|
||||||
u8 *wallet_datastore_fetch(const tal_t *ctx,
|
u8 *wallet_datastore_fetch(const tal_t *ctx,
|
||||||
struct wallet *w, const char *key);
|
struct wallet *w, const char *key,
|
||||||
|
u64 *generation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate through the datastore.
|
* Iterate through the datastore.
|
||||||
@@ -1573,6 +1577,7 @@ u8 *wallet_datastore_fetch(const tal_t *ctx,
|
|||||||
* @w: the wallet
|
* @w: the wallet
|
||||||
* @key: the first key (if returns non-NULL)
|
* @key: the first key (if returns non-NULL)
|
||||||
* @data: the first data (if returns non-NULL)
|
* @data: the first data (if returns non-NULL)
|
||||||
|
* @generation: the first generation (if returns non-NULL)
|
||||||
*
|
*
|
||||||
* Returns pointer to hand as @stmt to wallet_datastore_next(), or NULL.
|
* Returns pointer to hand as @stmt to wallet_datastore_next(), or NULL.
|
||||||
* If you choose not to call wallet_datastore_next() you must free it!
|
* If you choose not to call wallet_datastore_next() you must free it!
|
||||||
@@ -1580,15 +1585,17 @@ u8 *wallet_datastore_fetch(const tal_t *ctx,
|
|||||||
struct db_stmt *wallet_datastore_first(const tal_t *ctx,
|
struct db_stmt *wallet_datastore_first(const tal_t *ctx,
|
||||||
struct wallet *w,
|
struct wallet *w,
|
||||||
const char **key,
|
const char **key,
|
||||||
const u8 **data);
|
const u8 **data,
|
||||||
|
u64 *generation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate through the datastore.
|
* Iterate through the datastore.
|
||||||
* @ctx: the tal ctx to allocate off
|
* @ctx: the tal ctx to allocate off
|
||||||
* @w: the wallet
|
* @w: the wallet
|
||||||
* @stmt: the previous statement.
|
* @stmt: the previous statement.
|
||||||
* @key: the first key (if returns non-NULL)
|
* @key: the key (if returns non-NULL)
|
||||||
* @data: the first data (if returns non-NULL)
|
* @data: the data (if returns non-NULL)
|
||||||
|
* @generation: the generation (if returns non-NULL)
|
||||||
*
|
*
|
||||||
* Returns pointer to hand as @stmt to wallet_datastore_next(), or NULL.
|
* Returns pointer to hand as @stmt to wallet_datastore_next(), or NULL.
|
||||||
* If you choose not to call wallet_datastore_next() you must free it!
|
* If you choose not to call wallet_datastore_next() you must free it!
|
||||||
@@ -1597,6 +1604,7 @@ struct db_stmt *wallet_datastore_next(const tal_t *ctx,
|
|||||||
struct wallet *w,
|
struct wallet *w,
|
||||||
struct db_stmt *stmt,
|
struct db_stmt *stmt,
|
||||||
const char **key,
|
const char **key,
|
||||||
const u8 **data);
|
const u8 **data,
|
||||||
|
u64 *generation);
|
||||||
|
|
||||||
#endif /* LIGHTNING_WALLET_WALLET_H */
|
#endif /* LIGHTNING_WALLET_WALLET_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user