Commit Graph

198 Commits

Author SHA1 Message Date
Rusty Russell
66741dda79 plugins/bkpr/test/run-recorder: don't hand NULL cmd.
ubsan complains that we declared a function not to take NULL.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
f8a44d911d bkpr: restore run-recorder.
This requires us to turn "sql" calls into calls to a local db, which
means pulling in a lot of infrastructure.  But it's possible.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
194febe873 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>
2025-08-19 13:37:50 +09:30
Rusty Russell
52d69df10f lightningd: migrate events from bookkeeper at startup.
We take over the --bookkeeper-dir and --bookkeeper-db options, and
then if we can find the bookkeeper db we extract the records to
initialize our chain_moves and channel_moves tables.

Of course, bookkeeper now needs to not register those options.

When bookkeeper gets invoked the first time, it will reconstruct
everything from listchannelmoves and listcoinmoves.  It cannot
preserve manually-added descriptions, so we put those in the datastore
for it ready to go.

Note that the order of onchain_fee changes slightly from the original.
But this is fine.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
41ac9db7ea bookkeeper: remove database.
Changelog-Changed: Plugins: `bookkeeper` now uses the lightningd database, not "accounts.db".
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
8748755834 bkpr: remove missing event handling.
There will be no more missing events (and at initialization time, we will do
that as a migration).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
b70f4f6184 bkpr: convert all the local db sql queries into calls to sql plugin.
With some help (and hinderance!) from ChatGPT: the field names
differ slightly from our internal db.

The particilar wrinkle is that we have to restrict all queries to
limit them to entries we've seen already.  Our code expects this (we
used to only enter it into the db when we processed it), and it would
otherwise be confusing if a sql query returned inconsistent results
because an event occurred while bookkeeper was processing.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
2a191479a3 bkpr: take, don't steal in new_channel_event.
Cleaner (I'm about to hand it a sha256 on the stack).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
45e860ad58 bkpr: helpers to query sql plugin for chainmoves and channelmoves.
We're going to be using this instead of our internal db.

I also made json_out_obj() take the str arg, as it didn't and I
expected it to.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
70d19e852e bkpr: use list commands instead of subscribing to notifications.
This is reliable, meaning we should never get replayed events.

We have to reference count to make sure all commands are complete,
before we return.  In particular, annotating with descriptions can
involve several calls to list commands.  We need to give them the
results *after* this is all complete.

test_bookkeeping_descriptions() relied on log messages from
notifications, which now only happen when a command is called.  This
changes the test a bit.

Since we no longer subscribe to the balance_snapshot event, we
need to create the wallet account at initialization, as callers
expect it to exist.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
f50ceb4ce6 bookkeeper: call refresh before processing any commands.
Rearrange all the JSON interfaces to call refresh_moves() (async)
before doing anything.

This does nothing for now, but it will be useful once we transition
from notifications to using the list commands.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
9cc08bf06d plugins/bkpr/test/run-recorder: remove.
It's a great test, but it's very hard to simulate now we are going to be
going from the internal db.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
1f7905259b bkpr: forward utxo_deposit / utxo_spend notifications to new injectutxodeposit / injectutxospend calls.
And thus we absorb them as normal when they come back as "foreign" entries.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
980241fc36 bookkeeper: don't set origin account to "null" if that's specified as transfer_from.
Before bkpr_listaccountevents() gave entries with origin like:

	{'account': "nifty's secret stash",
         'blockheight': 111,
         'credit_msat': 180000000,
         'currency': 'bcrt',
         'debit_msat': 0,
         'origin': 'null',
         'outpoint': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:0',
         'tag': 'deposit',
         'timestamp': 1679955976,
         'type': 'chain'},

Changelog-Changed: Plugins: "utxo_deposit" is allows to have missing `transfer_from`, and null is not considered an account name.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
78f88c1c0c common: use "foreign" in extra_tags to indicate a chain movement is injected.
This allows the bookkeeper plugin to know it's not actually a channel account.

Remove the "ignored" tag from the schema too: we removed it previously.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
254b7ed666 lightningd: new internal-use commands to allow utxo spend / deposit injection.
For the moment, we'll continue to use bookkeeper to monitor the
notifications to insert these (we don't have the internal infrastructure
for that, and actually these commands are probably better than using
notifications).

We hoist param_outpoint() into common code, since there are already
two uses.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
c5e359c7ee bkpr: add in-mem & datastore storage for external blockheights.
We won't be able to "UPDATE chain_events", so keep a separate record
of these blockheights, and lookup that when the blockheight is 0.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
e28443ed40 bkpr: pass bkpr struct into all functions in recorder.c.
We want to access it in stmt2chain_event, so plumb it through.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
0afc4c0346 bookkeeper: use the in-memory rebalances.
Remove the rebalance field from channel_event, and use the
find_rebalance(bkpr, ev->db_id) to look it up instead.

chain_event's also had a `rebalance` field, but it was only ever set
(to false), never read.

Note: list_rebalances() was only used by tests, not a public API.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
6dcc580612 bkpr: infrastructure to keep rebalance pairs in mem & datastore.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
af2e403490 bkpr: use the in-memory event descriptions, not the database ones.
The new access APIs are more symmetrical:

1. edit_utxo_description -> add_utxo_description
2. add_payment_hash_desc -> add_payment_hash_description

And to read it, instead of accessing ->ev_desc (now removed) we use
chain_event_description() & channel_event_description(), threading bkpr though
as needed.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
e012a82c60 bookkeeper: infrastructure to keep descriptions (annotations) in mem and datastore.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
66d3680f0c bkpr: remove onchain_fees table.
This proves we don't access it any more.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
bf9c864e0f bkpr: save and restore onchain_fees from the datastore, not the db.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
4e49a66c03 bkpr: keep onchain_fees in memory & datastore.
This is not quite as efficient, perhaps, but in practice there are only
a handful of onchain fee records per account.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
568f12ea71 bkpr: remove redundant account_onchain_fees
It's account_get_chain_fees() without the ORDER BY clause, *and* it's
only used on the run-recorder.c test.

I also got ChatGPT to compare them, in case I missed something subtle.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
5dc88c9e84 bkpr: move onchain fees access into bkpr/onchain_fee.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
902f821f88 bkpr: remove accounts table from db altogether.
This proves we don't access it any more.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
fd657e8483 ]bkpr: save accounts in the datastore instead of database.
Note that the test where we remove the database causes the bookkeeper
plugin to assert, since we have removed part (but not all!) of its data
by removing the datastore.

