Description
Thinking about #3863, and experimenting with a badly-connected node, suggests to me that we badly mismanage the given pay
budget.
I made some large payments of about a millibitcoin or so (large relative to the badly-connected node, it has barely 10 millibitcoins locked up to nodes that turn out to themselves be fairly badly connected when I do some manual 2-hop sendpay
probes from the badly-connected node) and when giving maxfeepercent
of 1% or 2% it fails, but afterwards with doing 5% it succeeds.
Yet when I look at the listpays
report it claims to have sent out only around ~0.6% more than the requested amount, i.e. the feepercent is only 0.6%. In principle the payment solution it found at maxfeepercent=5
should have been discoverable at maxfeepercent=1
or 2
. Either listpays
is wrong, or we are badly mismanging our fee budget.
I think we should instead make a single budget for a tree of payments, rather than the "budget-stealing" idea suggested in #3863.
Basically:
- Add a new
struct payment_budget
which is initialized to theamount_msat
of the fee budget.- The root payment allocates and constructs this object.
- Child payments copy the pointer to this structure from the parent.
- Could just be a
struct amount_msat
directly, why do we need a newstruct
type for it anyway?
- Remove the fee-checking in the post-
getroute
processing.- Remove the constraints thing, it should not be necessary, but cutting that out may be the hardest part of this effort, as we have some assumptions about it.
- Prior to
createonion
+sendonion
+waitsendpay
, check the fee of the route (value at last hop minus value at first hop).- If this fee is larger than the
payment_budget
, pretend this is awaitsendpay
returning with aPAY_ROUTE_TOO_EXPENSIVE
(whichwaitsendpay
will not actually return, but is a useful fiction to have in the paymod system) --- invent apayment_result
withcode
=PAY_ROUTE_TOO_EXPENSIVE
and pointless values in other fields --- and then callpayment_failed
, and let paymods figure out what to do about it (we could make a new paymod that does the exempting of channels with high feerates in case of that error). - If the fee is less than or equal to the
payment_budget
we deduct it from thepayment
budget and continue with thecreateonion
/sendonion
/waitsendpay
sequence.
- If this fee is larger than the
- If any of the
createonion
sendonion
orwaitsendpay
fail, return the allocated fee back to thepayment_budget
.- Create new
payment_createonion_fail
etc. functions which do this returning of the fee budget, and then forward the call to whatever was the previous fail-handler for that RPC (payment_rpc_failure
forcreateonion
andsendonion
,payment_waitsendpay_finished
forwaitsendpay
).
- Create new
The above should basically allocate budgets to each sub-payment as "tightly" as possible, and means that even on my badly-connected node, it should be able to acquire payment solutions of 0.6% with just maxfeepercent=2
or even maxfeepercent=1
.
To be clear, I am not working on this for now, so anyone who is willing to poke into plugins/libplugin-pay.c
can go try to implement the above. Not sure if this is a good first issue, but hey, just try, mkay?