Skip to content

Commit f649a49

Browse files
committed
wallet: generate fixup chainmoves and channelmoves when first starting.
If we don't have an accountdb from bookkeeper: 1. Generate a deposit chain event for every confirmed UTXO. 2. Generate an open chain event for every open, confirmed channel. 3. Generate a push/lease event if necessary. 4. Generate a fixup "journal" entry if balance is different from initial. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent c6f91ee commit f649a49

File tree

10 files changed

+493
-93
lines changed

10 files changed

+493
-93
lines changed

common/coin_mvt.c

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -208,21 +208,22 @@ struct mvt_account_id *new_mvt_account_id(const tal_t *ctx,
208208
return acct;
209209
}
210210

211-
struct channel_coin_mvt *new_channel_coin_mvt(const tal_t *ctx,
212-
const struct channel *channel,
213-
u64 timestamp,
214-
const struct sha256 *payment_hash TAKES,
215-
const u64 *part_id,
216-
const u64 *group_id,
217-
enum coin_mvt_dir direction,
218-
struct amount_msat amount,
219-
struct mvt_tags tags,
220-
struct amount_msat fees)
211+
struct channel_coin_mvt *new_channel_coin_mvt_general(const tal_t *ctx,
212+
const struct channel *channel,
213+
const struct channel_id *cid,
214+
u64 timestamp,
215+
const struct sha256 *payment_hash TAKES,
216+
const u64 *part_id,
217+
const u64 *group_id,
218+
enum coin_mvt_dir direction,
219+
struct amount_msat amount,
220+
struct mvt_tags tags,
221+
struct amount_msat fees)
221222
{
222223
struct channel_coin_mvt *mvt = tal(ctx, struct channel_coin_mvt);
223224

224225
assert(mvt_tags_valid(tags));
225-
set_mvt_account_id(&mvt->account, channel, NULL);
226+
set_mvt_account_id(&mvt->account, channel, cid ? take(fmt_channel_id(NULL, cid)) : NULL);
226227
mvt->timestamp = timestamp;
227228
mvt->payment_hash = tal_dup_or_null(mvt, struct sha256, payment_hash);
228229
if (!part_id) {
@@ -252,6 +253,21 @@ struct channel_coin_mvt *new_channel_coin_mvt(const tal_t *ctx,
252253
abort();
253254
}
254255

256+
struct channel_coin_mvt *new_channel_coin_mvt(const tal_t *ctx,
257+
const struct channel *channel,
258+
u64 timestamp,
259+
const struct sha256 *payment_hash TAKES,
260+
const u64 *part_id,
261+
const u64 *group_id,
262+
enum coin_mvt_dir direction,
263+
struct amount_msat amount,
264+
struct mvt_tags tags,
265+
struct amount_msat fees)
266+
{
267+
return new_channel_coin_mvt_general(ctx, channel, NULL, timestamp, payment_hash,
268+
part_id, group_id, direction, amount, tags, fees);
269+
}
270+
255271
static struct chain_coin_mvt *new_chain_coin_mvt(const tal_t *ctx,
256272
const struct channel *channel,
257273
const char *account_name TAKES,
@@ -409,15 +425,17 @@ struct chain_coin_mvt *new_coin_channel_open_proposed(const tal_t *ctx,
409425
return mvt;
410426
}
411427

412-
struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx,
413-
const struct channel *channel,
414-
const struct bitcoin_outpoint *out,
415-
const struct node_id *peer_id,
416-
u32 blockheight,
417-
const struct amount_msat amount,
418-
const struct amount_sat output_val,
419-
bool is_opener,
420-
bool is_leased)
428+
struct chain_coin_mvt *new_coin_channel_open_general(const tal_t *ctx,
429+
const struct channel *channel,
430+
const struct channel_id *cid,
431+
u64 timestamp,
432+
const struct bitcoin_outpoint *out,
433+
const struct node_id *peer_id,
434+
u32 blockheight,
435+
const struct amount_msat amount,
436+
const struct amount_sat output_val,
437+
bool is_opener,
438+
bool is_leased)
421439
{
422440
struct chain_coin_mvt *mvt;
423441
struct mvt_tags tags = tag_to_mvt_tags(MVT_CHANNEL_OPEN);
@@ -429,7 +447,8 @@ struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx,
429447
if (is_leased)
430448
tag_set(&tags, MVT_LEASED);
431449

432-
mvt = new_chain_coin_mvt(ctx, channel, NULL, time_now().ts.tv_sec,
450+
mvt = new_chain_coin_mvt(ctx, channel, cid ? take(fmt_channel_id(NULL, cid)) : NULL,
451+
timestamp,
433452
NULL, out, NULL, blockheight,
434453
tags,
435454
COIN_CREDIT, amount,
@@ -439,6 +458,22 @@ struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx,
439458
return mvt;
440459
}
441460

461+
struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx,
462+
const struct channel *channel,
463+
const struct bitcoin_outpoint *out,
464+
const struct node_id *peer_id,
465+
u32 blockheight,
466+
const struct amount_msat amount,
467+
const struct amount_sat output_val,
468+
bool is_opener,
469+
bool is_leased)
470+
{
471+
return new_coin_channel_open_general(ctx, channel, NULL,
472+
time_now().ts.tv_sec,
473+
out, peer_id, blockheight,
474+
amount, output_val, is_opener, is_leased);
475+
}
476+
442477
struct chain_coin_mvt *new_onchain_htlc_deposit(const tal_t *ctx,
443478
const struct bitcoin_outpoint *outpoint,
444479
u32 blockheight,
@@ -523,16 +558,29 @@ struct chain_coin_mvt *new_coin_wallet_withdraw(const tal_t *ctx,
523558
COIN_DEBIT, amount);
524559
}
525560

561+
struct channel_coin_mvt *new_coin_channel_push_general(const tal_t *ctx,
562+
const struct channel *channel,
563+
const struct channel_id *cid,
564+
u64 timestamp,
565+
enum coin_mvt_dir direction,
566+
struct amount_msat amount,
567+
struct mvt_tags tags)
568+
{
569+
return new_channel_coin_mvt_general(ctx, channel, cid, timestamp, NULL,
570+
NULL, NULL, direction, amount,
571+
tags,
572+
AMOUNT_MSAT(0));
573+
}
574+
526575
struct channel_coin_mvt *new_coin_channel_push(const tal_t *ctx,
527576
const struct channel *channel,
528577
enum coin_mvt_dir direction,
529578
struct amount_msat amount,
530579
struct mvt_tags tags)
531580
{
532-
return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec, NULL,
533-
NULL, NULL, direction, amount,
534-
tags,
535-
AMOUNT_MSAT(0));
581+
return new_coin_channel_push_general(ctx, channel, NULL,
582+
time_now().ts.tv_sec,
583+
direction, amount, tags);
536584
}
537585

538586
struct chain_coin_mvt *new_foreign_deposit(const tal_t *ctx,

common/coin_mvt.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,39 @@ struct chain_coin_mvt *new_foreign_withdrawal(const tal_t *ctx,
277277
u64 timestamp)
278278
NON_NULL_ARGS(2, 3, 6);
279279

280+
/* Generic versions (prefer the above ones: these are for migrations) */
281+
struct channel_coin_mvt *new_channel_coin_mvt_general(const tal_t *ctx,
282+
const struct channel *channel,
283+
const struct channel_id *cid,
284+
u64 timestamp,
285+
const struct sha256 *payment_hash TAKES,
286+
const u64 *part_id,
287+
const u64 *group_id,
288+
enum coin_mvt_dir direction,
289+
struct amount_msat amount,
290+
struct mvt_tags tags,
291+
struct amount_msat fees);
292+
293+
struct chain_coin_mvt *new_coin_channel_open_general(const tal_t *ctx,
294+
const struct channel *channel,
295+
const struct channel_id *cid,
296+
u64 timestamp,
297+
const struct bitcoin_outpoint *out,
298+
const struct node_id *peer_id,
299+
u32 blockheight,
300+
const struct amount_msat amount,
301+
const struct amount_sat output_val,
302+
bool is_opener,
303+
bool is_leased);
304+
305+
struct channel_coin_mvt *new_coin_channel_push_general(const tal_t *ctx,
306+
const struct channel *channel,
307+
const struct channel_id *cid,
308+
u64 timestamp,
309+
enum coin_mvt_dir direction,
310+
struct amount_msat amount,
311+
struct mvt_tags tags);
312+
280313
/* There are three standard accounts:
281314
* "wallet" for our internal wallet,
282315
* "external" for other bitcoin sources,

common/test/run-coin_mvt.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u
4343
/* Generated stub for amount_tx_fee */
4444
struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
4545
{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); }
46+
/* Generated stub for fmt_channel_id */
47+
char *fmt_channel_id(const tal_t *ctx UNNEEDED, const struct channel_id *channel_id UNNEEDED)
48+
{ fprintf(stderr, "fmt_channel_id called!\n"); abort(); }
4649
/* Generated stub for fromwire */
4750
const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED)
4851
{ fprintf(stderr, "fromwire called!\n"); abort(); }

common/test/run-route_blinding_test.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#include <stdio.h>
1818

1919
/* AUTOGENERATED MOCKS START */
20+
/* Generated stub for fmt_channel_id */
21+
char *fmt_channel_id(const tal_t *ctx UNNEEDED, const struct channel_id *channel_id UNNEEDED)
22+
{ fprintf(stderr, "fmt_channel_id called!\n"); abort(); }
2023
/* Generated stub for fromwire_channel_id */
2124
bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
2225
struct channel_id *channel_id UNNEEDED)

