Browse Source

db: offer table.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa
Rusty Russell 4 years ago
committed by Christian Decker
parent
commit
381b0f456c
  1. 7
      wallet/db.c
  2. 52
      wallet/db_postgres_sqlgen.c
  3. 52
      wallet/db_sqlite3_sqlgen.c
  4. 66
      wallet/statements_gettextgen.po
  5. 166
      wallet/wallet.c
  6. 123
      wallet/wallet.h

7
wallet/db.c

@ -657,6 +657,13 @@ static struct migration dbmigrations[] = {
" cause INTEGER,"
" message TEXT"
");"), NULL},
{SQL("CREATE TABLE offers ("
" offer_id BLOB"
", bolt12 TEXT"
", label TEXT"
", status INTEGER"
", PRIMARY KEY (offer_id)"
");"), NULL},
};
/* Leak tracking. */

52
wallet/db_postgres_sqlgen.c

@ -848,6 +848,12 @@ struct db_query db_postgres_queries[] = {
.placeholders = 0,
.readonly = false,
},
{
.name = "CREATE TABLE offers ( offer_id BLOB, bolt12 TEXT, label TEXT, status INTEGER, PRIMARY KEY (offer_id));",
.query = "CREATE TABLE offers ( offer_id BYTEA, bolt12 TEXT, label TEXT, status INTEGER, PRIMARY KEY (offer_id));",
.placeholders = 0,
.readonly = false,
},
{
.name = "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?",
.query = "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = $1",
@ -1664,6 +1670,48 @@ struct db_query db_postgres_queries[] = {
.placeholders = 2,
.readonly = false,
},
{
.name = "SELECT 1 FROM offers WHERE offer_id = ?;",
.query = "SELECT 1 FROM offers WHERE offer_id = $1;",
.placeholders = 1,
.readonly = true,
},
{
.name = "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);",
.query = "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES ($1, $2, $3, $4);",
.placeholders = 4,
.readonly = false,
},
{
.name = "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;",
.query = "SELECT bolt12, label, status FROM offers WHERE offer_id = $1;",
.placeholders = 1,
.readonly = true,
},
{
.name = "SELECT offer_id FROM offers;",
.query = "SELECT offer_id FROM offers;",
.placeholders = 0,
.readonly = true,
},
{
.name = "UPDATE offers SET status=? WHERE offer_id = ?;",
.query = "UPDATE offers SET status=$1 WHERE offer_id = $2;",
.placeholders = 2,
.readonly = false,
},
{
.name = "UPDATE invoices SET state=? WHERE state=? AND offer_id = ?;",
.query = "UPDATE invoices SET state=$1 WHERE state=$2 AND offer_id = $3;",
.placeholders = 3,
.readonly = false,
},
{
.name = "SELECT status FROM offers WHERE offer_id = ?;",
.query = "SELECT status FROM offers WHERE offer_id = $1;",
.placeholders = 1,
.readonly = true,
},
{
.name = "SELECT name FROM sqlite_master WHERE type='table';",
.query = "SELECT name FROM sqlite_master WHERE type='table';",
@ -1684,10 +1732,10 @@ struct db_query db_postgres_queries[] = {
},
};
#define DB_POSTGRES_QUERY_COUNT 279
#define DB_POSTGRES_QUERY_COUNT 287
#endif /* HAVE_POSTGRES */
#endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */
// SHA256STAMP:a51ae4928fd56f2b22d0dd8f498f1288e2c3df7be872ddf1240f4b8fded6fd22
// SHA256STAMP:94af743741cd2a2d8725371af12e130a692334a118b52386fb901fadfe25d4cd

52
wallet/db_sqlite3_sqlgen.c

@ -848,6 +848,12 @@ struct db_query db_sqlite3_queries[] = {
.placeholders = 0,
.readonly = false,
},
{
.name = "CREATE TABLE offers ( offer_id BLOB, bolt12 TEXT, label TEXT, status INTEGER, PRIMARY KEY (offer_id));",
.query = "CREATE TABLE offers ( offer_id BLOB, bolt12 TEXT, label TEXT, status INTEGER, PRIMARY KEY (offer_id));",
.placeholders = 0,
.readonly = false,
},
{
.name = "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?",
.query = "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?",
@ -1664,6 +1670,48 @@ struct db_query db_sqlite3_queries[] = {
.placeholders = 2,
.readonly = false,
},
{
.name = "SELECT 1 FROM offers WHERE offer_id = ?;",
.query = "SELECT 1 FROM offers WHERE offer_id = ?;",
.placeholders = 1,
.readonly = true,
},
{
.name = "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);",
.query = "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);",
.placeholders = 4,
.readonly = false,
},
{
.name = "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;",
.query = "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;",
.placeholders = 1,
.readonly = true,
},
{
.name = "SELECT offer_id FROM offers;",
.query = "SELECT offer_id FROM offers;",
.placeholders = 0,
.readonly = true,
},
{
.name = "UPDATE offers SET status=? WHERE offer_id = ?;",
.query = "UPDATE offers SET status=? WHERE offer_id = ?;",
.placeholders = 2,
.readonly = false,
},
{
.name = "UPDATE invoices SET state=? WHERE state=? AND offer_id = ?;",
.query = "UPDATE invoices SET state=? WHERE state=? AND offer_id = ?;",
.placeholders = 3,
.readonly = false,
},
{
.name = "SELECT status FROM offers WHERE offer_id = ?;",
.query = "SELECT status FROM offers WHERE offer_id = ?;",
.placeholders = 1,
.readonly = true,
},
{
.name = "SELECT name FROM sqlite_master WHERE type='table';",
.query = "SELECT name FROM sqlite_master WHERE type='table';",
@ -1684,10 +1732,10 @@ struct db_query db_sqlite3_queries[] = {
},
};
#define DB_SQLITE3_QUERY_COUNT 279
#define DB_SQLITE3_QUERY_COUNT 287
#endif /* HAVE_SQLITE3 */
#endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */
// SHA256STAMP:a51ae4928fd56f2b22d0dd8f498f1288e2c3df7be872ddf1240f4b8fded6fd22
// SHA256STAMP:94af743741cd2a2d8725371af12e130a692334a118b52386fb901fadfe25d4cd

66
wallet/statements_gettextgen.po

@ -558,67 +558,71 @@ msgstr ""
msgid "CREATE TABLE channel_state_changes ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, timestamp BIGINT, old_state INTEGER, new_state INTEGER, cause INTEGER, message TEXT);"
msgstr ""
#: wallet/db.c:886
#: wallet/db.c:660
msgid "CREATE TABLE offers ( offer_id BLOB, bolt12 TEXT, label TEXT, status INTEGER, PRIMARY KEY (offer_id));"
msgstr ""
#: wallet/db.c:893
msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?"
msgstr ""
#: wallet/db.c:986
#: wallet/db.c:993
msgid "SELECT version FROM version LIMIT 1"
msgstr ""
#: wallet/db.c:1044
#: wallet/db.c:1051
msgid "UPDATE version SET version=?;"
msgstr ""
#: wallet/db.c:1052
#: wallet/db.c:1059
msgid "INSERT INTO db_upgrades VALUES (?, ?);"
msgstr ""
#: wallet/db.c:1064
#: wallet/db.c:1071
msgid "SELECT intval FROM vars WHERE name = 'data_version'"
msgstr ""
#: wallet/db.c:1091
#: wallet/db.c:1098
msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1"
msgstr ""
#: wallet/db.c:1107
#: wallet/db.c:1114
msgid "UPDATE vars SET intval=? WHERE name=?;"
msgstr ""
#: wallet/db.c:1116
#: wallet/db.c:1123
msgid "INSERT INTO vars (name, intval) VALUES (?, ?);"
msgstr ""
#: wallet/db.c:1130
#: wallet/db.c:1137
msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;"
msgstr ""
#: wallet/db.c:1151
#: wallet/db.c:1158
msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;"
msgstr ""
#: wallet/db.c:1167
#: wallet/db.c:1174
msgid "SELECT type, keyindex, prev_out_tx, prev_out_index, channel_id, peer_id, commitment_point FROM outputs WHERE scriptpubkey IS NULL;"
msgstr ""
#: wallet/db.c:1229
#: wallet/db.c:1236
msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?"
msgstr ""
#: wallet/db.c:1254
#: wallet/db.c:1261
msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;"
msgstr ""
#: wallet/db.c:1273
#: wallet/db.c:1280
msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;"
msgstr ""
#: wallet/db.c:1296
#: wallet/db.c:1303
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 ""
#: wallet/db.c:1363
#: wallet/db.c:1370
msgid "UPDATE channels SET last_tx = ? WHERE id = ?;"
msgstr ""
@ -1102,6 +1106,34 @@ msgstr ""
msgid "DELETE FROM penalty_bases WHERE channel_id = ? AND commitnum = ?"
msgstr ""
#: wallet/wallet.c:3976
msgid "SELECT 1 FROM offers WHERE offer_id = ?;"
msgstr ""
#: wallet/wallet.c:3989
msgid "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);"
msgstr ""
#: wallet/wallet.c:4017
msgid "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;"
msgstr ""
#: wallet/wallet.c:4045
msgid "SELECT offer_id FROM offers;"
msgstr ""
#: wallet/wallet.c:4071
msgid "UPDATE offers SET status=? WHERE offer_id = ?;"
msgstr ""
#: wallet/wallet.c:4082
msgid "UPDATE invoices SET state=? WHERE state=? AND offer_id = ?;"
msgstr ""
#: wallet/wallet.c:4110
msgid "SELECT status FROM offers WHERE offer_id = ?;"
msgstr ""
#: wallet/test/run-db.c:120
msgid "SELECT name FROM sqlite_master WHERE type='table';"
msgstr ""
@ -1113,4 +1145,4 @@ msgstr ""
#: wallet/test/run-wallet.c:1377
msgid "INSERT INTO channels (id) VALUES (1);"
msgstr ""
# SHA256STAMP:ebfc7675e32b832d172d040d0120cd339a1e1e924969373f8d7d6b75a7836c5b
# SHA256STAMP:3c2b67d1ede6a371d5dfbc97c6406cb3152c0a36ff60d714967552de6d02f7d7

166
wallet/wallet.c

@ -3961,3 +3961,169 @@ void wallet_penalty_base_delete(struct wallet *w, u64 chan_id, u64 commitnum)
db_bind_u64(stmt, 1, commitnum);
db_exec_prepared_v2(take(stmt));
}
bool wallet_offer_create(struct wallet *w,
const struct sha256 *offer_id,
const char *bolt12,
const struct json_escape *label,
enum offer_status status)
{
struct db_stmt *stmt;
assert(offer_status_active(status));
/* Test if already exists. */
stmt = db_prepare_v2(w->db, SQL("SELECT 1"
" FROM offers"
" WHERE offer_id = ?;"));
db_bind_sha256(stmt, 0, offer_id);
db_query_prepared(stmt);
if (db_step(stmt)) {
tal_free(stmt);
return false;
}
tal_free(stmt);
stmt = db_prepare_v2(w->db,
SQL("INSERT INTO offers ("
" offer_id"
", bolt12"
", label"
", status"
") VALUES (?, ?, ?, ?);"));
db_bind_sha256(stmt, 0, offer_id);
db_bind_text(stmt, 1, bolt12);
if (label)
db_bind_json_escape(stmt, 2, label);
else
db_bind_null(stmt, 2);
db_bind_int(stmt, 3, offer_status_in_db(status));
db_exec_prepared_v2(take(stmt));
return true;
}
char *wallet_offer_find(const tal_t *ctx,
struct wallet *w,
const struct sha256 *offer_id,
const struct json_escape **label,
enum offer_status *status)
{
struct db_stmt *stmt;
char *bolt12;
/* Test if already exists. */
stmt = db_prepare_v2(w->db, SQL("SELECT bolt12, label, status"
" FROM offers"
" WHERE offer_id = ?;"));
db_bind_sha256(stmt, 0, offer_id);
db_query_prepared(stmt);
if (!db_step(stmt)) {
tal_free(stmt);
return NULL;
}
bolt12 = tal_strdup(ctx, cast_signed(const char *, db_column_text(stmt, 0)));
if (label) {
if (db_column_is_null(stmt, 1))
*label = NULL;
else
*label = db_column_json_escape(ctx, stmt, 1);
}
if (status)
*status = offer_status_in_db(db_column_int(stmt, 2));
tal_free(stmt);
return bolt12;
}
struct db_stmt *wallet_offer_first(struct wallet *w, struct sha256 *offer_id)
{
struct db_stmt *stmt;
stmt = db_prepare_v2(w->db, SQL("SELECT offer_id FROM offers;"));
db_query_prepared(stmt);
return wallet_offer_next(w, stmt, offer_id);
}
struct db_stmt *wallet_offer_next(struct wallet *w,
struct db_stmt *stmt,
struct sha256 *offer_id)
{
if (!db_step(stmt))
return tal_free(stmt);
db_column_sha256(stmt, 0, offer_id);
return stmt;
}
/* If we make an offer inactive, this also expires all invoices
* which we issued for it. */
static void offer_status_update(struct db *db,
const struct sha256 *offer_id,
enum offer_status oldstatus,
enum offer_status newstatus)
{
struct db_stmt *stmt;
stmt = db_prepare_v2(db, SQL("UPDATE offers"
" SET status=?"
" WHERE offer_id = ?;"));
db_bind_int(stmt, 0, offer_status_in_db(newstatus));
db_bind_sha256(stmt, 1, offer_id);
db_exec_prepared_v2(take(stmt));
if (!offer_status_active(oldstatus)
|| offer_status_active(newstatus))
return;
stmt = db_prepare_v2(db, SQL("UPDATE invoices"
" SET state=?"
" WHERE state=? AND offer_id = ?;"));
db_bind_int(stmt, 0, invoice_status_in_db(UNPAID));
db_bind_int(stmt, 1, invoice_status_in_db(EXPIRED));
db_bind_sha256(stmt, 2, offer_id);
db_exec_prepared_v2(take(stmt));
}
enum offer_status wallet_offer_disable(struct wallet *w,
const struct sha256 *offer_id,
enum offer_status s)
{
enum offer_status newstatus;
assert(offer_status_active(s));
newstatus = offer_status_in_db(s &= ~OFFER_STATUS_ACTIVE_F);
offer_status_update(w->db, offer_id, s, newstatus);
return newstatus;
}
void wallet_offer_mark_used(struct db *db, const struct sha256 *offer_id)
{
struct db_stmt *stmt;
enum offer_status status;
stmt = db_prepare_v2(db, SQL("SELECT status"
" FROM offers"
" WHERE offer_id = ?;"));
db_bind_sha256(stmt, 0, offer_id);
db_query_prepared(stmt);
if (!db_step(stmt))
fatal("Unknown stats offer_id %s",
type_to_string(tmpctx, struct sha256, offer_id));
status = offer_status_in_db(db_column_int(stmt, 0));
tal_free(stmt);
if (!offer_status_active(status))
fatal("offer_id %s status %i",
type_to_string(tmpctx, struct sha256, offer_id),
status);
if (status == OFFER_SINGLE_USE)
offer_status_update(db, offer_id, status, OFFER_USED);
}

123
wallet/wallet.h

@ -1331,4 +1331,127 @@ struct penalty_base *wallet_penalty_base_load_for_channel(const tal_t *ctx,
*/
void wallet_penalty_base_delete(struct wallet *w, u64 chan_id, u64 commitnum);
/* /!\ This is a DB ENUM, please do not change the numbering of any
* already defined elements (adding is ok) /!\ */
#define OFFER_STATUS_ACTIVE_F 0x1
#define OFFER_STATUS_SINGLE_F 0x2
#define OFFER_STATUS_USED_F 0x4
enum offer_status {
OFFER_MULTIPLE_USE = OFFER_STATUS_ACTIVE_F,
OFFER_SINGLE_USE = OFFER_STATUS_ACTIVE_F|OFFER_STATUS_SINGLE_F,
OFFER_USED = OFFER_STATUS_SINGLE_F|OFFER_STATUS_USED_F,
OFFER_SINGLE_DISABLED = OFFER_STATUS_SINGLE_F,
OFFER_MULTIPLE_DISABLED = 0,
};
static inline enum offer_status offer_status_in_db(enum offer_status s)
{
switch (s) {
case OFFER_MULTIPLE_USE:
BUILD_ASSERT(OFFER_MULTIPLE_USE == 1);
return s;
case OFFER_SINGLE_USE:
BUILD_ASSERT(OFFER_SINGLE_USE == 3);
return s;
case OFFER_USED:
BUILD_ASSERT(OFFER_USED == 6);
return s;
case OFFER_SINGLE_DISABLED:
BUILD_ASSERT(OFFER_SINGLE_DISABLED == 2);
return s;
case OFFER_MULTIPLE_DISABLED:
BUILD_ASSERT(OFFER_MULTIPLE_DISABLED == 0);
return s;
}
fatal("%s: %u is invalid", __func__, s);
}
static inline bool offer_status_active(enum offer_status s)
{
return s & OFFER_STATUS_ACTIVE_F;
}
static inline bool offer_status_single(enum offer_status s)
{
return s & OFFER_STATUS_SINGLE_F;
}
/**
* Store an offer in the database.
* @w: the wallet
* @offer_id: the merkle root, as used for signing (must be unique)
* @bolt12: offer as text.
* @label: optional label for this offer.
* @status: OFFER_SINGLE_USE or OFFER_MULTIPLE_USE
*/
bool wallet_offer_create(struct wallet *w,
const struct sha256 *offer_id,
const char *bolt12,
const struct json_escape *label,
enum offer_status status)
NON_NULL_ARGS(1,2,3);
/**
* Retrieve an offer from the database.
* @ctx: the tal context to allocate return from.
* @w: the wallet
* @offer_id: the merkle root, as used for signing (must be unique)
* @label: the label of the offer, set to NULL if none (or NULL)
* @status: set if succeeds (or NULL)
*
* If @offer_id is found, returns the bolt12 text, sets @label and
* @state. Otherwise returns NULL.
*/
char *wallet_offer_find(const tal_t *ctx,
struct wallet *w,
const struct sha256 *offer_id,
const struct json_escape **label,
enum offer_status *status)
NON_NULL_ARGS(1,2,3);
/**
* Iterate through all the offers.
* @w: the wallet
* @offer_id: the first offer id (if returns non-NULL)
*
* Returns pointer to hand as @stmt to wallet_offer_next(), or NULL.
* If you choose not to call wallet_offer_next() you must free it!
*/
struct db_stmt *wallet_offer_first(struct wallet *w,
struct sha256 *offer_id);
/**
* Iterate through all the offers.
* @w: the wallet
* @stmt: return from wallet_offer_first() or previous wallet_offer_next()
* @offer_id: the next offer id (if returns non-NULL)
*
* Returns NULL once we're out of offers. If you choose not to call
* wallet_offer_next() again you must free return.
*/
struct db_stmt *wallet_offer_next(struct wallet *w,
struct db_stmt *stmt,
struct sha256 *offer_id);
/**
* Disable an offer in the database.
* @w: the wallet
* @offer_id: the merkle root, as used for signing (must be unique)
* @s: the current status (must be active).
*
* Must exist. Returns new status. */
enum offer_status wallet_offer_disable(struct wallet *w,
const struct sha256 *offer_id,
enum offer_status s)
NO_NULL_ARGS;
/**
* Mark an offer in the database used.
* @w: the wallet
* @offer_id: the merkle root, as used for signing (must be unique)
*
* Must exist and be active.
*/
void wallet_offer_mark_used(struct db *db, const struct sha256 *offer_id)
NO_NULL_ARGS;
#endif /* LIGHTNING_WALLET_WALLET_H */

Loading…
Cancel
Save