Skip to content

Commit 2a066b9

Browse files
committed
wallet: separate datastore access functions for the lightning-downgrade tool to access.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 9981e23 commit 2a066b9

File tree

8 files changed

+249
-164
lines changed

8 files changed

+249
-164
lines changed

wallet/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
WALLET_LIB_SRC := \
44
wallet/account_migration.c \
5+
wallet/datastore.c \
56
wallet/db.c \
67
wallet/invoices.c \
78
wallet/migrations.c \
@@ -34,6 +35,7 @@ WALLET_SQL_FILES := \
3435
$(DB_SQL_FILES) \
3536
wallet/account_migration.c \
3637
wallet/db.c \
38+
wallet/datastore.c \
3739
wallet/invoices.c \
3840
wallet/migrations.c \
3941
wallet/wallet.c \

wallet/datastore.c

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#include "config.h"
2+
#include <ccan/cast/cast.h>
3+
#include <ccan/str/str.h>
4+
#include <ccan/tal/str/str.h>
5+
#include <db/bindings.h>
6+
#include <db/common.h>
7+
#include <db/utils.h>
8+
#include <wallet/datastore.h>
9+
#include <wallet/db.h>
10+
11+
/* Does k1 match k2 as far as k2 goes? */
12+
bool datastore_key_startswith(const char **k1, const char **k2)
13+
{
14+
size_t k1len = tal_count(k1), k2len = tal_count(k2);
15+
16+
if (k2len > k1len)
17+
return false;
18+
19+
for (size_t i = 0; i < k2len; i++) {
20+
if (!streq(k1[i], k2[i]))
21+
return false;
22+
}
23+
return true;
24+
}
25+
26+
bool datastore_key_eq(const char **k1, const char **k2)
27+
{
28+
return tal_count(k1) == tal_count(k2)
29+
&& datastore_key_startswith(k1, k2);
30+
}
31+
32+
/* We join key parts with nuls for now. */
33+
void db_bind_datastore_key(struct db_stmt *stmt, const char **key)
34+
{
35+
u8 *joined;
36+
size_t len;
37+
38+
if (tal_count(key) == 1) {
39+
db_bind_blob(stmt, (u8 *)key[0], strlen(key[0]));
40+
return;
41+
}
42+
43+
len = strlen(key[0]);
44+
joined = (u8 *)tal_strdup(tmpctx, key[0]);
45+
for (size_t i = 1; i < tal_count(key); i++) {
46+
tal_resize(&joined, len + 1 + strlen(key[i]));
47+
joined[len] = '\0';
48+
memcpy(joined + len + 1, key[i], strlen(key[i]));
49+
len += 1 + strlen(key[i]);
50+
}
51+
db_bind_blob(stmt, joined, len);
52+
}
53+
54+
u8 *db_datastore_get(const tal_t *ctx,
55+
struct db *db,
56+
const char **key,
57+
u64 *generation)
58+
{
59+
struct db_stmt *stmt;
60+
u8 *ret;
61+
62+
stmt = db_prepare_v2(db,
63+
SQL("SELECT data, generation"
64+
" FROM datastore"
65+
" WHERE key = ?"));
66+
db_bind_datastore_key(stmt, key);
67+
db_query_prepared(stmt);
68+
69+
if (!db_step(stmt)) {
70+
tal_free(stmt);
71+
return NULL;
72+
}
73+
74+
ret = db_col_arr(ctx, stmt, "data", u8);
75+
if (generation)
76+
*generation = db_col_u64(stmt, "generation");
77+
else
78+
db_col_ignore(stmt, "generation");
79+
tal_free(stmt);
80+
return ret;
81+
}
82+
83+
static const char **db_col_datastore_key(const tal_t *ctx,
84+
struct db_stmt *stmt,
85+
const char *colname)
86+
{
87+
char **key;
88+
const u8 *joined = db_col_blob(stmt, colname);
89+
size_t len = db_col_bytes(stmt, colname);
90+
91+
key = tal_arr(ctx, char *, 0);
92+
do {
93+
size_t partlen;
94+
for (partlen = 0; partlen < len; partlen++) {
95+
if (joined[partlen] == '\0') {
96+
partlen++;
97+
break;
98+
}
99+
}
100+
tal_arr_expand(&key, tal_strndup(key, (char *)joined, partlen));
101+
len -= partlen;
102+
joined += partlen;
103+
} while (len != 0);
104+
105+
return cast_const2(const char **, key);
106+
}
107+
108+
struct db_stmt *db_datastore_next(const tal_t *ctx,
109+
struct db_stmt *stmt,
110+
const char **startkey,
111+
const char ***key,
112+
const u8 **data,
113+
u64 *generation)
114+
{
115+
if (!db_step(stmt))
116+
return tal_free(stmt);
117+
118+
*key = db_col_datastore_key(ctx, stmt, "key");
119+
120+
/* We select from startkey onwards, so once we're past it, stop */
121+
if (startkey && !datastore_key_startswith(*key, startkey)) {
122+
db_col_ignore(stmt, "data");
123+
db_col_ignore(stmt, "generation");
124+
return tal_free(stmt);
125+
}
126+
127+
if (data)
128+
*data = db_col_arr(ctx, stmt, "data", u8);
129+
else
130+
db_col_ignore(stmt, "data");
131+
132+
if (generation)
133+
*generation = db_col_u64(stmt, "generation");
134+
else
135+
db_col_ignore(stmt, "generation");
136+
137+
return stmt;
138+
}
139+
140+
struct db_stmt *db_datastore_first(const tal_t *ctx,
141+
struct db *db,
142+
const char **startkey,
143+
const char ***key,
144+
const u8 **data,
145+
u64 *generation)
146+
{
147+
struct db_stmt *stmt;
148+
149+
if (startkey) {
150+
stmt = db_prepare_v2(db,
151+
SQL("SELECT key, data, generation"
152+
" FROM datastore"
153+
" WHERE key >= ?"
154+
" ORDER BY key;"));
155+
db_bind_datastore_key(stmt, startkey);
156+
} else {
157+
stmt = db_prepare_v2(db,
158+
SQL("SELECT key, data, generation"
159+
" FROM datastore"
160+
" ORDER BY key;"));
161+
}
162+
db_query_prepared(stmt);
163+
164+
return db_datastore_next(ctx, stmt, startkey, key, data, generation);
165+
}
166+
167+
void db_datastore_update(struct db *db, const char **key, const u8 *data)
168+
{
169+
struct db_stmt *stmt;
170+
171+
stmt = db_prepare_v2(db,
172+
SQL("UPDATE datastore SET data=?, generation=generation+1 WHERE key=?;"));
173+
db_bind_talarr(stmt, data);
174+
db_bind_datastore_key(stmt, key);
175+
db_exec_prepared_v2(take(stmt));
176+
}
177+