plugins/bkpr/test/run-sql.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ u32 find_blockheight(const struct bkpr *bkpr UNNEEDED, const struct bitcoin_txid
3535
/* Generated stub for first_fee_state */
3636
enum htlc_state first_fee_state(enum side opener UNNEEDED)
3737
{ fprintf(stderr, "first_fee_state called!\n"); abort(); }
38+
/* Generated stub for fmt_channel_id */
39+
char *fmt_channel_id(const tal_t *ctx UNNEEDED, const struct channel_id *channel_id UNNEEDED)
40+
{ fprintf(stderr, "fmt_channel_id called!\n"); abort(); }
3841
/* Generated stub for fmt_wireaddr_without_port */
3942
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
4043
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }

tests/test_bookkeeper.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,3 +986,52 @@ def test_migration(node_factory, bitcoind):
986986

987987
# When generating, we want to stop so you can grab databases.
988988
assert generate is False
989+
990+
991+
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "uses snapshots")
992+
def test_migration_no_bkpr(node_factory, bitcoind):
993+
"""These nodes need to invent coinmoves to make the balances work"""
994+
bitcoind.generate_block(1)
995+
l1 = node_factory.get_node(dbfile="l1-before-moves-in-db.sqlite3.xz",
996+
options={'database-upgrade': True})
997+
l2 = node_factory.get_node(dbfile="l2-before-moves-in-db.sqlite3.xz",
998+
options={'database-upgrade': True})
999+
1000+
chan = only_one(l1.rpc.listpeerchannels()['channels'])
1001+
payment = only_one(l1.rpc.listsendpays()['payments'])
1002+
1003+
l1_events = l1.rpc.bkpr_listaccountevents()['events']
1004+
for e in l1_events:
1005+
del e['timestamp']
1006+
1007+
l2_events = l2.rpc.bkpr_listaccountevents()['events']
1008+
for e in l2_events:
1009+
del e['timestamp']
1010+
1011+
assert l1_events == [{'account': chan['channel_id'],
1012+
'blockheight': 103,
1013+
'credit_msat': 1000000000,
1014+
'currency': 'bcrt',
1015+
'debit_msat': 0,
1016+
'outpoint': f"{chan['funding_txid']}:{chan['funding_outnum']}",
1017+
'tag': 'channel_open',
1018+
'type': 'chain'},
1019+
{'account': 'wallet',
1020+
'blockheight': 103,
1021+
'credit_msat': 995073000,
1022+
'currency': 'bcrt',
1023+
'debit_msat': 0,
1024+
'outpoint': f"{chan['funding_txid']}:{chan['funding_outnum'] ^ 1}",
1025+
'tag': 'deposit',
1026+
'type': 'chain'},
1027+
{'account': chan['channel_id'],
1028+
'credit_msat': 0,
1029+
'currency': 'bcrt',
1030+
'debit_msat': 12345678,
1031+
'is_rebalance': False,
1032+
'part_id': 0,
1033+
'payment_id': payment['payment_hash'],
1034+
'tag': 'journal',
1035+
'type': 'channel'}]
1036+
1037+
assert l2_events == []

tests/test_coinmoves.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
sync_blockheight, wait_for, only_one, TIMEOUT
44
)
55

6+
import os
67
import pytest
78
import re
89
import time
10+
import unittest
911

1012

1113
# While we're doing this, check sql plugin's representation too.
@@ -1909,3 +1911,43 @@ def test_wait(node_factory, bitcoind, executor):
19091911
'channelmoves': {'account': fund['channel_id'],
19101912
'debit_msat': 1000000000,
19111913
'credit_msat': 0}}
1914+
1915+
1916+
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "uses snapshots")
1917+
def test_migration(node_factory, bitcoind):
1918+
"""These nodes import coinmoves from the old bookkeeper account.db"""
1919+
bitcoind.generate_block(1)
1920+
l1 = node_factory.get_node(dbfile="l1-before-moves-in-db.sqlite3.xz",
1921+
bkpr_dbfile="l1-bkpr-accounts.sqlite3.xz",
1922+
options={'database-upgrade': True})
1923+
l2 = node_factory.get_node(dbfile="l2-before-moves-in-db.sqlite3.xz",
1924+
bkpr_dbfile="l2-bkpr-accounts.sqlite3.xz",
1925+
options={'database-upgrade': True})
1926+
1927+
expected_channel1 = []
1928+
expected_channel2 = []
1929+
expected_chain1 = []
1930+
expected_chain2 = []
1931+
check_channel_moves(l1, expected_channel1)
1932+
check_channel_moves(l2, expected_channel2)
1933+
check_chain_moves(l1, expected_chain1)
1934+
check_chain_moves(l2, expected_chain2)
1935+
1936+
1937+
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "uses snapshots")
1938+
def test_migration_no_bkpr(node_factory, bitcoind):
1939+
"""These nodes need to invent coinmoves to make the balances work"""
1940+
bitcoind.generate_block(1)
1941+
l1 = node_factory.get_node(dbfile="l1-before-moves-in-db.sqlite3.xz",
1942+
options={'database-upgrade': True})
1943+
l2 = node_factory.get_node(dbfile="l2-before-moves-in-db.sqlite3.xz",
1944+
options={'database-upgrade': True})
1945+
1946+
expected_channel1 = []
1947+
expected_channel2 = []
1948+
expected_chain1 = []
1949+
expected_chain2 = []
1950+
check_channel_moves(l1, expected_channel1)
1951+
check_channel_moves(l2, expected_channel2)
1952+
check_chain_moves(l1, expected_chain1)
1953+
check_chain_moves(l2, expected_chain2)

