Skip to content

MPP Should Have Single Global Budget #4104

Open
@ZmnSCPxj

Description

@ZmnSCPxj

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 the amount_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 new struct 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 a waitsendpay returning with a PAY_ROUTE_TOO_EXPENSIVE (which waitsendpay will not actually return, but is a useful fiction to have in the paymod system) --- invent a payment_result with code=PAY_ROUTE_TOO_EXPENSIVE and pointless values in other fields --- and then call payment_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 the payment budget and continue with the createonion/sendonion/waitsendpay sequence.
  • If any of the createonion sendonion or waitsendpay fail, return the allocated fee back to the payment_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 for createonion and sendonion, payment_waitsendpay_finished for waitsendpay).

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?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions