Update to upstream v26.06.8 - #13
Merged
Merged
Conversation
When a block containing a non-tip inflight's funding tx was processed, dual_funding_found set the channel's scid right away, but the channel's funding fields were only updated to the mined inflight once block catch-up completed (opening_depth_cb, via the blockdepth watches). A peer reconnecting inside that window reestablished against channel_current_inflight() -- the latest inflight -- with the scid already set, so dualopend sent channel_ready and the channel locked in a funding tx that was never mined: its last_tx spends a nonexistent outpoint, and the two peers disagree about the channel's funding. Record the mined inflight on the channel as soon as its block is seen, and make peer_restart_dualopend reestablish with the inflight matching the recorded funding when the scid is already set. Fixes: ElementsProject#9373 Changelog-Fixed: Protocol: dual-funding: reconnecting during block catch-up could lock in a channel with the latest RBF candidate rather than the one that was actually mined.
test_rbf_non_last_mined occasionally fails in CI when the peer reconnects while the node is still catching up on blocks (ElementsProject#9373). Reproduce that window deterministically: stall the fetch of the block after the funding block via the bitcoind proxy, so the node has seen the funding confirm but cannot finish catching up, then reconnect. Without the previous commit, this locks in the never-mined latest inflight on every run.
The existing BOLT #2 quote already required this, but the first bullet was unimplemented: the only zero check sat under next_commitment_number == next_index[REMOTE] - 1, after the stale-revocation warning. Implement that bullet next to the quote, and drop the nested copy. Fixes: ElementsProject#9425 Changelog-Fixed: Protocol: immediately fail the channel if channel_reestablish next_commitment_number is zero. Reported-by: Leo Nash (@tankyleo) Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
BOLT #2 says if next_commitment_number is zero we MUST immediately fail the channel and broadcast the latest commitment. On an advanced channel a reset peer sends 0 for both numbers; we warn about the stale revocation_number and never reach the zero check, so the channel stays up. The test funds, pays so next_index is past 1, then injects that reestablish. It fails until the next commit. Reproduces: ElementsProject#9425 Reported-by: Leo Nash (@tankyleo) Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
test_node_bias_persistence() restarted l2, but the layer and its node bias records live in l1's datastore. The assert compared l1's in-memory layer against itself, so load_node_bias() was never actually exercised and this test could not have caught the startup crash in ElementsProject#9433. Restarting l1 instead makes the test reload the layer from the datastore at startup. This is the reproducer for ElementsProject#9433; it fails until the next commit. Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
load_node_bias() passed take(description) to two consecutive set_node_bias() calls. The first call's tal_strdup() consumes the take (tal_resize_ + tal_steal), so the second take() was on freed memory and we aborted in to_tal_hdr() with "Not a valid header" while loading the layer at startup. Since askrene is an important plugin, lightningd shuts down and the node cannot restart at all. The description is already a copy off tmpctx, so simply don't take() it: set_node_bias() strdups it into the bias anyway. With this, the test from the previous commit passes. Fixes: ElementsProject#9433 Reported-by: endothermicdev Changelog-Fixed: askrene: node failed to start (`exited before replying to init`) when a persistent layer contains a node bias with a description Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
Changelog-Fixed: askrene: setting an absolute bias value to zero on a persistent layer doesn't result on a NULL pointer dereference. Reported-by: @whkim0 and @Ahmadsm2005 Suggested-fix: @Andezion Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
create_onionpacket returns NULL when the route's per-hop payloads exceed the 1300-byte onion; send_payment passed the packet to send_onion unchecked, and serialize_onionpacket dereferenced it, killing lightningd with SIGSEGV. Observed in production on a 25-hop route submitted by a rebalancing plugin. The sendonion path already checks this call and fails the command; mirror it, and add a test. Changelog-Fixed: JSON-RPC: `sendpay` with a route too long to fit the onion packet now fails cleanly instead of crashing lightningd.
funding_satoshis values above the total bitcoin supply were not rejected during open_channel/accept_channel negotiation and would later cause libwally to fail and openingd to crash during commitment transaction construction. Reject such funding_satoshis values immediately so that the negotiation terminates gracefully. Fixes: ElementsProject#9225 Changelog-Fixed: `openingd` no longer crashes when a peer opens a channel with a `funding_satoshis` value greater than the total bitcoin supply.
marginal_feerate() computed current_feerate * 1.1 as a double and
converted the result back to u32. Since current_feerate is chosen by
the peer in open_channel or update_fee, they could choose an absurdly
high value that overflows u32 after the computation. UBSan reports:
common/fee_states.c:179:10: runtime error: 4.72446e+09 is outside the range of representable values of type 'unsigned int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior common/fee_states.c:179:10
Do the arithmetic with u64 and saturate at UINT32_MAX to avoid the
undefined behavior.
Found by fuzzing with smite.
Changelog-Fixed: JSON-RPC: `listpeerchannels` no longer derives `receivable_msat` from an overflowed fee estimate when the peer sets an absurd `feerate_per_kw`.
``` lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: FATAL SIGNAL 11 (version v26.06-57-g6889d36-modded) lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: common/daemon.c:46 (send_backtrace) 0x55cca29bb0b9 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: common/daemon.c:83 (crashdump) 0x55cca29bb0f6 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0 ((null)) 0x7f642cb26def lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: common/configvar.c:112 (configvar_finalize_overrides) 0x55cca29baa1d lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: lightningd/plugin.c:1607 (plugin_add_params) 0x55cca295ea4f lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: lightningd/plugin.c:1806 (plugin_parse_getmanifest_response) 0x55cca2960435 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: lightningd/plugin.c:1822 (plugin_manifest_cb) 0x55cca296155b lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: lightningd/plugin.c:693 (plugin_response_handle) 0x55cca295cfd8 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: lightningd/plugin.c:782 (plugin_read_json) 0x55cca29620c3 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:60 (next_plan) 0x55cca29f8201 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:422 (do_plan) 0x55cca29f868c lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:439 (io_ready) 0x55cca29f8745 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: ccan/ccan/io/poll.c:470 (io_loop) 0x55cca29fa0db lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: lightningd/io_loop_with_timers.c:22 (io_loop_with_timers) 0x55cca2930979 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: lightningd/lightningd.c:1480 (main) 0x55cca2936209 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: ../sysdeps/nptl/libc_start_call_main.h:58 (__libc_start_call_main) 0x7f642cb10ca7 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: ../csu/libc-start.c:360 (__libc_start_main_impl) 0x7f642cb10d64 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: (null):0 ((null)) 0x55cca2905120 lightningd-1 2026-06-23T15:23:52.744Z **BROKEN** lightningd: backtrace: (null):0 ((null)) 0xffffffffffffffff ``` Seems like a stale option is causing it, in this case `selfdisable` from `test_libplugin` Changelog-None
Changelog-Fixed: plugins: fix crash when starting a plugin with start parameters after a previously-configured plugin option disabled itself
On macOS under load, socketpair fds sent via SCM_RIGHTS can have O_NONBLOCK set (from the sender's io_new_conn call in hsmd's pass_client_hsmfd). This causes wire_sync_read to return NULL with EAGAIN, killing connectd or channeld with "No hsmd ECDH response". The fix mirrors the "Don't trust subd to set it blocking" pattern already used in lightningd/subd.c:read_fds(): explicitly call io_fd_block(hsm_fd, true) in ecdh_hsmd_setup. Changelog-Fixed: connectd: fix intermittent "No hsmd ECDH response" crash on macOS under load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shades of `efacada7ddf` which did the same thing in multifundchannel:
(ab)used the id, which being a string, gave and id of 34 (").
Also clean up the leftover assert in multifundchannel.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…firms
After consider_onchain_rebroadcast() creates a higher-fee replacement,
rebroadcast_txs() calls refresh() which updates otx->tx in-place, but
the confirmation guard still queries the original otx->txid (the map key):
if (wallet_transaction_height(topo->ld->wallet, &otx->txid))
continue;
Because the original tx was never mined (only the replacement was),
wallet_transaction_height always returns 0 and the RBF loop fires on
every subsequent block forever, even after the channel is fully resolved.
Fix: compute cur_txid from the current otx->tx before the guard. This
naturally reflects any replacement made by a prior refresh() call, so
wallet_transaction_height finds the confirmed txid and skips the entry.
otx->txid (the hash-map key) is intentionally left unchanged: mutating
the key in-place while the entry lives in the map would corrupt the table.
Changelog-Fixed: chaintopology: stop the on-chain RBF rebroadcast loop once a fee-bumped replacement transaction confirms; previously the loop kept firing on every new block forever.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Changelog-None Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
Changelog-Fixed: renepay: fix the computation of the CLTV for the first hop, it was double counting the current blockheight leading to too 900k blocks into the future. Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
The local variable `error` in handle_peer_spoke() is declared as a pointer type with no initialization. Several error paths jump to the `send_error` label where `error` is dereferenced (passed to tal_hex() and towire_connectd_peer_send_msg()). While sockpair() currently sets the `error` pointer via the output parameter on failure, the declaration should be initialized to NULL as a defensive measure and to avoid undefined behavior if code paths change. Fixes ElementsProject#8849 Changelog-Fixed: peer_control: initialize error pointer in handle_peer_spoke to NULL to prevent undefined behavior on error paths.
Avoids having to create a special test plugin most of the time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
```
Valgrind error file: valgrind-errors.3449770
==3449770== Invalid read of size 8
==3449770== at 0x1B4F4A: htlc_set_fail_ (htlc_set.c:77)
==3449770== by 0x1B59FB: invoice_payment_hooks_done (invoice.c:276)
==3449770== by 0x1EC5DF: hook_done (plugin_hook.c:243)
==3449770== by 0x1EC710: plugin_hook_call_next (plugin_hook.c:343)
==3449770== by 0x1EC90E: plugin_hook_callback (plugin_hook.c:299)
==3449770== by 0x1E6316: plugin_response_handle (plugin.c:692)
==3449770== by 0x1EB443: plugin_read_json (plugin.c:781)
==3449770== by 0x283D01: next_plan (io.c:60)
==3449770== by 0x28418C: do_plan (io.c:422)
==3449770== by 0x284245: io_ready (io.c:439)
==3449770== by 0x285BE3: io_loop (poll.c:471)
==3449770== by 0x1B9A99: io_loop_with_timers (io_loop_with_timers.c:22)
==3449770== Address 0x38 is not stack'd, malloc'd or (recently) free'd
==3449770==
{
<insert_a_suppression_name_here>
Memcheck:Addr8
fun:htlc_set_fail_
fun:invoice_payment_hooks_done
fun:hook_done
fun:plugin_hook_call_next
fun:plugin_hook_callback
fun:plugin_response_handle
fun:plugin_read_json
fun:next_plan
fun:do_plan
fun:io_ready
fun:io_loop
fun:io_loop_with_timers
}
```
Changelog-Fixed: lightningd: fix crash of lightningd on race condition between delinvoice and a returning invoice_payment hook for fallback onchain settlements
Reported-by: Vincenzo Palazzo (Bitcoin Security Council finding 2026-08-11)
Co-Authored-By: Grok 4.5
Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
We crashed if the name collision happened to be a builtin command. ``` lightningd: FATAL SIGNAL 11 (version v26.06-241-gb35b848-modded) 0x5573cd532b2c send_backtrace common/daemon.c:38 0x5573cd532bb6 crashdump common/daemon.c:83 0x7fe1fd4ccdef ??? ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0 0x5573cd4d51a4 plugin_rpcmethod_add lightningd/plugin.c:1396 0x5573cd4d5268 plugin_rpcmethods_add lightningd/plugin.c:1423 0x5573cd4d57ef plugin_parse_getmanifest_response lightningd/plugin.c:1805 0x5573cd4d68db plugin_manifest_cb lightningd/plugin.c:1827 0x5573cd4d2316 plugin_response_handle lightningd/plugin.c:692 0x5573cd4d7443 plugin_read_json lightningd/plugin.c:781 0x5573cd56fd01 next_plan ccan/ccan/io/io.c:60 0x5573cd57018c do_plan ccan/ccan/io/io.c:422 0x5573cd570245 io_ready ccan/ccan/io/io.c:439 0x5573cd571be3 io_loop ccan/ccan/io/poll.c:471 0x5573cd4a5a99 io_loop_with_timers lightningd/io_loop_with_timers.c:22 0x5573cd4d61d1 plugins_init lightningd/plugin.c:2063 0x5573cd4aad6c main lightningd/lightningd.c:1269 0x7fe1fd4b6ca7 __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 0x7fe1fd4b6d64 __libc_start_main_impl ../csu/libc-start.c:360 0x5573cd47a120 ??? _start+0x20:0 0xffffffffffffffff ??? ???:0 ``` Changelog-Fixed: lightningd: checks for rpc name collisions with builtin commands when registering plugin RPC methods Reported-by: Vincenzo Palazzo (Bitcoin Security Council finding 2026-08-11) Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
We first check that the "usage" can be unescaped before handing it down to jsonrpc_command_add. The latter can only fail if there is a method collision. Changelog-None Signed-off-by: Lagrang3 <lagrang3@protonmail.com>
unwrap_onionreply always runs 27 iterations to hide the route length, and for iterations at or beyond the real hop count it substitutes a hardcoded secret of 32 bytes of 0x07. The "um" HMAC key for those iterations is therefore a public constant that anyone can compute. Because wrap_onionreply is a length-preserving XOR, a payment recipient (which knows the last real shared secret) can forge a reply whose HMAC matches on a padding iteration. The loop had no break and the last match won, so origin_index could be set to 26 for any route. lightningd then passes that index to remote_routing_failure, where assert(origin_index < tal_count(route_nodes)) fails and aborts the whole lightningd process. The attacker only needs the victim to attempt a payment to it, and failing at the final hop is ordinary protocol behaviour. Only record a match as an origin when it happened on a real hop (i < numhops). The loop still runs all 27 iterations for constant-time route-length hiding, but a match on a padding iteration is ignored, so origin_index is always within the real path and cannot be forced out of range by a peer. Changelog-Fixed: Protocol: a peer receiving a payment can no longer crash the sender's node by returning a crafted error onion. Co-authored-by: Cursor <cursoragent@cursor.com>
We assume elsewhere this is only for final hops. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Fixed: lightningd: crash when forwarding onion message with path_id set.
This code path could happen if things are going wrong generally, so lets log invalid txs instead of aborting on them. Changelog-Fixed: lightningd: a mutual close proposed after a splice left almost nothing in the channel no longer aborts the node; the invalid closing fee is rejected instead.
Turns out we never persisted this flag after the fact. We're about to start relying on it, so save it properly. Co-authored-by: Cursor <cursoragent@cursor.com>
Set i_sent_sigs when dualopend tells us the sigs went out, and add a little helper to ask "did we sign this yet?" No behavior change... yet. Co-authored-by: Cursor <cursoragent@cursor.com>
Add local_funding_sigs_sent to tx_state, set when we write our sigs to the peer (both the normal path and the reconnect dance). Pass it back in over dualopend_reinit, since dualopend restarts on every reconnect and would otherwise start from scratch. Co-authored-by: Cursor <cursoragent@cursor.com>
Once our sigs have gone out, BOLT #2 says to hold onto the channel until an input of the funding tx has been spent. Guard the deletion paths on the new i_sent_sigs flag so an abort or error after that point keeps the channel around. Changelog-Fixed: Protocol: dual-fund: we now remember the channel when the peer sends `tx_abort` after we have already sent our `tx_signatures`, as required by BOLT #2. Co-authored-by: Cursor <cursoragent@cursor.com>
A v1 channel_id is derived from the funding outpoint, which the peer chooses and which we can't check until it confirms. We only refused an outpoint already used by a live channel with the same peer, so a second channel could end up sharing a forgotten channel's channel_id. When it is closed too we abort in closed_channel_map_add() with "Assertion `!closed_channel_map_getmatch_(...)' failed", and since the channel is in the db, onchaind or a restart then crashes us again every time. Refuse to commit a channel whose channel_id is used by any live or closed channel, in the fundee, funder and dual-funding paths, and allow duplicates in the closed channel map so nodes which already have such channels in their db can close and load them. Changelog-Fixed: lightningd: a peer reusing a funding outpoint can no longer crash the node with a duplicate channel_id.
When a splice candidate confirms, keep only the htlc_sigs rows whose inflight outpoint matches the confirmed funding outpoint in both the transaction ID and the output index, then promote them to the active set. Add unit coverage for wallet_htlcsigs_confirm_inflight. Seed a pre-existing active set plus inflight candidates that share the confirmed outpoint's txid, share its output index, or match neither, then confirm the outpoint. The test checks that all five rows were stored, that only the confirmed candidate's signatures are loaded as the active set, and that no other htlc_sigs rows remain. Row counting goes through a count_htlc_sigs helper alongside the existing count_inflights. The test restores the channel's htlc_sigs before returning so the surrounding CRUD test never sees fixture rows. Add an integration test that runs two fee-bump splices on a channel, so both candidates place the funding output at index 0 and differ only by txid, then leaves one HTLC stuck so the next commitment stores an HTLC signature for the active funding and for each candidate. After the replacement confirms, both nodes must hold exactly one htlc_sigs row, promoted to active. Fee-bump splices carry no wallet inputs and no payout output, which keeps the funding output index deterministic. Changelog-Fixed: wallet: keep only the confirmed splice candidate's HTLC signatures after a splice-RBF. Signed-off-by: jaonoctus <jaonoctus@protonmail.com>
…adopted splice_locked needs both sides. A peer that never sends it and closes on the confirmed splice output leaves us in CHANNELD_AWAITING_SPLICE with channel->funding still the outpoint the splice spent, and the candidate watch hands onchaind that stale funding. Expected to fail until the next commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…before splice_locked
splice_locked needs both sides. A peer that never sends it and closes
on the confirmed splice output left us in CHANNELD_AWAITING_SPLICE with
channel->funding still the outpoint the splice spent; the candidate
watch fired funding_spent(), which handed onchaind a commitment for
that old funding ("Funding transaction spent" on the wrong outpoint,
nothing resolved). The same happened on our own side after a force
close with an inflight, once the candidate's commitment confirmed:
onchaind took our own commitment for the peer's and died with "Could
not find resolution for output 1".
Whenever the spent outpoint is a candidate's and not the channel's
funding, adopt that candidate first, the way handle_peer_splice_locked()
(or opening_depth_cb for a dual-funding candidate) would have, then go
to onchaind on it.
Changelog-Fixed: splicing: a close on a confirmed splice output before splice_locked completed is now handled by onchaind on that output, on both sides.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…hen a throttle ends
This was referenced Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings
blake2b-unifiedup to upstream Core Lightning v26.06.8, a security point release: peer-triggerable crashes, rune authorization, onchain HTLC matching, splice and dual-funding fixes, closing fee bounds, and libwally 1.5.6.Conflicts
Each is a place where this branch and upstream fixed the same thing independently; upstream's version is taken so later merges stay clean.
hsmd/libhsmd.{h,c},hsmd/test/run-bad-request-close.c: this branch'shsmd_secrets_free()and upstream'shsmd_deinit()do the same thing (free the seed, mark hsmd uninitialized so later requests fail closed). Kepthsmd_deinit()and removed the duplicate.tests/test_opening.py: the same fix to thetest_zero_length_upfront_shutdown_scriptrace.tests/test_clnrest.py: the same fix to the large request body test.tests/test_pay.py: this branch skippedtest_pay_bolt11_metadata(its fixture had expired); upstream fixed it.tests/test_invoices.py: both sides added a new test at the same place; both are kept.Fixes to v26.06.8 itself
Found by running the full suite under valgrind and ASan.
connectd: when the new per-peer CPU throttle ended,wake_gossip()started streaming the gossip store to a peer that had never sentgossip_timestamp_filter, filtered against timestamps that were never set. BOLT 7 forbids relaying gossip that was not requested, and the budget is split across all peers, so on a busy node this was easy to trip. A peer that has not sent a filter now only has its query replies resumed. Regression test:test_gossip_throttle_no_unrequested_stream.lightningd/runes.c: the blacklist range walk read one bit past the end of the bitmap.lightningd/channel.c: an unsaved channel's funding outpoint was uninitialized but compared byfind_channel_by_funding_outpoint().xpay: ablock_addednotification arriving before thegetchaininforeply compared against an uninitializedblockheight.Tests and CI
wallet/test/run-wallet.c: upstream's new splice-RBF test callswallet_htlc_sigs_load(..., false). Here that parameter is aconst struct channel_type *, sofalsecompiled silently as NULL and the test crashed. It now passes a non-anchor channel type, the equivalent offalse.pyln-testing: under valgrind and ASan, ordinary messages can exceed connectd's CPU budget, so the throttle's "too much CPU" notice is allowed there, extending upstream's existing slow-request allowance. It still fails every other job, and "too much traffic" always fails.test_gossip_query_channel_range_cpu_throttleasserts on the throttle log instead of waiting for all ten replies, which could take longer than the timeout under valgrind.test_splice_rbf_htlc_sigsannounces the channel before splicing, and the reestablish test tolerates the expected hangup.test_no_delay, thetest_sqlblockheight race, gRPC readiness in the notification tests, and thetest_multichan_stressandtest_graceful_htlcflakes.ci.yaml: a pull request already based on its target is not rebased, so merges are tested as merges.Deferred: #14, #15, #16, #17, #18.
Verification
CI green on the final commit. Locally against Bitcoin Knots v29.4.2: unit tests under valgrind, the gossip, connection and xpay suites under valgrind, and repeated valgrind runs of every test changed here. The connectd, runes and funding fixes were each reproduced before the fix and clean after; the xpay race was caught once under valgrind and has no deterministic test.