Skip to content

Commit d72f045

Browse files
rustyrussellendothermicdev
authored andcommitted
lightningd: represent runes blacklist as simple bitmap.
Sure, we have to convert to and from the db set-of-pairs, but that's far simpler than dealing with the current structure now we want to add code to *remove* from the blacklist. Changelog-Changed: JSON-RPC: `blacklistrune` no longer supports of runes over id 100,000,000. Signed-off-by: Rusty Russell <[email protected]>
1 parent 7b1e36d commit d72f045

File tree

3 files changed

+72
-108
lines changed

3 files changed

+72
-108
lines changed

lightningd/runes.c

Lines changed: 59 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "config.h"
22
#include <ccan/array_size/array_size.h>
3+
#include <ccan/bitmap/bitmap.h>
34
#include <ccan/json_escape/json_escape.h>
45
#include <ccan/rune/rune.h>
56
#include <ccan/tal/str/str.h>
@@ -19,6 +20,9 @@
1920
#include <lightningd/runes.h>
2021
#include <wallet/wallet.h>
2122

23+
/* "640k should be enough for anybody!" */
24+
#define MAX_BLACKLIST_NUM 100000000
25+
2226
static const u64 sec_per_nsec = 1000000000;
2327

2428
struct cond_info {
@@ -36,7 +40,7 @@ struct runes {
3640
struct lightningd *ld;
3741
struct rune *master;
3842
u64 next_unique_id;
39-
struct rune_blacklist *blacklist;
43+
BITMAP_DECLARE(blist_bitmap, MAX_BLACKLIST_NUM);
4044
};
4145

4246
enum invoice_field {
@@ -179,12 +183,41 @@ struct runes *runes_early_init(struct lightningd *ld)
179183
return runes;
180184
}
181185

186+
static void blacklist_to_bitmap(const struct rune_blacklist *blist,
187+
bitmap *bitmap, size_t nbits)
188+
{
189+
bitmap_zero(bitmap, nbits);
190+
for (size_t i = 0; i < tal_count(blist); i++) {
191+
assert(blist[i].end < nbits);
192+
bitmap_fill_range(bitmap, blist[i].start, blist[i].end+1);
193+
}
194+
}
195+
196+
static struct rune_blacklist *bitmap_to_blacklist(tal_t *ctx,
197+
const bitmap *bitmap, size_t nbits)
198+
{
199+
struct rune_blacklist *blist = tal_arr(ctx, struct rune_blacklist, 0);
200+
size_t i = 0;
201+
202+
while ((i = bitmap_ffs(bitmap, i, nbits)) != nbits) {
203+
struct rune_blacklist b;
204+
b.start = b.end = i;
205+
while (b.end < nbits && bitmap_test_bit(bitmap, b.end + 1))
206+
b.end++;
207+
tal_arr_expand(&blist, b);
208+
i = b.end + 1;
209+
}
210+
return blist;
211+
}
212+
182213
void runes_finish_init(struct runes *runes)
183214
{
184215
struct lightningd *ld = runes->ld;
216+
struct rune_blacklist *blist;
185217

186218
runes->next_unique_id = wallet_get_rune_next_unique_id(runes, ld->wallet);
187-
runes->blacklist = wallet_get_runes_blacklist(runes, ld->wallet);
219+
blist = wallet_get_runes_blacklist(tmpctx, ld->wallet);
220+
blacklist_to_bitmap(blist, runes->blist_bitmap, MAX_BLACKLIST_NUM);
188221
}
189222

190223
struct rune_and_string {
@@ -301,12 +334,7 @@ static bool is_rune_blacklisted(const struct runes *runes, const struct rune *ru
301334
return false;
302335
}
303336
uid = rune_unique_id(rune);
304-
for (size_t i = 0; i < tal_count(runes->blacklist); i++) {
305-
if (runes->blacklist[i].start <= uid && runes->blacklist[i].end >= uid) {
306-
return true;
307-
}
308-
}
309-
return false;
337+
return uid < MAX_BLACKLIST_NUM && bitmap_test_bit(runes->blist_bitmap, uid);
310338
}
311339

312340
static void join_strings(char **base, const char *connector, char *append)
@@ -595,32 +623,16 @@ static const struct json_command invokerune_command = {
595623
};
596624
AUTODATA(json_command, &invokerune_command);
597625

598-
static void blacklist_merge(struct rune_blacklist *blacklist,
599-
const struct rune_blacklist *entry)
600-
{
601-
if (entry->start < blacklist->start) {
602-
blacklist->start = entry->start;
603-
}
604-
if (entry->end > blacklist->end) {
605-
blacklist->end = entry->end;
606-
}
607-
}
608-
609-
static bool blacklist_before(const struct rune_blacklist *first,
610-
const struct rune_blacklist *second)
611-
{
612-
// Is it before with a gap
613-
return (first->end + 1) < second->start;
614-
}
615-
616-
static struct command_result *list_blacklist(struct command *cmd)
626+
static struct command_result *list_blacklist(struct command *cmd,
627+
const struct rune_blacklist *blist)
617628
{
618629
struct json_stream *js = json_stream_success(cmd);
630+
619631
json_array_start(js, "blacklist");
620-
for (size_t i = 0; i < tal_count(cmd->ld->runes->blacklist); i++) {
632+
for (size_t i = 0; i < tal_count(blist); i++) {
621633
json_object_start(js, NULL);
622-
json_add_u64(js, "start", cmd->ld->runes->blacklist[i].start);
623-
json_add_u64(js, "end", cmd->ld->runes->blacklist[i].end);
634+
json_add_u64(js, "start", blist[i].start);
635+
json_add_u64(js, "end", blist[i].end);
624636
json_object_end(js);
625637
}
626638
json_array_end(js);
@@ -633,7 +645,7 @@ static struct command_result *json_blacklistrune(struct command *cmd,
633645
const jsmntok_t *params)
634646
{
635647
u64 *start, *end;
636-
struct rune_blacklist *entry, *newblacklist;
648+
struct rune_blacklist *blist;
637649

638650
if (!param_check(cmd, buffer, params,
639651
p_opt("start", param_u64, &start), p_opt("end", param_u64, &end), NULL))
@@ -643,53 +655,30 @@ static struct command_result *json_blacklistrune(struct command *cmd,
643655
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Can not specify end without start");
644656
}
645657

658+
if (!end) {
659+
end = start;
660+
}
661+
662+
if (*end >= MAX_BLACKLIST_NUM) {
663+
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Cannot blacklist beyond %u", MAX_BLACKLIST_NUM);
664+
}
665+
646666
if (command_check_only(cmd))
647667
return command_check_done(cmd);
648668

649669
if (!start) {
650-
return list_blacklist(cmd);
670+
blist = bitmap_to_blacklist(cmd, cmd->ld->runes->blist_bitmap, MAX_BLACKLIST_NUM);
671+
return list_blacklist(cmd, blist);
651672
}
652-
if (!end) {
653-
end = start;
654-
}
655-
entry = tal(cmd, struct rune_blacklist);
656-
entry->start = *start;
657-
entry->end = *end;
658673

659-
newblacklist = tal_arr(cmd->ld->runes, struct rune_blacklist, 0);
674+
/* Include end */
675+
bitmap_fill_range(cmd->ld->runes->blist_bitmap, *start, (*end)+1);
660676

661-
for (size_t i = 0; i < tal_count(cmd->ld->runes->blacklist); i++) {
662-
/* if new entry if already merged just copy the old list */
663-
if (entry == NULL) {
664-
tal_arr_expand(&newblacklist, cmd->ld->runes->blacklist[i]);
665-
continue;
666-
}
667-
/* old list has not reached the entry yet, so we are just copying it */
668-
if (blacklist_before(&(cmd->ld->runes->blacklist)[i], entry)) {
669-
tal_arr_expand(&newblacklist, cmd->ld->runes->blacklist[i]);
670-
continue;
671-
}
672-
/* old list has passed the entry, time to put the entry in */
673-
if (blacklist_before(entry, &(cmd->ld->runes->blacklist)[i])) {
674-
tal_arr_expand(&newblacklist, *entry);
675-
tal_arr_expand(&newblacklist, cmd->ld->runes->blacklist[i]);
676-
wallet_insert_blacklist(cmd->ld->wallet, entry);
677-
// mark entry as copied
678-
entry = NULL;
679-
continue;
680-
}
681-
/* old list overlaps combined into the entry we are adding */
682-
blacklist_merge(entry, &(cmd->ld->runes->blacklist)[i]);
683-
wallet_delete_blacklist(cmd->ld->wallet, &(cmd->ld->runes->blacklist)[i]);
684-
}
685-
if (entry != NULL) {
686-
tal_arr_expand(&newblacklist, *entry);
687-
wallet_insert_blacklist(cmd->ld->wallet, entry);
688-
}
677+
/* Convert to list once, use for db and for list_blacklist */
678+
blist = bitmap_to_blacklist(cmd, cmd->ld->runes->blist_bitmap, MAX_BLACKLIST_NUM);
679+
wallet_set_blacklist(cmd->ld->wallet, blist);
689680

690-
tal_free(cmd->ld->runes->blacklist);
691-
cmd->ld->runes->blacklist = newblacklist;
692-
return list_blacklist(cmd);
681+
return list_blacklist(cmd, blist);
693682
}
694683

695684
static const struct json_command blacklistrune_command = {

wallet/wallet.c

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6234,37 +6234,20 @@ void wallet_rune_update_last_used(struct wallet *wallet, const struct rune *rune
62346234
tal_free(stmt);
62356235
}
62366236

6237-
static void db_insert_blacklist(struct db *db,
6238-
const struct rune_blacklist *entry)
6239-
{
6240-
struct db_stmt *stmt;
6241-
6242-
stmt = db_prepare_v2(db,
6243-
SQL("INSERT INTO runes_blacklist VALUES (?,?)"));
6244-
db_bind_u64(stmt, entry->start);
6245-
db_bind_u64(stmt, entry->end);
6246-
db_exec_prepared_v2(stmt);
6247-
tal_free(stmt);
6248-
}
6249-
6250-
void wallet_insert_blacklist(struct wallet *wallet, const struct rune_blacklist *entry)
6251-
{
6252-
db_insert_blacklist(wallet->db, entry);
6253-
}
6254-
6255-
void wallet_delete_blacklist(struct wallet *wallet, const struct rune_blacklist *entry)
6237+
/* Hardly a common operation! Delete and rewrite entire table */
6238+
void wallet_set_blacklist(struct wallet *wallet, const struct rune_blacklist *blist)
62566239
{
62576240
struct db_stmt *stmt;
6241+
stmt = db_prepare_v2(wallet->db, SQL("DELETE FROM runes_blacklist"));
6242+
db_exec_prepared_v2(take(stmt));
62586243

6259-
stmt = db_prepare_v2(wallet->db,
6260-
SQL("DELETE FROM runes_blacklist WHERE start_index = ? AND end_index = ?"));
6261-
db_bind_u64(stmt, entry->start);
6262-
db_bind_u64(stmt, entry->end);
6263-
db_exec_prepared_v2(stmt);
6264-
if (db_count_changes(stmt) != 1) {
6265-
db_fatal(wallet->db, "Failed to delete from runes_blacklist");
6244+
for (size_t i = 0; i < tal_count(blist); i++) {
6245+
stmt = db_prepare_v2(wallet->db,
6246+
SQL("INSERT INTO runes_blacklist VALUES (?,?)"));
6247+
db_bind_u64(stmt, blist[i].start);
6248+
db_bind_u64(stmt, blist[i].end);
6249+
db_exec_prepared_v2(take(stmt));
62666250
}
6267-
tal_free(stmt);
62686251
}
62696252

62706253
void migrate_datastore_commando_runes(struct lightningd *ld, struct db *db)

wallet/wallet.h

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,20 +1749,12 @@ u64 wallet_get_rune_next_unique_id(const tal_t *ctx, struct wallet *wallet);
17491749
struct rune_blacklist *wallet_get_runes_blacklist(const tal_t *ctx, struct wallet *wallet);
17501750

17511751
/**
1752-
* wallet_insert_blacklist -- Insert rune into blacklist
1752+
* wallet_set_blacklist -- Replace the blacklist
17531753
*
17541754
* @wallet: the wallet to save into
1755-
* @entry: the new entry to insert
1755+
* @blist: the new blacklist
17561756
*/
1757-
void wallet_insert_blacklist(struct wallet *wallet, const struct rune_blacklist *entry);
1758-
1759-
/**
1760-
* wallet_delete_blacklist -- Delete row from blacklist
1761-
*
1762-
* @wallet: the wallet to delete from
1763-
* @entry: the entry to delete
1764-
*/
1765-
void wallet_delete_blacklist(struct wallet *wallet, const struct rune_blacklist *entry);
1757+
void wallet_set_blacklist(struct wallet *wallet, const struct rune_blacklist *blist);
17661758

17671759
/**
17681760
* wallet_set_local_anchor -- Set local anchor point for a remote commitment tx

0 commit comments

Comments
 (0)