mirror of
https://github.com/ZmnSCPxj/clboss.git
synced 2026-08-13 12:33:20 +02:00
XMoveFunds: never disable_node our own node on a NODE-level failure
In a circular rebalance the destination is ourselves, so a NODE-level onion failure (failcode & 0x2000) at the closing hop is attributed to erring_node == self. accumulate_failure_feedback's node-level branch called disable_node( erring_node) unconditionally, so it disabled OUR OWN node in the persistent clboss-xrebalance layer. askrene then treats every one of our channels as a disabled source -- getroutes fails with 205 "source has disabled N of N channels, leaving capacity only 0msat" -- and because disabled_nodes never ages, every subsequent rebalance is locked out permanently (fee budget is irrelevant). Observed on prod1: one end-of-route node failure took out all 73 source channels at once. Guard the node-level branch: if erring_node == self_id, return without disabling. Mirrors the self-loop guard FundsMover already has on the clboss layer. A node-level failure blamed on us (we are the paying destination, so we would accept) is a mis-attribution anyway and nothing about our own node should be disabled. Recovery for an already-poisoned layer (no askrene un-disable-node exists): askrene-remove-layer clboss-xrebalance ; askrene-create-layer clboss-xrebalance true Logging/behavior otherwise unchanged.
This commit is contained in:
parent
118a722b32
commit
7500a2344b
1 changed files with 12 additions and 2 deletions
|
|
@ -1233,8 +1233,18 @@ private:
|
|||
}
|
||||
|
||||
if (fail & 0x2000) {
|
||||
/* NODE-level failure: take the whole
|
||||
* forwarder out of consideration. */
|
||||
/* NODE-level failure: take the whole forwarder
|
||||
* out of consideration -- but NEVER our own node.
|
||||
* In a circular rebalance the destination is us,
|
||||
* so a node-level failure at the closing hop is
|
||||
* attributed to self; disable_node(self) would
|
||||
* disable ALL our channels as the source (askrene:
|
||||
* "source has disabled N of N channels, capacity
|
||||
* 0msat") and lock out every future rebalance --
|
||||
* permanently, since disabled_nodes does not age.
|
||||
* Mirrors FundsMover's self_id guard. */
|
||||
if (std::string(enode) == std::string(self_id))
|
||||
return;
|
||||
actions.push_back(
|
||||
Boss::Mod::AskreneLayer::disable_node(
|
||||
*rpc,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue