Commit Graph

121 Commits

Author SHA1 Message Date
Rusty Russell
873d4102c8 bookkeeper: restore limit on asking for all channelmoves at once.
Now we've found all the issues, the latency spike (4 seconds on my laptop)
for querying 2M elements remains.

Restore the limited sampling which we reverted, but make it 10,000 now.

This doesn't help our worst-case latency, because sql still asks for all 2M entries on
first access.  We address that next.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-20 16:30:50 +10:30
Rusty Russell
673729bdb9 Revert "bookkeeper: don't flood logs if we have many channelmoves all at once."
This reverts commit 1dda0c0753 so we can test
what its like to be flooded with logs again.

This benefits from other improvements we've made this release, to handling
plugin input (i.e. converting to use common/jsonrpc_io), so this doesn't
make much difference.

tests/test_coinmoves.py::test_generate_coinmoves (100,000, sqlite3):
	Time (from start to end of l2 node):	211 seconds
	Worst latency:				108 seconds

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-20 16:30:50 +10:30
Rusty Russell
2f2eacaac7 bookkeeper: no longer read listchannelmoves 1000 entries at a time.
This reverts `bookkeeper: only read listchannelmoves 1000 entries at a time.` commit,
so we can properly fix the scalability in the coming patches.

tests/test_coinmoves.py::test_generate_coinmoves (100,000):
	Time (from start to end of l2 node):	207 seconds
	Worst latency:				106 seconds

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-20 16:30:50 +10:30
Rusty Russell
ef5a9bd0de bookkeeper: fix printing of bad JSON results.
I noticed this in the logs:

```
listinvoices: description/bolt11/bolt12 not found (

{"jsonrpc":"2)
```

And we make the same formatting mistake in several places.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-20 16:30:50 +10:30
Rusty Russell
8b9020d7b9 global: use clock_time in place of time_now().
Except for tracing, that sticks with time_now().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-11-13 21:21:29 +10:30
Rusty Russell
1dda0c0753 bookkeeper: don't flood logs if we have many channelmoves all at once.
Since we're synchronous, these only reach lightningd after we're done:
in the case of 1.6M channelmoves, that can give it major heartburn.

In practice, this reduces the first bkpr command on a fresh upgrade
from 349 to 235 seconds (but this was before other improvements we did
this release).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: Plugins: `bookkeeper` reduced logging for large imports to increase speed.
2025-11-04 12:47:37 +10:30
Rusty Russell
bd1798323a bookkeeper: fix assert() which happens with parallel queries.
```
bookkeeper: plugins/bkpr/bookkeeper.c:1226: parse_and_log_chain_move: Assertion `e->db_id > bkpr->chainmoves_index' failed.
bookkeeper: FATAL SIGNAL 6 (version v25.09-245-g901714b-modded)
0x5d7d8718b40f send_backtrace
        common/daemon.c:36
0x5d7d8718b4ab crashdump
        common/daemon.c:81
0x7a6086c4532f ???
        ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0
0x7a6086c9eb2c __pthread_kill_implementation
        ./nptl/pthread_kill.c:44
0x7a6086c9eb2c __pthread_kill_internal
        ./nptl/pthread_kill.c:78
0x7a6086c9eb2c __GI___pthread_kill
        ./nptl/pthread_kill.c:89
0x7a6086c4527d __GI_raise
        ../sysdeps/posix/raise.c:26
0x7a6086c288fe __GI_abort
        ./stdlib/abort.c:79
0x7a6086c2881a __assert_fail_base
        ./assert/assert.c:96
0x7a6086c3b516 __assert_fail
        ./assert/assert.c:105
0x5d7d8717505d parse_and_log_chain_move
        plugins/bkpr/bookkeeper.c:1226
0x5d7d871754f4 listchainmoves_done
        plugins/bkpr/bookkeeper.c:169
0x5d7d87182a4b handle_rpc_reply
        plugins/libplugin.c:1072
0x5d7d87182b5c rpc_conn_read_response
        plugins/libplugin.c:1361
0x5d7d871ba660 next_plan
        ccan/ccan/io/io.c:60
0x5d7d871bab31 do_plan
        ccan/ccan/io/io.c:422
0x5d7d871babee io_ready
        ccan/ccan/io/io.c:439
