Commit graph

2460 commits

Author SHA1 Message Date
enaples
6175642e72 currencyrate: round to the third digit and adding source argument to currencyrate command
Changelog-None
2026-05-11 15:06:41 +02:00
Lagrang3
bd71651b3c xpay: add sendamount command
Changelog-Added: sendamount command, to make a payment specifying the desired amount to send instead of the amount to be received.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 20:29:39 +09:30
Rusty Russell
ae956f2a7b xpay: fix taken leak if we fail xpay_core early.
This was uncovered by a test in the next commit.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 20:29:39 +09:30
Lagrang3
1f55feec4a xpay: add a special offer payable condition ...
that only applies to sendamount payments (includefees flag on).

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 20:29:39 +09:30
Lagrang3
c9f16f3cc8 xpay: add helper to fetch the MPP amount ...
for the final hop payload, which for normal xpay payments is known in
advanced but not for sendamount payments (includefees flag on).

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 20:29:39 +09:30
Lagrang3
9813232450 xpay: add flag for "includefees"
Add an includefees flag to payment to indicate the desire for this
payment to be a "send amount" kind instead of "receive amount".

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 20:29:39 +09:30
Lagrang3
a012c4d1ef xpay: add helper for payment deliver
Don't assume that payment->amount means the desired delivery amount.
Use a helper instead when we need that.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 20:29:39 +09:30
Lagrang3
fee5eb4c2f xpay: add payment MPP amount variable
Change the name of payment->full_amount to payment->mpp_amount,
to make clear that this refers to the value needed in the last
hop payload for MPP payments to coordinate.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 20:29:39 +09:30
Lagrang3
5b0dcb9f53 xpay: attempt amount could have different meanings
Change the name of attempt->deliver to attempt->amount,
do not assume that amount is the "desired delivery", since it might be
the "desired send" depending on the payment context.

Use helpers to get the fees and deliver amount from an attempt.

Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 20:29:39 +09:30
Lagrang3
902242b0eb askrene: askrene-remove-channel-update
Changelog-Added: askrene: askrene-remove-channel-update, a new RPC to remove channel_update entries from layers.

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 16:16:57 +09:30
Vincenzo Palazzo
1c5e632994 fix: release txprepare reservations on send failure
Clean up the original PSBT reservation when withdraw/txsend fail after signing or broadcast.

Include the final withdraw regression coverage, including the liquid-safe address handling needed for CI.

Fixes #8925
2026-05-11 15:54:55 +09:30
Sangbida Chaudhuri
c3d4ae3cfc bwatch: gate chain polling behind --experimental-bwatch
The plugin still loads (so its options and RPCs stay registered) but
stays inert — no chain polling, no watch replay — unless the user
explicitly opts in with --experimental-bwatch.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
3b73db585e bwatch: notify watch owners on reorg
When bwatch removes its tip block on a reorg, fire watch_revert for
the affected owners so lightningd-side handlers actually run.

Two cases, depending on whether the watch has an anchor block:

  - scriptpubkey watches have no anchor (a wallet address can receive
    funds in any block), so notify every owner on every removed block.
    Handlers are cheap and defensive — they check their own state and
    no-op if there is nothing to undo.

  - outpoint, scid, and blockdepth watches each carry a start_block.
    Notify only those with start_block >= removed_height (the watch's
    anchor is gone).  Older watches stay armed and refire naturally on
    the new chain.

Owners are snapshotted before dispatch so revert handlers can safely
call watchman_unwatch_* and mutate the watch tables.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
9af6b3761e bwatch: trigger rescan when a watch is added behind tip
bwatch_add_watch returns the watch it created (or found); each
addwatch RPC now passes that into add_watch_and_maybe_rescan,
which:

  - returns success immediately if start_block > current_height
    (the watch only cares about future blocks), and
  - otherwise calls bwatch_start_rescan over
    [start_block, current_height] for that one watch and leaves
    the RPC pending until the rescan completes.

This lets callers add a watch for an event that already confirmed
(e.g. a channel funding tx some blocks back) and still get a
watch_found.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
acc0b66711 bwatch: add rescan engine for historical blocks
bwatch_start_rescan(cmd, w, start_block, target_block) replays
blocks from start_block..target_block for a single watch w (or
for all watches if w is NULL).

The rescan runs asynchronously: fetch_block_rescan ->
rescan_block_done -> next fetch, terminating with rescan_complete
(which returns success for an RPC-driven rescan and aux_command_done
for a timer-driven one).

