For old channels, this can take a while, and it stops everything. But
we are only doing this to save space; it's not a *functional* necessity.
A quick and dirty test with 50,000 htlcs shows the htlc deletion took
450msec. I tried adding an index, and changing it to set hstate to
HTLC_STATE_INVALID instead of deleting entries, but it still took about 350ms.
Whereas the "COUNT(*)" only took 1.7msec, so it's worth keeping.
Reported-by: @michael1011
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Changed: lightningd: we defer deletion of old htlcs on channel close, to avoid pausing for a long time (we clean them on startup)
Fixes: https://github.com/ElementsProject/lightning/issues/7962
* tests/test_cln_lsps.py::test_lsps0_listprotocols
* tests/test_clnrest.py
* tests/test_connection.py::test_wss_proxy
Changelog-Fixed: pytest: Tests that require Rust no longer fail if Rust is disabled.
In this case, we make an immediately-expiring invoice. This correctly blocks
any successive requests for invoices, as per the spec requirement.
This means we have to handle invoice_requests without reply_path, amounts
or quantity *if* they specify invreq_recurrence_cancel.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
We added this to the recurrence spec: the offer expiration only applies to the
first request, not subsequent ones.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changes:
* Fields renumbered to their draft values + billion.
* offer_recurrence now comes in compulsory or optional (backwards compat) flavors.
* `proportional_amount` is now inside `offer_recurrence_base` not `offer_recurrence_paywindow`.
* New field `invreq_recurrence_cancel`.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-EXPERIMENTAL: Draft specification for recurring offers changed: old recurring offers will no longer work.
Offer_absolute_expiry should be used if you want to require starting at the start.
Changelog-EXPERIMENTAL: Protocol: BOLT 12 recurrence `start_any_period` removed, use expiry if you need to restrict when they can start using the offer.
openingd sends an ERROR, and exits. lightningd tells us to
disconnect. We read from lightningd first, and don't read from
openingd.
We need to drain subds when we're told to disconnect.
One issue we have in CI is reconnection races: if an incoming
connection arrives while an outgoing one is negotiated, we close the
outgoing one and issue a disconnect, which fails any connect attempts.
By sending a "reconnected" message instead of disconnect/connect we
can avoid disturbing in-progress connection attempts which happens in CI
quite a bit.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Something changed in Matt's example:
error: {'code': -32700, 'data': None, 'message': 'failed to fetch payment instructions: HrnResolutionError("Multiple TXT records existed for the HRN, which is invalid")'}
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1. Establish a channel with l3; we already have one with l2.
2. Don't bother generating 6 more blocks (fundchannel ensures it's mined).
3. Allow htlcs to be empty: Whitslack reported that happens for him
4. Use only_one() to access where we insist there is only one element in the list.
5. Tighten tests to assert the exact contents, not just test some.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Fixes: https://github.com/ElementsProject/lightning/issues/8497
DER sigs! Normally, the commitment weight is:
```
Anchorspend for local commit tx fee 9751sat (w=722), commit_tx fee 4866sat (w=1284): package feerate 7286 perkw
Creating anchor spend for local commit tx 6a0816ca60d499edc70bfb786ebd164fb7a55d234c84d926102f5bd35087fd45: we're paying fee 9751sat
```
But if we're "lucky" the commitment tx is shorter:
```
Anchorspend for local commit tx fee 9744sat (w=722), commit_tx fee 4866sat (w=1283): package feerate 7286 perkw
Creating anchor spend for local commit tx acf78532a9448dd62a4e6319a3d2712189a88b6e59abc637260067d60df70782: we're paying fee 9744sat
```
The resulting failure:
```
2025-08-21T02:30:34.1906751Z > assert moves == expected
...
...
2025-08-21T02:30:34.1965346Z E {
2025-08-21T02:30:34.1965529Z E 'account_id': 'wallet',
2025-08-21T02:30:34.1965767Z E 'blockheight': 104,
2025-08-21T02:30:34.1965997Z E 'created_index': 6,
2025-08-21T02:30:34.1966229Z E - 'credit_msat': 15579000,
2025-08-21T02:30:34.1966467Z E ? ^^
2025-08-21T02:30:34.1966698Z E + 'credit_msat': 15586000,
2025-08-21T02:30:34.1966927Z E ? ^^
2025-08-21T02:30:34.1967150Z E 'debit_msat': 0,
2025-08-21T02:30:34.1967376Z E 'extra_tags': [],
2025-08-21T02:30:34.1967599Z E - 'output_msat': 15579000,
2025-08-21T02:30:34.1967832Z E ? ^^
2025-08-21T02:30:34.1968061Z E + 'output_msat': 15586000,
2025-08-21T02:30:34.1968294Z E ? ^^
2025-08-21T02:30:34.1968540Z E 'primary_tag': 'deposit',
2025-08-21T02:30:34.1968908Z E 'utxo': 'acf78532a9448dd62a4e6319a3d2712189a88b6e59abc637260067d60df70782:0',
2025-08-21T02:30:34.1969366Z E },
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Don't test installing a plugin under valgrind. There's no way to
increase reckless' (completely reasonable) 15 seconds timeout, and that
can happen under valgrind & CI:
```
def test_reckless_uv_install(node_factory):
node = get_reckless_node(node_factory)
node.start()
r = reckless([f"--network={NETWORK}", "-v", "install", "testpluguv"],
dir=node.lightning_dir)
> assert r.returncode == 0
E assert 1 == 0
E + where 1 = self.returncode, self.stdout, self.stderr.returncode
tests/test_reckless.py:359: AssertionError
...
***RECKLESS STDERR***
config file not found: /tmp/ltests-tui1vmrg/test_reckless_uv_install_1/lightning-1/regtest/config
press [Y] to create one now.
config file not found: /tmp/ltests-tui1vmrg/test_reckless_uv_install_1/lightning-1/reckless/regtest-reckless.conf
config file not found: /tmp/ltests-tui1vmrg/test_reckless_uv_install_1/lightning-1/reckless/.sources
Traceback (most recent call last):
File "/home/runner/work/lightning/lightning/tools/reckless", line 2091, in <module>
log.add_result(args.func(target))
File "/home/runner/work/lightning/lightning/tools/reckless", line 1524, in install
return _enable_installed(installed, plugin_name)
File "/home/runner/work/lightning/lightning/tools/reckless", line 1476, in _enable_installed
if enable(installed.name):
File "/home/runner/work/lightning/lightning/tools/reckless", line 1647, in enable
lightning_cli('plugin', 'start', path)
File "/home/runner/work/lightning/lightning/tools/reckless", line 1613, in lightning_cli
clncli = run(cmd, stdout=PIPE, stderr=PIPE, check=False, timeout=timeout)
File "/opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/subprocess.py", line 505, in run
stdout, stderr = process.communicate(input, timeout=timeout)
File "/opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/subprocess.py", line 1154, in communicate
stdout, stderr = self._communicate(input, endtime, timeout)
File "/opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/subprocess.py", line 2022, in _communicate
self._check_timeout(endtime, orig_timeout, stdout, stderr)
File "/opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/subprocess.py", line 1198, in _check_timeout
raise TimeoutExpired(
subprocess.TimeoutExpired: Command '['/home/runner/work/lightning/lightning/cli/lightning-cli', '--network=regtest', '--lightning-dir=/tmp/ltests-tui1vmrg/test_reckless_uv_install_1/lightning-1', 'plugin', 'start', '/tmp/ltests-tui1vmrg/test_reckless_uv_install_1/lightning-1/reckless/testpluguv/testpluguv.py']' timed out after 15 seconds
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Change in the fuzzing scheme of fuzz-bech32 led to the
discovery of test inputs that result in greater in code
coverage. Add these inputs to the test's seed corpus.
According to `common/bech32.h`, the valid values of witness
program version are between 0 and 16 (inclusive). Update the
test to iterate over all of these values.
Changelog-None: Use the common library utilities for temporary
allocations instead of manually calling `malloc` and `free`.
This makes the code conformant with rest of the codebase and
reduces the chances of leaks.
Change in the fuzzing scheme of `fuzz-close_tx` led to the
discovery of test inputs that result in greater in code
coverage. Add these inputs to the test's seed corpus.
Changelog-None: The value WALLY_SATOSHI_PER_BTC * WALLY_BTC_MAX
is equal to 2.1e15, which is much higher than the maximum capacity
of a u32, which is 4.29e9.
Hence, use a u64 to store this value instead.
Improvements in the fuzz-testing scheme of `fuzz-channel_id led
to the discovery of test inputs that result in greater in code
coverage. Add these inputs to the test's seed corpus.
Changelog-None: `memcmp()` the output of `towire_channel_id()`
and the input to `fromwire_channel_id()` to ensure that wire
encoding-decoding is correctly performed.
Change in the fuzzing scheme of `fuzz-bolt11` led to the
discovery of test inputs that result in greater in code
coverage. Add these inputs to the test's seed corpus.
Changelog-None: `handle_peer_error_or_warning()` in
`common/read_peer_message.{c, h}` is responsible for parsing any
incoming `error` or `warning` messages as defined in BOLT #1.
Add a test for it.
The FUZZ_COMMON_OBJS list roughly follows lexicographic
order. Make it adhere strictly to the order. This makes adding
and reviewing changes to the file easier.
Improvements in the fuzz-testing scheme of fuzz-bigsize led
to the discovery of test inputs that result in greater in
code-coverage. Add these inputs to the test's seed corpus.
Add a roundtrip check for `bigsize_put()` using `bigsize_get()`.
This enforces a stricter check for the former and adds a test
for the latter, which is currently untested.
Changelog-None: The exisiting fuzz test only extracts chunks of
a fixed size (8) from the fuzzer's input. Replace this with an
iteration over a set of chunk sizes (1 to BIGSIZE_MAX_LEN) for
better coverage.
While at it, get rid of the check `if (bs != 0)` because 0 is a
valid value for bigsize_t as well.
Change in the fuzz-testing scheme of fuzz-addr led to the
discovery of test inputs that result in greater in code
coverage. Add these inputs to the test's seed corpus.
Changelog-None: Currently, fuzz-addr only tests encoding via
encode_scriptpubkey_to_addr(), without checking decoding. Add a
round‑trip assertion: if encoding produces an address, decode
it back with decode_scriptpubkey_from_addr() and confirm the
result matches the original scriptpubkey.
Changelog-None: 'closing_signed' and 'closing_sig' are
channel closing negotiation messages defined in BOLT #2.
While 'closing_signed' has a wire fuzz test, 'closing_sig'
does not. Add a test to perform a round-trip encoding check
(towire -> fromwire) similar to the other wire fuzzers.