Add AskreneUpdates, a standalone module both rebalancers will use to hold the
node disables and channel_update overrides they learn from routing failures.
askrene never ages these (they carry no timestamp, unlike the inform-channel
constraints), so instead of accumulating them in a shared askrene layer they
live in two append-only sqlite tables here and are projected, still-fresh, into
a private per-request layer for each getroutes.
Records arrive as AskreneNodeDisableUpdate / AskreneChannelUpdate. A ReqResp
(Request/ResponseAskreneUpdates) returns the distinct nodes disabled within
clboss-node-disable-age-secs and the latest override per channel direction
within clboss-channel-update-age-secs. Static open_layer/close_layer build and
tear down a uuid-named, non-persistent layer from a response (open_layer returns
an empty name if askrene is absent, so a caller never names a missing layer).
Rows are pruned only at clboss-update-retain-secs (default 30d), so the log
survives long enough to mine. Nothing calls the module yet.
Also add an AskreneLayer header comment pointing at this store for where
the learned node disables and channel_update overrides live.
Introduces a single source of truth for which rebalancing track is
active. Boss::Mod::RebalanceModeManager owns the mode in memory (no
sqlite, so a restart reverts to the configured default, giving a
known-good baseline on every boot) and registers clboss-rebalance-mode
as a dynamic option: the config file sets the startup default and
`setconfig clboss-rebalance-mode <mode>` switches it at runtime without
a restart. It answers RequestRebalanceMode queries and reports the mode
under clboss-status.
Modes are "classic" (run the rebalancer) and "off" (a real quiesce,
also the supported way to disable rebalancing entirely). This is the
seam that later lets a second rebalancing track coexist and be toggled
without a restart.
The classic-track rebalancers self-gate on the mode at their existing
decision points, modeled on RebalanceUnmanager: EarningsRebalancer gates
its trigger, InitialRebalancer gates its run, and JitRebalancer gates
the top of htlc_accepted so that in off mode it does not defer the HTLC
and adds no forwarding latency. A header-only Boss::ModG::
RebalanceModeProxy provides get_mode for the gate sites. off composes
with the existing per-peer unmanage balance tag: off wins globally,
otherwise the per-peer tag still excludes specific peers.
The three rebalancers' unit tests now install a RebalanceModeManager on
the test bus so the self-gate query is answered (default classic, so
they behave as before). Without a responder the RequestRebalanceMode
ReqResp is never satisfied and leaks, which the valgrind-checked tests
flag as a failure.
New files: Boss/RebalanceMode.hpp, Boss/Msg/RequestRebalanceMode.hpp,
Boss/Msg/ResponseRebalanceMode.hpp, Boss/ModG/RebalanceModeProxy.hpp,
Boss/Mod/RebalanceModeManager.{hpp,cpp}.
Introduces the mechanism for runtime-mutable plugin options: an option
marked dynamic can be changed via `lightning-cli setconfig <name> <val>`
without restarting clboss or lightningd. No option opts in yet -- this
is the foundation (the rebalancer mode selector is the first consumer).
- Boss::Msg::ManifestOption gains a bool dynamic field (default false,
preserving the existing startup-only contract).
- Boss::Mod::Manifester emits the per-option dynamic flag in the
getmanifest response, so lightningd knows to forward setconfig for
that option.
- New Boss::Mod::SetConfigHandler module records (name -> dynamic)
from Msg::ManifestOption events, then handles incoming setconfig
CommandRequests: it validates the named option is registered and
dynamic, and re-raises a fresh Msg::Option on the bus, so existing
option handlers re-apply the new value transparently.
Because Msg::Option is now re-emitted at runtime (not only during init),
subscribers must filter by name and tolerate post-init arrival.
AmountSettingsHandler gains an `if (!settings) return` guard: it moves
`settings` away at EndOfOptions, so a later Msg::Option for an unrelated
name must be dropped -- this also fixes a latent assert(settings) crash
that any post-EndOfOptions Msg::Option would have tripped.
Contract documented in SetConfigHandler.hpp: lightningd delivers
Int/Bool/Flag option values as JSON primitives at startup but as JSON
strings at setconfig time, so dynamic-option handlers must accept both
Jsmn shapes.