wallet/test/run-db.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,19 @@ struct channel *new_channel(struct peer *peer UNNEEDED, u64 dbid UNNEEDED,
265265
const struct channel_stats *stats UNNEEDED,
266266
struct channel_state_change **state_changes STEALS UNNEEDED)
267267
{ fprintf(stderr, "new_channel called!\n"); abort(); }
268+
/* Generated stub for new_channel_coin_mvt_general */
269+
struct channel_coin_mvt *new_channel_coin_mvt_general(const tal_t *ctx UNNEEDED,
270+
const struct channel *channel UNNEEDED,
271+
const struct channel_id *cid UNNEEDED,
272+
u64 timestamp UNNEEDED,
273+
const struct sha256 *payment_hash TAKES UNNEEDED,
274+
const u64 *part_id UNNEEDED,
275+
const u64 *group_id UNNEEDED,
276+
enum coin_mvt_dir direction UNNEEDED,
277+
struct amount_msat amount UNNEEDED,
278+
struct mvt_tags tags UNNEEDED,
279+
struct amount_msat fees UNNEEDED)
280+
{ fprintf(stderr, "new_channel_coin_mvt_general called!\n"); abort(); }
268281
/* Generated stub for new_channel_state_change */
269282
struct channel_state_change *new_channel_state_change(const tal_t *ctx UNNEEDED,
270283
struct timeabs timestamp UNNEEDED,
@@ -273,6 +286,28 @@ struct channel_state_change *new_channel_state_change(const tal_t *ctx UNNEEDED,
273286
enum state_change cause UNNEEDED,
274287
const char *message TAKES UNNEEDED)
275288
{ fprintf(stderr, "new_channel_state_change called!\n"); abort(); }
289+
/* Generated stub for new_coin_channel_open_general */
290+
struct chain_coin_mvt *new_coin_channel_open_general(const tal_t *ctx UNNEEDED,
291+
const struct channel *channel UNNEEDED,
292+
const struct channel_id *cid UNNEEDED,
293+
u64 timestamp UNNEEDED,
294+
const struct bitcoin_outpoint *out UNNEEDED,
295+
const struct node_id *peer_id UNNEEDED,
296+
u32 blockheight UNNEEDED,
297+
const struct amount_msat amount UNNEEDED,
298+
const struct amount_sat output_val UNNEEDED,
299+
bool is_opener UNNEEDED,
300+
bool is_leased UNNEEDED)
301+
{ fprintf(stderr, "new_coin_channel_open_general called!\n"); abort(); }
302+
/* Generated stub for new_coin_channel_push_general */
303+
struct channel_coin_mvt *new_coin_channel_push_general(const tal_t *ctx UNNEEDED,
304+
const struct channel *channel UNNEEDED,
305+
const struct channel_id *cid UNNEEDED,
306+
u64 timestamp UNNEEDED,
307+
enum coin_mvt_dir direction UNNEEDED,
308+
struct amount_msat amount UNNEEDED,
309+
struct mvt_tags tags UNNEEDED)
310+
{ fprintf(stderr, "new_coin_channel_push_general called!\n"); abort(); }
276311
/* Generated stub for new_coin_wallet_deposit */
277312
struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx UNNEEDED,
278313
const struct bitcoin_outpoint *outpoint UNNEEDED,

0 commit comments

Comments
 (0)