Nothing calls bwatch_start_rescan yet; the add-watch RPCs wire it
up next.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
852ed1ab39 bwatch: thread per-watch parameter through block scanning
To support rescans (added next), bwatch_process_block_txs and
bwatch_check_scid_watches gain a `const struct watch *w` parameter
so the caller can ask the scanner to check just one watch instead
of all of them.

When a new watch is added with start_block <= current_height (say
the watch starts at block 100 but bwatch is already at 105) we
need to replay blocks 100..105 for that watch alone — not re-scan
every active watch over those blocks.

  w == NULL  -> check every active watch (normal polling)
  w != NULL  -> check only that one watch (rescan)
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
32333bc086 bwatch: add listwatch RPC
listwatch returns every active watch as a flat array. Each entry
carries its type-specific key (scriptpubkey hex, outpoint, scid
triple, or blockdepth anchor) plus the common type / start_block /
owners fields, so callers can dispatch on the per-type key without
parsing the type string first.

Mostly used by tests and operator tooling to inspect what bwatch
is currently tracking.

Changelog-Added: Plugins: bwatch exposes listwatch RPC.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
5bb206dd74 bwatch: add blockdepth watch RPCs
addblockdepthwatch and delblockdepthwatch are how lightningd asks
bwatch to start/stop a depth-tracker for a given (owner, start_block).
start_block doubles as the watch key and the anchor used to compute
depth = tip - start_block + 1 on every new block.

Changelog-Added: Plugins: bwatch exposes addblockdepthwatch / delblockdepthwatch RPCs.
Made-with: Cursor
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
0a5360d11f bwatch: add scid watch RPCs
addscidwatch and delscidwatch are how lightningd asks bwatch to
start/stop watching a specific short_channel_id for a given owner.
The scid pins the watch to one (block, txindex, outnum), so on each
new block we go straight to that position rather than scanning.

Changelog-Added: Plugins: bwatch exposes addscidwatch / delscidwatch RPCs.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
6ed4be67fb bwatch: add outpoint watch RPCs
addoutpointwatch and deloutpointwatch are how lightningd asks bwatch
to start/stop watching a specific (txid, outnum) for a given owner.

Changelog-Added: Plugins: bwatch exposes addoutpointwatch / deloutpointwatch RPCs.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
64cd3fedd2 bwatch: add scriptpubkey watch RPCs
addscriptpubkeywatch and delscriptpubkeywatch are how lightningd asks
bwatch to start/stop watching an output script for a given owner.

Changelog-Added: Plugins: bwatch exposes addscriptpubkeywatch / delscriptpubkeywatch RPCs.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
100805d9ae bwatch: send chaininfo to watchman on startup
On init, query bcli for chain name, headercount, blockcount and IBD
state, then forward the result to watchman via the chaininfo RPC
before bwatch starts its normal poll loop. Watchman uses this to
gate any work that depends on bitcoind being synced.

If bitcoind's blockcount comes back lower than our persisted tip,
peel stored blocks off until they line up so watchman gets a
consistent picture. During steady-state polling the same case is
handled by hash-mismatch reorg detection inside handle_block; this
shortcut only matters at startup, before we've fetched anything.

If bcli or watchman is not yet ready, log and fall back to scheduling
the poll loop anyway so init never stalls.

bwatch_remove_tip is exposed in bwatch.h so the chaininfo path in
bwatch_interface.c can use it.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
b5c5fe4b41 bwatch: fire blockdepth notifications per block
Subdaemons like channel_open and onchaind care about confirmation
depth, not the underlying tx. Walk blockdepth_watches on every new
block and send watch_found with the current depth to each owner.

This is what keeps bwatch awake in environments like Greenlight,
where we'd otherwise prefer to hibernate: as long as something is
waiting on a confirmation milestone, the blockdepth watch holds the
poll open; once it's deleted, we're free to sleep again.

Depth fires before the per-tx scan so restart-marker watches get a
chance to spin up subdaemons before any outpoint hits land for the
same block. Watches whose start_block is ahead of the tip are stale
(reorged-away, awaiting delete) and skipped.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
8eccae35dd bwatch: scan blocks for scid matches
After the per-tx scriptpubkey/outpoint pass, walk every scid watch and
fire watch_found for any whose encoded blockheight matches the block
just processed.

The watch's scid encodes the expected (txindex, outnum), so we jump
straight there without scanning. If the position is out of range
(txindex past the block, or outnum past the tx) we send watch_found
with tx=NULL, which lightningd treats as the "not found" case.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
4f12b48a6d bwatch: scan blocks for scriptpubkey and outpoint matches
After every fetched block, walk each transaction and fire watch_found
for matching scriptpubkey outputs and spent outpoints.

