clboss/Boss/Mod/DemandTracker.cpp
Ken Sedgwick a612d759dd
Some checks are pending
Code Base Sanity Check / tests (push) Waiting to run
Code Base Sanity Check / coverage (push) Waiting to run
Code Base Sanity Check / build-clang (push) Waiting to run
DemandTracker: trigger demand rebalance cycles from observed forwards
New module DemandTracker registers an htlc_accepted deferrer that
never holds an HTLC: for each forward it raises DemandObserved
naming the outgoing channel, then immediately declines.  The
message deliberately carries no amount: unforwardable probe HTLCs
cost an attacker nothing, so sizing from a demanded amount would
be a free lever over our spend.

XRebalancer consumes the message.  A trigger arriving while any
cycle runs is discarded (traffic recurrence re-arms real demand);
otherwise it runs a demand cycle: the same fetch/join pipeline as
a matched cycle, targeting the peer whose channel the forward
exited through.  Fill-pool membership is the entire criterion --
demand controls when we rebalance, never who qualifies or how
much.  The request restores the peer to the fill edge, priced at
target NetPpm plus the minimum offered NetPpm, executed through
the existing executor with cycle tag [demand].

The new in_flight flag serializes matched and demand cycles; both
paths clear it behind a catch-all so an exception cannot wedge
it.  The catch-all around the matched tick also keeps the Poisson
loop alive on RPC errors, which previously terminated it with
only a stderr notice.
2026-08-05 10:59:08 -07:00

36 lines
1 KiB
C++

#include"Boss/Mod/DemandTracker.hpp"
#include"Boss/Msg/DemandObserved.hpp"
#include"Boss/Msg/ProvideHtlcAcceptedDeferrer.hpp"
#include"Boss/Msg/SolicitHtlcAcceptedDeferrer.hpp"
#include"Ev/Io.hpp"
#include"Ln/HtlcAccepted.hpp"
#include"S/Bus.hpp"
namespace Boss { namespace Mod {
void DemandTracker::start() {
bus.subscribe<Msg::SolicitHtlcAcceptedDeferrer
>([this](Msg::SolicitHtlcAcceptedDeferrer const&) {
auto f = [this](Ln::HtlcAccepted::Request const& req) {
return htlc_accepted(req);
};
return bus.raise(Msg::ProvideHtlcAcceptedDeferrer{
std::move(f)
});
});
}
Ev::Io<bool>
DemandTracker::htlc_accepted(Ln::HtlcAccepted::Request const& req) {
/* Not a forward (we are the recipient)? */
if (!req.next_channel)
return Ev::lift(false);
/* This runs in the hook path: raise (subscribers keep their
* synchronous part cheap) and decline the HTLC either way. */
auto msg = Msg::DemandObserved{req.next_channel};
return bus.raise(std::move(msg)).then([]() {
return Ev::lift(false);
});
}
}}