wallet/datastore.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef LIGHTNING_WALLET_DATASTORE_H
2+
#define LIGHTNING_WALLET_DATASTORE_H
3+
/* Access routines for the datastore: here so that tools/lightningd-downgrade
4+
* can use them */
5+
#include "config.h"
6+
#include <ccan/short_types/short_types.h>
7+
#include <ccan/tal/tal.h>
8+
#include <stdbool.h>
9+
10+
struct db;
11+
struct db_stmt;
12+
13+
/* Does k1 match k2 as far as k2 goes? */
14+
bool datastore_key_startswith(const char **k1, const char **k2);
15+
bool datastore_key_eq(const char **k1, const char **k2);
16+
void db_bind_datastore_key(struct db_stmt *stmt, const char **key);
17+
u8 *db_datastore_get(const tal_t *ctx,
18+
struct db *db,
19+
const char **key,
20+
u64 *generation);
21+
struct db_stmt *db_datastore_next(const tal_t *ctx,
22+
struct db_stmt *stmt,
23+
const char **startkey,
24+
const char ***key,
25+
const u8 **data,
26+
u64 *generation);
27+
28+
struct db_stmt *db_datastore_first(const tal_t *ctx,
29+
struct db *db,
30+
const char **startkey,
31+
const char ***key,
32+
const u8 **data,
33+
u64 *generation);
34+
35+
/* Update existing record */
36+
void db_datastore_update(struct db *db, const char **key, const u8 *data);
37+
#endif /* LIGHTNING_WALLET_DATASTORE_H */