Outputs are matched by hash lookup against scriptpubkey_watches; inputs
by reconstructing the spent outpoint and looking it up in
outpoint_watches.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
34d8c6fef0 bwatch: add watch_found and watch_revert notifications
Add two RPCs for surfacing watches to lightningd on a new block or
reorg.

bwatch_send_watch_found informs lightningd of any watches that were
found in the current processed block.  The owner is used to
disambiguate watches that may pertain to multiple subdaemons.

bwatch_send_watch_revert is sent in case of a revert; it informs the
owner that a previously reported watch has been rolled back.

These functions get wired up in subsequent commits.

Made-with: Cursor
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
65c92ec330 bwatch: detect reorgs and roll back tip
When handle_block fetches the next block, validate its parent hash
against our current tip. If they disagree we're seeing a reorg: pop our
in-memory + persisted tip via bwatch_remove_tip, walk the history one
back, and re-fetch from the new height. Each fetch may itself reorg
further, so the loop naturally peels off as many stale tips as needed
until the chain rejoins.

After every rollback, tell watchman the new tip via
revert_block_processed so its persisted height tracks bwatch's. If we
crash before the ack lands, watchman's stale height will be higher than
ours on restart, which retriggers the rollback.

If the rollback exhausts our history (we rolled back past the oldest
record we still hold) we zero current_height/current_blockhash and let
the next poll re-init from bitcoind's tip.

Notifying owners that their watches were reverted lands in a subsequent
commit.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
e8a1694815 bwatch: notify watchman on block_processed
After bwatch persists a new tip, send a block_processed RPC to watchman
(lightningd) with the height and hash. bwatch only continues polling
for the next block once watchman has acknowledged that it has also
processed the new block height on its end.

This matters for crash safety: on restart we treat watchman's height as
the floor and re-fetch anything above it, so any block we acted on must
be visible to watchman before we move on.

If watchman isn't ready yet (e.g. lightningd still booting) the RPC
errors out non-fatally; we just reschedule and retry.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
591a57b285 bwatch: poll chain and append blocks
Add the chain-polling loop. A timer fires bwatch_poll_chain, which calls
getchaininfo to learn bitcoind's tip; if we're behind, we fetch the next
block via getrawblockbyheight, append it to the in-memory history and
persist it to the datastore. After each successful persist we reschedule
the timer at zero delay so we keep fetching back-to-back until we catch
up to the chain tip. Once getchaininfo reports no new block, we settle
into the steady-state cadence (30s by default, tunable via the
--bwatch-poll-interval option).

This commit only handles the happy path. Reorg detection, watchman
notifications and watch matching land in subsequent commits.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
5371cfab6f bwatch: add addwatch/delwatch helpers
bwatch_add_watch and bwatch_del_watch are the high-level entry points
the RPCs (added in a later commit) use. Adding a watch that already
exists merges the owner list and lowers start_block if the new request
needs to scan further back, so a re-registering daemon (e.g. onchaind
on restart) doesn't lose missed events. Removing a watch drops only
the requesting owner; the watch itself is removed once the owner list
is empty.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
ef8b11e441 bwatch: persist watches
Each watch (and its set of owners) is serialized through the wire
format from the earlier commit and stored in the datastore. On startup
we walk each type's prefix and reload the watches into their
respective hash tables, so a restart resumes watching the same things
without anyone re-registering.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
aaffcc8bd6 bwatch: persist block history
bwatch keeps a tail of recent blocks (height, hash, prev hash) so it
can detect and unwind reorgs without re-fetching from bitcoind. The
datastore key for each block is zero-padded to 10 digits so
listdatastore returns blocks in ascending height order. On startup
we replay the stored history and resume from the most recent block.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
ca2e79ff8f bwatch: add typed hash tables for watches
We have 4 types of watches: utxo (outpoint), scriptpubkey, scid and
blockdepth. Each gets its own hash table with a key shape that makes
lookups direct.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
02e0df876a bwatch: add wire format
This wire file primarily contains datastructures that is used to serialize data for storing in the datastore. We have 2 types of datastores for bwatch.
The block history datastore and the watch datastore. For block history we store height, the hash and the hash of the previous block.
For watches we have 4 types of watches - utxo, scriptpubkey, scid and blockdepth watches, each of these have their unique info stored in the datastore. The common info for all watches includes the start block and the list of owners interested in watching.
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
764e81d55b bwatch: add skeleton and makefile
bwatch is an async block scanner that consumes blocks from bcli or any
other bitcoind interface and communicates with lightningd by sending
it updates. In this commit we're only introducing the plugin and some
files that we will populate in future commits.