Once the transition to the datastore is complete, this can be restored.

Note that we destroy the request before receiving a response, which causes
a message in the trace span which was confusing our test.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
9c786a20a7 bkpr: use direct names, not another table, in db.
This simplifies the transition (since accounts are going to be outside
the db).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
f72df6da9c bkpr: cache accounts table in memory.
When we don't have our own db, we're going to need to keep this information
in memory (and the datastore).  As a first step, simply cache it in memory
and still write through to the db.

This introduces some changes:
1. The account structures are not temporary, but in the hash table (so don't steal them).
2. test_forward_pad_fees_and_cltv assumed ordering, which was a latent bug.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
fb20a55706 bkpr: find_or_create_account() instead of raw new_account().
In practice, it's always either find_account() or find_or_create_account().

This means account_add can be made internal: we rename it to
account_db_add.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
40c0d86a5c bkpr: move account db functions from recorder.c into account.c.
This will let us cache them gradually in account.c, and eventually
remove the database table.

We also change find_close_account() to find_close_account_name(),
and maybe_mark_account_onchain() into account_onchain_closeheight()
and account_update_closeheight();

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
41856dc6c0 bkpr: expose struct bkpr to outside bookkeeper.c.
We're going to add more members here, so we will start handing around
the whole thing.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
c00d12fa0d bookkeeper: use modern plugin_get_data() instead of globals.
Slightly neater as we expand this, but also handles memleak natively!

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
030863d10b bkpr: strings in structures should be const.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
b7e95e49b4 bkpr: send a backtrace if we get a fatal db event.
Particularly useful if we do something outside a transaction if I mess
up the code, e.g:

```
bookkeeper: Attempting to prepare a db_stmt outside of a transaction: plugins/bkpr/recorder.c:591 (version v25.05-112-g4daf355-modded)
0x5caefda2414b send_backtrace
	common/daemon.c:33
0x5caefda08a30 db_error
	plugins/bkpr/db.c:133
0x5caefda4cb32 db_fatal
	db/utils.c:322
0x5caefda4cc9e db_prepare_v2_
	db/utils.c:103
0x5caefda0dcbe get_chain_events_by_id
	plugins/bkpr/recorder.c:591
0x5caefda063ce json_edit_desc_payment_id
	plugins/bkpr/bookkeeper.c:550
0x5caefda13ad3 ld_command_handle
	plugins/libplugin.c:2185
0x5caefda13d27 ld_read_json_one
	plugins/libplugin.c:2274
0x5caefda13dba ld_read_json
	plugins/libplugin.c:2294
0x5caefdab5478 next_plan
	ccan/ccan/io/io.c:60
0x5caefdab5949 do_plan
	ccan/ccan/io/io.c:422
0x5caefdab5a06 io_ready
	ccan/ccan/io/io.c:439
0x5caefdab7375 io_loop
	ccan/ccan/io/poll.c:455
0x5caefda1420c plugin_main
	plugins/libplugin.c:2507
0x5caefda07762 main
	plugins/bkpr/bookkeeper.c:2048
0x79a7c522a1c9 __libc_start_call_main
	../sysdeps/nptl/libc_start_call_main.h:58
0x79a7c522a28a __libc_start_main_impl
	../csu/libc-start.c:360
0x5caefda00374 ???
	???:0
0xffffffffffffffff ???
	???:0
Attempting to prepare a db_stmt outside of a transaction: plugins/bkpr/recorder.c:591
```
2025-08-19 13:37:50 +09:30
Rusty Russell
c5a80336a1 bkpr: NULL-out the function migrations.
Note that these migrations were inserted for v0.12, so only someone
upgrading directly from before that (2022-08-23) would be affected.

This avoids having to fix the migrations as we make changes.

We are going to mangle the db to allow testing, but then the final
step will be to migrate it to the core.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-19 13:37:50 +09:30
Rusty Russell
16819f345d lightningd: make notifications from plugins just like native ones.
Rather than forcing them to wrap their parameters in a "payload"
sub-object, copy in params directly.  We include the "origin" field
one level up, if they care.

The next patch restores compatibility for the one place we currently use
them, which is the pay plugin.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Deprecated: pyln-client: plugin custom notifications origins and payload (use parameters directly)
2025-08-18 10:01:07 +09:30
longhutianjie
f1bfa71e7b chore: fix some minor issues
Signed-off-by: longhutianjie <keplrnewton@icloud.com>
2025-08-15 11:05:51 +09:30
Rusty Russell
22b452ad19 lightningd: have onchaind inform us when to make a channel penalty_adj.
bookkeeper used to generate these as channel events, now lightningd does.

We also add a "journal" event, which we will need later too.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-14 19:49:09 +09:30
Rusty Russell
b1fa2ef30b bkpr: remove different currency support.
We still output the fields, they're just always the currency of the node.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: Plugins: `bookkeeper` now explicitly assumes every transaction is in the same currency as the node (true unless you added manually)
2025-08-14 19:49:09 +09:30
Rusty Russell
47c2735e17 bkpr: remove currency support from balances.
We're going to get rid of this concept, but the main change is that the
account_get_balance API can be drastically simplified:

account_get_credit_debit() accesses the raw fields, never fails, but
returns the a flag which tells us if the account doesn't actually have
any events.

The one place we care about the balance, calculate by hand.  Then
account_get_balance() (and struct account_balance) can simply be
moved to th test.

Subtly, without the "GROUP BY" clause, you always get one row, even if
there are no rows (but the SUM are null).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-14 19:49:09 +09:30
Rusty Russell
0c9dc4cf07 bkpr: remove unused "account_exits" parameter to account_get_balance().
Only used in tests.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-14 19:49:09 +09:30
Rusty Russell
b0231a59d8 common: put "external" and "wallet" strings, and test functions into common/coin_mvt.h
They're scattered and reproduced in many places: unify them.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-14 19:49:09 +09:30
Rusty Russell
841a8bd03a lightningd: extract core of coin_movement notification, for use in list functions.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Deprecated: JSON-RPC: `coin_movement` notification `utxo_txid`, `vout` and `txid` fields (use `utxo` and `spending_txid`).
Changelog-Added: JSON-RPC: `coin_movement` notification `utxo` field.
Changelog-Added: JSON-RPC: `coin_movement` notification `spending_txid` field.
2025-08-14 19:49:09 +09:30
Rusty Russell
650f3882dd lightningd: separate coin_movement tags array into primary_tag and extra_tags.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Deprecated: JSON-RPC: `coin_movement` notification `tags` array (use `primary_tag` and `extra_tags`).
Changelog-Added: JSON-RPC: `coin_movement` notification `primary_tag` and `extra_tags`.
2025-08-14 19:49:09 +09:30
Rusty Russell
5756b54f38 common: rename enum mvt_tag values.
Prefix MVT_ to them, for clarity.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-14 19:49:09 +09:30
Rusty Russell
6fc0b1f3d1 common/coin_mvt: add struct mvt_account_id to separate channels from others.
This means we can keep a pointer to the channel directly, *or* a string.
This avoids gratuitous formatting (on creation) and lookups (later).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-14 19:49:09 +09:30
Rusty Russell
b8b1d45ddc db: hand amount_msat / amount_sat by copy, not pointer.
This is how we handle amount_msat and amount_sat everywhere these days, and this
wasn't updated.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-14 19:49:09 +09:30