wallet/test/run-chain_moves_duplicate-detect.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static void db_log_(struct logger *log UNUSED, enum log_level level UNUSED, cons
2121
#include "db/db_sqlite3.c"
2222
#include "db/exec.c"
2323
#include "db/utils.c"
24+
#include "wallet/datastore.c"
2425
#include "wallet/db.c"
2526
#include "wallet/migrations.c"
2627
#include "common/coin_mvt.c"

wallet/test/run-db.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ static void db_log_(struct logger *log UNUSED, enum log_level level UNUSED, cons
1010
#include "db/db_sqlite3.c"
1111
#include "db/exec.c"
1212
#include "db/utils.c"
13+
#include "wallet/datastore.c"
1314
#include "wallet/db.c"
1415
#include "wallet/wallet.c"
1516
#include "wallet/migrations.c"

wallet/test/run-migrate_remove_chain_moves_duplicates.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,34 @@ void connect_htlc_in(struct htlc_in_map *map UNNEEDED, struct htlc_in *hin UNNEE
7878
/* Generated stub for connect_htlc_out */
7979
void connect_htlc_out(struct htlc_out_map *map UNNEEDED, struct htlc_out *hout UNNEEDED)
8080
{ fprintf(stderr, "connect_htlc_out called!\n"); abort(); }
81+
/* Generated stub for db_bind_datastore_key */
82+
void db_bind_datastore_key(struct db_stmt *stmt UNNEEDED, const char **key UNNEEDED)
83+
{ fprintf(stderr, "db_bind_datastore_key called!\n"); abort(); }
84+
/* Generated stub for db_datastore_first */
85+
struct db_stmt *db_datastore_first(const tal_t *ctx UNNEEDED,
86+
struct db *db UNNEEDED,
87+
const char **startkey UNNEEDED,
88+
const char ***key UNNEEDED,
89+
const u8 **data UNNEEDED,
90+
u64 *generation UNNEEDED)
91+
{ fprintf(stderr, "db_datastore_first called!\n"); abort(); }
92+
/* Generated stub for db_datastore_get */
93+
u8 *db_datastore_get(const tal_t *ctx UNNEEDED,
94+
struct db *db UNNEEDED,
95+
const char **key UNNEEDED,
96+
u64 *generation UNNEEDED)
97+
{ fprintf(stderr, "db_datastore_get called!\n"); abort(); }
98+
/* Generated stub for db_datastore_next */
99+
struct db_stmt *db_datastore_next(const tal_t *ctx UNNEEDED,
100+
struct db_stmt *stmt UNNEEDED,
101+
const char **startkey UNNEEDED,
102+
const char ***key UNNEEDED,
103+
const u8 **data UNNEEDED,
104+
u64 *generation UNNEEDED)
105+
{ fprintf(stderr, "db_datastore_next called!\n"); abort(); }
106+
/* Generated stub for db_datastore_update */
107+
void db_datastore_update(struct db *db UNNEEDED, const char **key UNNEEDED, const u8 *data UNNEEDED)
108+
{ fprintf(stderr, "db_datastore_update called!\n"); abort(); }
81109
/* Generated stub for fatal */
82110
void fatal(const char *fmt UNNEEDED, ...)
83111
{ fprintf(stderr, "fatal called!\n"); abort(); }

wallet/test/run-wallet.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ static void test_error(struct lightningd *ld, bool fatal, const char *fmt, va_li
3535
#include "db/db_sqlite3.c"
3636
#include "db/exec.c"
3737
#include "db/utils.c"
38+
#include "wallet/datastore.c"
3839
#include "wallet/db.c"
3940
#include "wallet/migrations.c"
4041

0 commit comments

Comments
 (0)