Changelog-Added: bwatch plugin, this is to handle block processing outside of lightningd. Not yet hooked up to lightningd.
2026-05-11 15:51:05 +09:30
Rusty Russell
9c07b985e2 common: extract param_string_array from xpay into common.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 15:51:05 +09:30
Sangbida Chaudhuri
2dd780c9f0 common: expose json_hex_to_be32/be64
These helper functions decode hex strings from JSON into big-endian 32-bit and 64-bit values, useful for parsing datastore entries exposing these into a more common space so they can be used by bwatch in the future.
2026-05-11 15:51:05 +09:30
Rusty Russell
c1b428a759 libplugin: expose json_add_keypath.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 15:51:05 +09:30
Lagrang3
2346d3792c xpay: config option xpay-user-layer
This option allow user to configure xpay to always use the layers
specified.

Changelog-Added: xpay: config option xpay-user-layer

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 15:43:30 +09:30
Lagrang3
03e5d22a95 libplugin: add helpers for multi-string options
Changelog-None

Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
2026-05-11 15:43:30 +09:30
Rusty Russell
6eb7dc0428 renepay: deprecate.
I think Eduardo and I stole all the best bits to make xpay and askrene.

I simply enabled deprecations on all the renepay tests.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 13:51:52 +09:30
Rusty Russell
ed42adc9e4 plugins: move listpays from pay plugin to xpay plugin.
This will make life easier when we remove the pay plugin, but also fixes
an issue where `listpays` can indicate ongoing payments are failed,
even though xpay is still working on it.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 13:51:52 +09:30
Rusty Russell
560b016584 xpay: keep track of ongoing payments, to implement attempt_ongoing()
This will help when we implement listpays (next) to be xpay-aware.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 13:51:52 +09:30
Rusty Russell
98315531fa keysend: deprecate in favor of xkeysend.
Changelog-Deprecated: JSON-RPC: `keysend` (use `xkeysend`).  `xkeysend` will take over `keysend` in v27.03.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 13:51:52 +09:30
Rusty Russell
e657552058 getroute: deprecate in favor of getroutes
Changelog-Deprecated: JSON-RPC: `getroute` (use `getroutes` with layers `["auto.localchans","auto.sourcefree"]` and `maxparts=1`) (since v25.09).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 13:51:52 +09:30
Rusty Russell
eebc6eea00 pay: deprecate pay and paystatus.
Use xpay and listpays.

Some tests which are pay/paystatus specific simply enabled deprecations.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Deprecated: JSON-RPC: `pay` and `paystatus`: use `xpay`, `listpays` (or `xpay`'s notifications for details of attempts).  `pay` will be replaced by `xpay` in v27.03.
2026-05-11 13:51:52 +09:30
Rusty Russell
68d700c609 pay: accept invstring as first parameter name.
If you don't use complex pay options, you can use `invstring` now and when xpay
becomes pay, there's no transition.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: JSON-RPC: `pay` now accepts `invstring` as a parameter name for `bolt11`, to ease transition when xpay takes over in v27.03.
2026-05-11 13:51:52 +09:30
Rusty Russell
afea38138d xpay: take over pay invocations by default.
The main change here is the error messages got better.  Where that was
the case, and the test was not completely redundant with existing xpay
tests, I explicitly converted to calls to xpay (meaning the tests
will be kept when `pay` is finally removed).

Test changes:
1. deschash checking is old-pay only, keep that there.
2. Add debug logs for checks for using forwarding via scid in injectpaymentonion.
3. Don't assert that not all sendpays should have the invoice string: xpay does not try to be clever there.
4. We no longer check if invoices are already paid before routing, since injectpaymentonion will catch that for us.
5. Removed `test_pay_get_error_with_update` which has xpay equiv.

Changelog-Changed: JSON-RPC: `xpay` now handles `pay` command by default (use `xpay-handle-pay=false` to prevent this)
Changelog-Removed: JSON-RPC: `exclude` parameter to `pay` (when `xpay-handle-pay` is True): craft a layer with desired modifications and pass it to `xpay` `layers`.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 13:51:52 +09:30
Rusty Russell
a488711de3 offers: use xpay.
Changelog-Changed: offers: we now use `xpay` not `pay` for paying invoices made with invoicerequest().
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 13:51:52 +09:30
Rusty Russell
78721c7fcb xpay: add xkeysend support.
This uses askrene, so it benefits from previous payment experience.

Changelog-Added: JSON-RPC: `xkeysend` command for keysend with modern routing support.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2026-05-11 13:51:52 +09:30