```

Reported-by: @michael1011
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: plugins: assertion crash in bookkeeper when fresh records arrive while multiple queries in progress.
2025-11-03 14:03:25 +10:30
Rusty Russell
f6a4e79420 global: remove unnecessary includes from headers.
Each header should only include the other headers it needs to compile;
`devtools/reduce-includes.sh */*.h` does this.  The C files then need
additional includes if they don't compile.

And remove the entirely useless wire/onion_wire.h, which only serves to include wire/onion_wiregen.h.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-10-23 06:44:04 +10:30
Rusty Russell
e522aedc94 bookkeeper: only read listchannelmoves 1000 entries at a time.
If we read all of them, we might get 1.6M at once (after initial
migration).  Then we submit a few hundred thousand simultaneous
requests to lightningd, and it gets upset, queueing them all on the
xpay command hook and running out of memory.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: plugins: bookkeeper first invocation after migration from prior to 25.09 with very large databases will not crash.
2025-10-20 11:19:22 +10: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
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
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
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
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
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
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
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
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
0534c524b5 common: remove "ignored" tag.
We don't actually set it any more.  The bookkeeper db does a migration
for old anchors.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2025-08-14 19:49:09 +09:30
evansmj
edc0eb6473 bkpr: add examples for new edit description RPC calls 2024-11-12 09:46:09 +10:30
niftynei
2b4b91ff5c bkpr: add new RPC bkpr-editdescriptionbyoutpoint
Given an {outpoint}, sets the description on the matching outpoint (if exists).

Note that if no outpoint exists in bookkeeper, will return an empty list

Changleog-Added: PLUGINS: bookkeeper has a new RPC `bkrp-editdescriptionbyoutpoint` which will set/update a description for an outpoint creation event.
2024-11-12 09:46:09 +10:30
niftynei
a61b7ef347 bkpr: add new json RPC "bkpr-editdescriptionbypaymentid"
This takes an {payment_id} and {description}.
It looks for all chain + channel events that match
that {payment_id} and updates the description for those events.

We return all the updated events. If no events are updated, an empty
list is returned.

Changelog-Added: PLUGINS: bookkeeper has a new RPC `bkpr-editdescriptionbypaymentid` which will update the description for any event with matching payment_id
2024-11-12 09:46:09 +10:30
niftynei
4a6e014213 bkpr: refactor out the add_events logic for json stuff 2024-11-12 09:46:09 +10:30
Rusty Russell
c797b6fb20 libplugin: add method string to jsonrpc callbacks, implement generic helpers.
Without knowing what method was called, we can't have useful general logging
methods, so go through the pain of adding "const char *method" everywhere,
and add:

1. ignore_and_complete - we're done when jsonrpc returned
2. log_broken_and_complete - we're done, but emit BROKEN log.
3. plugin_broken_cb - if this happens, fail the plugin.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2024-11-07 17:04:35 +10:30
Rusty Russell
c5099b1647 libplugin: clean up API.
When we used to allow cmd to be NULL, we had to hand the plugin
everywhere.  We no longer do.

1. Various jsonrpc_ functions no longer need the plugin arg.
2. send_outreq no longer needs a plugin arg.
3. The init function takes a command, not a plugin.
4. Remove command_deprecated_in_nocmd_ok.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2024-11-07 17:04:35 +10:30
Rusty Russell
c85dd95c12 libplugin: tell compiler that plugin_err is like printf.
And fix the fallout!

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2024-11-07 17:04:35 +10:30
Rusty Russell
1362448352 common/bolt12: do more required checks in invoice_decode.
Rather than making the callers do this, make the invoice decoder perform
the various sanity checks.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2024-09-19 12:16:53 +09:30
Rusty Russell
679f46f733 common/amount: rename amount_sat_zero/amount_msat_zerp -> amount_sat_is_zero/amount_msat_is_zero.
I used `amount_msat_eq(x, AMOUNT_MSAT(0))` because I forgot this
function existed.  I probably missed it because the name is surprising,
so add "is" in there to make it clear it's a boolean function.

You'll note almost all the places which did use it are Eduardo's and
Lisa's code, so maybe it's just me.

Fix up a few places which I could use it, too.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2024-09-19 12:16:53 +09:30