Skip to content

Commit 52f1938

Browse files
committed
bkpr: migration to delete any duplicate lease_fee entries
Clean up for #5557. If you've got duplicate 'lease_fee' entries, we delete them!
1 parent af41c7c commit 52f1938

File tree

4 files changed

+69
-2
lines changed

4 files changed

+69
-2
lines changed

contrib/pyln-testing/pyln/testing/utils.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,8 +1435,8 @@ def get_nodes(self, num_nodes, opts=None):
14351435
return [j.result() for j in jobs]
14361436

14371437
def get_node(self, node_id=None, options=None, dbfile=None,
1438-
feerates=(15000, 11000, 7500, 3750), start=True,
1439-
wait_for_bitcoind_sync=True, may_fail=False,
1438+
bkpr_dbfile=None, feerates=(15000, 11000, 7500, 3750),
1439+
start=True, wait_for_bitcoind_sync=True, may_fail=False,
14401440
expect_fail=False, cleandir=True, **kwargs):
14411441
self.throttler.wait()
14421442
node_id = self.get_node_id() if not node_id else node_id
@@ -1470,6 +1470,12 @@ def get_node(self, node_id=None, options=None, dbfile=None,
14701470
with lzma.open(os.path.join('tests/data', dbfile), 'rb') as f:
14711471
out.write(f.read())
14721472

1473+
if bkpr_dbfile:
1474+
out = open(os.path.join(node.daemon.lightning_dir, TEST_NETWORK,
1475+
'accounts.sqlite3'), 'xb')
1476+
with lzma.open(os.path.join('tests/data', bkpr_dbfile), 'rb') as f:
1477+
out.write(f.read())
1478+
14731479
if start:
14741480
try:
14751481
node.start(wait_for_bitcoind_sync)

plugins/bkpr/db.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ struct migration {
1515

1616
static struct plugin *plugin;
1717

18+
static void migration_remove_dupe_lease_fees(struct plugin *p, struct db *db);
19+
1820
/* Do not reorder or remove elements from this array.
1921
* It is used to migrate existing databases from a prevoius state, based on
2022
* string indicies */
@@ -99,6 +101,7 @@ static struct migration db_migrations[] = {
99101
{SQL("ALTER TABLE chain_events ADD ev_desc TEXT DEFAULT NULL;"), NULL},
100102
{SQL("ALTER TABLE channel_events ADD ev_desc TEXT DEFAULT NULL;"), NULL},
101103
{SQL("ALTER TABLE channel_events ADD rebalance_id BIGINT DEFAULT NULL;"), NULL},
104+
{NULL, migration_remove_dupe_lease_fees}
102105
};
103106

104107
static bool db_migrate(struct plugin *p, struct db *db, bool *created)
@@ -142,6 +145,49 @@ static bool db_migrate(struct plugin *p, struct db *db, bool *created)
142145
return current != orig;
143146
}
144147

148+
static void migration_remove_dupe_lease_fees(struct plugin *p, struct db *db)
149+
{
150+
struct db_stmt *stmt, *del_stmt;
151+
u64 *last_acct_id;
152+
153+
stmt = db_prepare_v2(db, SQL("SELECT"
154+
" id"
155+
", account_id"
156+
" FROM channel_events"
157+
" WHERE tag = 'lease_fee'"
158+
" ORDER BY account_id"));
159+
db_query_prepared(stmt);
160+
last_acct_id = NULL;
161+
while (db_step(stmt)) {
162+
u64 id, acct_id;
163+
id = db_col_u64(stmt, "id");
164+
acct_id = db_col_u64(stmt, "account_id");
165+
166+
if (!last_acct_id) {
167+
last_acct_id = tal(stmt, u64);
168+
*last_acct_id = acct_id;
169+
continue;
170+
}
171+
172+
if (*last_acct_id != acct_id) {
173+
*last_acct_id = acct_id;
174+
continue;
175+
}
176+
177+
plugin_log(plugin, LOG_INFORM,
178+
"Duplicate 'lease_fee' found for"
179+
" account %"PRIu64", deleting dupe",
180+
id);
181+
182+
/* same acct as last, we found a duplicate */
183+
del_stmt = db_prepare_v2(db, SQL("DELETE FROM channel_events"
184+
" WHERE id=?"));
185+
db_bind_u64(del_stmt, 0, id);
186+
db_exec_prepared_v2(take(del_stmt));
187+
}
188+
tal_free(stmt);
189+
}
190+
145191
/* Implement db_fatal, as a wrapper around fatal.
146192
* We use a ifndef block so that it can get be
147193
* implemented in a test file first, if necessary */
1.41 KB
Binary file not shown.

tests/test_bookkeeper.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from fixtures import * # noqa: F401,F403
22
from decimal import Decimal
33
from pyln.client import Millisatoshi
4+
from db import Sqlite3Db
45
from fixtures import TEST_NETWORK
56
from utils import (
67
sync_blockheight, wait_for, only_one, first_channel_id, TIMEOUT
@@ -708,3 +709,17 @@ def test_rebalance_tracking(node_factory, bitcoind):
708709
assert outbound_ev['debit_msat'] == Millisatoshi(1001)
709710
assert outbound_ev['credit_msat'] == Millisatoshi(0)
710711
assert outbound_ev['payment_id'] == pay_hash
712+
713+
714+
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "This test is based on a sqlite3 snapshot")
715+
def test_bookkeeper_lease_fee_dupe_migration(node_factory):
716+
""" Check that if there's duplicate lease_fees, we remove them"""
717+
718+
l1 = node_factory.get_node(bkpr_dbfile='dupe_lease_fee.sqlite3.xz')
719+
720+
wait_for(lambda: l1.daemon.is_in_log('Duplicate \'lease_fee\' found for account'))
721+
722+
accts_db_path = os.path.join(l1.lightning_dir, TEST_NETWORK, 'accounts.sqlite3')
723+
accts_db = Sqlite3Db(accts_db_path)
724+
725+
assert accts_db.query('SELECT tag from channel_events where tag = \'lease_fee\';') == [{'tag': 'lease_fee'}]

0 commit comments

Comments
 (0)