Skip to content

Some thoughts on payment splitting heuristics for multi part payments #2276

Description

@renepickhardt

This is based on some out of band communication with @TheBlueMatt:

In #1276 there was the damand to revisit the splitting heuristic of payments in LDK. Back at that day I argued that the splitting problem is exactly what whould be solved throuph optimally reliable payment flows which are proposed to be added in #1668. However I think I have to withdraw or at least weaken some of my claims from before as I will lay out in this issue.

The following originated from the comments by @TheBlueMatt on the mailinglist :

While its much less capital-effecient, the ability to over-commit upfront and then only allow the
recipient to claim a portion of the total committed funds would substantially reduce the impact of
failed HTLCs on payment latency. Of course the extra round-trip to request the "unlock keys" for the
correct set of HTLCs adds a chunk to total latency, so senders will have to be careful about
deciding when to do this or not.

Still, now that we have onion messages, we should do (well, try) this! Its not super complicated to
implement (like everything it seems, the obvious implementation forgoes proof-of-payment, and like
everything the obvious solution is PTLCs, I think). Its not clear to me how we get good data from
trials, though, we'd need a sufficient set of the network to support this that we could actually
test it, which is hard to get for a test.

Maybe someone (anyone?) wants to do some experiments doing simulations using real probing success
rates to figure out how successful this would be and propose a concrete sender strategy that would
improve success rates.

While digging into redundant overpayments I figured out several noteworthy things:

  1. Minimum cost flows may not yield the maximum expected value to be delivered. A counterexample can be seen at: https://github.com/renepickhardt/Maximum-Expected-Value-Flows-For-Redundant-Overpayments/blob/main/img/counterExample.png
  2. Redundant overpayments can be understood as: "At least k out of n payment parts need to successfully reach the recipient". Thus the method of bernoulli trials can be applied (as orginially suggested in the probabilistic path finding paper for non redundant payments)
  3. While in the above mentioned paper I made poor / strange assumptions to the cost function and channel size to develope the theory I now observed that the only neccessary variable for a bernoulli trial is that the success probability for each path has the be (roughly) the same which can be controlled for by defining a target probability for the various paths and assign the sats for that onion / path such that the estimated success probability reaches the target probability.
  4. These observations lead to a natural splitting heuristic - which seems reasonable (in particular but not only for redundant overpayments) and useful in simulations but I don't have the infrastructure or resources to test this in mainnet.

Summary of the splitting algorithm

This is currently WIP and many choices are adhoc but it shows the princible. the foolowing is a summary of: renepickhardt/pickhardtpayments#36

We use dijkstra to compute candidate paths as shortest paths with respect to our cost function

  1. Use a cost function for a unit that is the combination of linearized routing cost and linearized uncertainty cost
  2. smooth the routing cost (currently laplace smoothing with +100. The exact value needs to be found through tests and feature engineering
  3. thus: cost = (ppm + 100) * 1/capacity
  4. After a path is planned increase cost of each edge with a multiplier

with respect to allocation of funds to paths

The cost function favors paths with low routing costs thus the only question is how many sats to allocate?
The following idea shall be used for motivation:

  • We want each path to have a success probability of at least x%
  • Thus let l be the length of the planned path and c be the capacity of the smallest channel.
  • Then s = (c+1-a)/(c+1) is the success probability for the allocated amount a (Of course one does not have to use a uniform distribution to estimate the success probabilities but use a different prior. the following fomulars would however change)
  • We require s >= x ** (1/l) which means the path has a probability of at least x
  • For now we ignore prior knowledge and believe (Thus one reason for this to be WIP)
  • knowing s at equality we solve for a --> a = (c+1) - s*(c+1) = (c+1)*(1-s)
  • we allocate a sats to the candidate path

Comparison to existing splitters

Existing splitters operate by the following ideas

  • divide by 2 if the amount seems to large after several attampts (I think this is the LND rational)
  • define a fixed number of parts one wishes to have and divide into that many parts (I think this is LDK)
  • define a payment size for the parts and split down to that size ( this is one of the rationals by core lightning)

Non of the above mentioned ideas start with reliability and can be used to derrive service level objectives. With the method that I proposed one can start with a clear service level objective and get single parts that have all the same success probability and obviously the single parts can be derrived with cost functions that focus more on fees or more on reliability or any other feature that one may find desireable

While this is not directly an issue I thought I drop this here as there was previously the discussion about splitting heuristics and as mentioned I have to withdraw some of by too strong claims statements.

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

    , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
     blocks
    (function() {
    function addCopyButtons() {
    document.querySelectorAll('pre code').forEach(function(codeBlock) {
    if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
    codeBlock.parentElement.setAttribute('data-copy-added', 'true');
    var btn = document.createElement('button');
    btn.textContent = 'Copy';
    btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
    btn.onmouseover = function() { this.style.opacity = '1'; };
    btn.onmouseout = function() { this.style.opacity = '0.7'; };
    btn.onclick = function() {
    navigator.clipboard.writeText(codeBlock.textContent).then(function() {
    btn.textContent = 'Copied!';
    setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
    });
    };
    codeBlock.parentElement.style.position = 'relative';
    codeBlock.parentElement.appendChild(btn);
    });
    }
    addCopyButtons();
    // Re-run on dynamic content
    var observer = new MutationObserver(addCopyButtons);
    observer.observe(document.body, { childList: true, subtree: true });
    })();
    }
    } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
    })();
    (function(){
    try {
    var __m = "github.com";
    var __re = new RegExp('^' + "github\\.com" + '
    Some thoughts on payment splitting heuristics for multi part payments · Issue #2276 · lightningdevkit/rust-lightning · GitHub
    Skip to content

    Some thoughts on payment splitting heuristics for multi part payments #2276

    Description

    @renepickhardt

    This is based on some out of band communication with @TheBlueMatt:

    In #1276 there was the damand to revisit the splitting heuristic of payments in LDK. Back at that day I argued that the splitting problem is exactly what whould be solved throuph optimally reliable payment flows which are proposed to be added in #1668. However I think I have to withdraw or at least weaken some of my claims from before as I will lay out in this issue.

    The following originated from the comments by @TheBlueMatt on the mailinglist :

    While its much less capital-effecient, the ability to over-commit upfront and then only allow the
    recipient to claim a portion of the total committed funds would substantially reduce the impact of
    failed HTLCs on payment latency. Of course the extra round-trip to request the "unlock keys" for the
    correct set of HTLCs adds a chunk to total latency, so senders will have to be careful about
    deciding when to do this or not.

    Still, now that we have onion messages, we should do (well, try) this! Its not super complicated to
    implement (like everything it seems, the obvious implementation forgoes proof-of-payment, and like
    everything the obvious solution is PTLCs, I think). Its not clear to me how we get good data from
    trials, though, we'd need a sufficient set of the network to support this that we could actually
    test it, which is hard to get for a test.

    Maybe someone (anyone?) wants to do some experiments doing simulations using real probing success
    rates to figure out how successful this would be and propose a concrete sender strategy that would
    improve success rates.

    While digging into redundant overpayments I figured out several noteworthy things:

    1. Minimum cost flows may not yield the maximum expected value to be delivered. A counterexample can be seen at: https://github.com/renepickhardt/Maximum-Expected-Value-Flows-For-Redundant-Overpayments/blob/main/img/counterExample.png
    2. Redundant overpayments can be understood as: "At least k out of n payment parts need to successfully reach the recipient". Thus the method of bernoulli trials can be applied (as orginially suggested in the probabilistic path finding paper for non redundant payments)
    3. While in the above mentioned paper I made poor / strange assumptions to the cost function and channel size to develope the theory I now observed that the only neccessary variable for a bernoulli trial is that the success probability for each path has the be (roughly) the same which can be controlled for by defining a target probability for the various paths and assign the sats for that onion / path such that the estimated success probability reaches the target probability.
    4. These observations lead to a natural splitting heuristic - which seems reasonable (in particular but not only for redundant overpayments) and useful in simulations but I don't have the infrastructure or resources to test this in mainnet.

    Summary of the splitting algorithm

    This is currently WIP and many choices are adhoc but it shows the princible. the foolowing is a summary of: renepickhardt/pickhardtpayments#36

    We use dijkstra to compute candidate paths as shortest paths with respect to our cost function

    1. Use a cost function for a unit that is the combination of linearized routing cost and linearized uncertainty cost
    2. smooth the routing cost (currently laplace smoothing with +100. The exact value needs to be found through tests and feature engineering
    3. thus: cost = (ppm + 100) * 1/capacity
    4. After a path is planned increase cost of each edge with a multiplier

    with respect to allocation of funds to paths

    The cost function favors paths with low routing costs thus the only question is how many sats to allocate?
    The following idea shall be used for motivation:

    • We want each path to have a success probability of at least x%
    • Thus let l be the length of the planned path and c be the capacity of the smallest channel.
    • Then s = (c+1-a)/(c+1) is the success probability for the allocated amount a (Of course one does not have to use a uniform distribution to estimate the success probabilities but use a different prior. the following fomulars would however change)
    • We require s >= x ** (1/l) which means the path has a probability of at least x
    • For now we ignore prior knowledge and believe (Thus one reason for this to be WIP)
    • knowing s at equality we solve for a --> a = (c+1) - s*(c+1) = (c+1)*(1-s)
    • we allocate a sats to the candidate path

    Comparison to existing splitters

    Existing splitters operate by the following ideas

    • divide by 2 if the amount seems to large after several attampts (I think this is the LND rational)
    • define a fixed number of parts one wishes to have and divide into that many parts (I think this is LDK)
    • define a payment size for the parts and split down to that size ( this is one of the rationals by core lightning)

    Non of the above mentioned ideas start with reliability and can be used to derrive service level objectives. With the method that I proposed one can start with a clear service level objective and get single parts that have all the same success probability and obviously the single parts can be derrived with cost functions that focus more on fees or more on reliability or any other feature that one may find desireable

    While this is not directly an issue I thought I drop this here as there was previously the discussion about splitting heuristics and as mentioned I have to withdraw some of by too strong claims statements.

    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

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Some thoughts on payment splitting heuristics for multi part payments · Issue #2276 · lightningdevkit/rust-lightning · GitHub
      Skip to content

      Some thoughts on payment splitting heuristics for multi part payments #2276

      Description

      @renepickhardt

      This is based on some out of band communication with @TheBlueMatt:

      In #1276 there was the damand to revisit the splitting heuristic of payments in LDK. Back at that day I argued that the splitting problem is exactly what whould be solved throuph optimally reliable payment flows which are proposed to be added in #1668. However I think I have to withdraw or at least weaken some of my claims from before as I will lay out in this issue.

      The following originated from the comments by @TheBlueMatt on the mailinglist :

      While its much less capital-effecient, the ability to over-commit upfront and then only allow the
      recipient to claim a portion of the total committed funds would substantially reduce the impact of
      failed HTLCs on payment latency. Of course the extra round-trip to request the "unlock keys" for the
      correct set of HTLCs adds a chunk to total latency, so senders will have to be careful about
      deciding when to do this or not.

      Still, now that we have onion messages, we should do (well, try) this! Its not super complicated to
      implement (like everything it seems, the obvious implementation forgoes proof-of-payment, and like
      everything the obvious solution is PTLCs, I think). Its not clear to me how we get good data from
      trials, though, we'd need a sufficient set of the network to support this that we could actually
      test it, which is hard to get for a test.

      Maybe someone (anyone?) wants to do some experiments doing simulations using real probing success
      rates to figure out how successful this would be and propose a concrete sender strategy that would
      improve success rates.

      While digging into redundant overpayments I figured out several noteworthy things:

      1. Minimum cost flows may not yield the maximum expected value to be delivered. A counterexample can be seen at: https://github.com/renepickhardt/Maximum-Expected-Value-Flows-For-Redundant-Overpayments/blob/main/img/counterExample.png
      2. Redundant overpayments can be understood as: "At least k out of n payment parts need to successfully reach the recipient". Thus the method of bernoulli trials can be applied (as orginially suggested in the probabilistic path finding paper for non redundant payments)
      3. While in the above mentioned paper I made poor / strange assumptions to the cost function and channel size to develope the theory I now observed that the only neccessary variable for a bernoulli trial is that the success probability for each path has the be (roughly) the same which can be controlled for by defining a target probability for the various paths and assign the sats for that onion / path such that the estimated success probability reaches the target probability.
      4. These observations lead to a natural splitting heuristic - which seems reasonable (in particular but not only for redundant overpayments) and useful in simulations but I don't have the infrastructure or resources to test this in mainnet.

      Summary of the splitting algorithm

      This is currently WIP and many choices are adhoc but it shows the princible. the foolowing is a summary of: renepickhardt/pickhardtpayments#36

      We use dijkstra to compute candidate paths as shortest paths with respect to our cost function

      1. Use a cost function for a unit that is the combination of linearized routing cost and linearized uncertainty cost
      2. smooth the routing cost (currently laplace smoothing with +100. The exact value needs to be found through tests and feature engineering
      3. thus: cost = (ppm + 100) * 1/capacity
      4. After a path is planned increase cost of each edge with a multiplier

      with respect to allocation of funds to paths

      The cost function favors paths with low routing costs thus the only question is how many sats to allocate?
      The following idea shall be used for motivation:

      • We want each path to have a success probability of at least x%
      • Thus let l be the length of the planned path and c be the capacity of the smallest channel.
      • Then s = (c+1-a)/(c+1) is the success probability for the allocated amount a (Of course one does not have to use a uniform distribution to estimate the success probabilities but use a different prior. the following fomulars would however change)
      • We require s >= x ** (1/l) which means the path has a probability of at least x
      • For now we ignore prior knowledge and believe (Thus one reason for this to be WIP)
      • knowing s at equality we solve for a --> a = (c+1) - s*(c+1) = (c+1)*(1-s)
      • we allocate a sats to the candidate path

      Comparison to existing splitters

      Existing splitters operate by the following ideas

      • divide by 2 if the amount seems to large after several attampts (I think this is the LND rational)
      • define a fixed number of parts one wishes to have and divide into that many parts (I think this is LDK)
      • define a payment size for the parts and split down to that size ( this is one of the rationals by core lightning)

      Non of the above mentioned ideas start with reliability and can be used to derrive service level objectives. With the method that I proposed one can start with a clear service level objective and get single parts that have all the same success probability and obviously the single parts can be derrived with cost functions that focus more on fees or more on reliability or any other feature that one may find desireable

      While this is not directly an issue I thought I drop this here as there was previously the discussion about splitting heuristics and as mentioned I have to withdraw some of by too strong claims statements.

      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

        , 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Some thoughts on payment splitting heuristics for multi part payments · Issue #2276 · lightningdevkit/rust-lightning · GitHub
        Skip to content

        Some thoughts on payment splitting heuristics for multi part payments #2276

        Description

        @renepickhardt

        This is based on some out of band communication with @TheBlueMatt:

        In #1276 there was the damand to revisit the splitting heuristic of payments in LDK. Back at that day I argued that the splitting problem is exactly what whould be solved throuph optimally reliable payment flows which are proposed to be added in #1668. However I think I have to withdraw or at least weaken some of my claims from before as I will lay out in this issue.

        The following originated from the comments by @TheBlueMatt on the mailinglist :

        While its much less capital-effecient, the ability to over-commit upfront and then only allow the
        recipient to claim a portion of the total committed funds would substantially reduce the impact of
        failed HTLCs on payment latency. Of course the extra round-trip to request the "unlock keys" for the
        correct set of HTLCs adds a chunk to total latency, so senders will have to be careful about
        deciding when to do this or not.

        Still, now that we have onion messages, we should do (well, try) this! Its not super complicated to
        implement (like everything it seems, the obvious implementation forgoes proof-of-payment, and like
        everything the obvious solution is PTLCs, I think). Its not clear to me how we get good data from
        trials, though, we'd need a sufficient set of the network to support this that we could actually
        test it, which is hard to get for a test.

        Maybe someone (anyone?) wants to do some experiments doing simulations using real probing success
        rates to figure out how successful this would be and propose a concrete sender strategy that would
        improve success rates.

        While digging into redundant overpayments I figured out several noteworthy things:

        1. Minimum cost flows may not yield the maximum expected value to be delivered. A counterexample can be seen at: https://github.com/renepickhardt/Maximum-Expected-Value-Flows-For-Redundant-Overpayments/blob/main/img/counterExample.png
        2. Redundant overpayments can be understood as: "At least k out of n payment parts need to successfully reach the recipient". Thus the method of bernoulli trials can be applied (as orginially suggested in the probabilistic path finding paper for non redundant payments)
        3. While in the above mentioned paper I made poor / strange assumptions to the cost function and channel size to develope the theory I now observed that the only neccessary variable for a bernoulli trial is that the success probability for each path has the be (roughly) the same which can be controlled for by defining a target probability for the various paths and assign the sats for that onion / path such that the estimated success probability reaches the target probability.
        4. These observations lead to a natural splitting heuristic - which seems reasonable (in particular but not only for redundant overpayments) and useful in simulations but I don't have the infrastructure or resources to test this in mainnet.

        Summary of the splitting algorithm

        This is currently WIP and many choices are adhoc but it shows the princible. the foolowing is a summary of: renepickhardt/pickhardtpayments#36

        We use dijkstra to compute candidate paths as shortest paths with respect to our cost function

        1. Use a cost function for a unit that is the combination of linearized routing cost and linearized uncertainty cost
        2. smooth the routing cost (currently laplace smoothing with +100. The exact value needs to be found through tests and feature engineering
        3. thus: cost = (ppm + 100) * 1/capacity
        4. After a path is planned increase cost of each edge with a multiplier

        with respect to allocation of funds to paths

        The cost function favors paths with low routing costs thus the only question is how many sats to allocate?
        The following idea shall be used for motivation:

        • We want each path to have a success probability of at least x%
        • Thus let l be the length of the planned path and c be the capacity of the smallest channel.
        • Then s = (c+1-a)/(c+1) is the success probability for the allocated amount a (Of course one does not have to use a uniform distribution to estimate the success probabilities but use a different prior. the following fomulars would however change)
        • We require s >= x ** (1/l) which means the path has a probability of at least x
        • For now we ignore prior knowledge and believe (Thus one reason for this to be WIP)
        • knowing s at equality we solve for a --> a = (c+1) - s*(c+1) = (c+1)*(1-s)
        • we allocate a sats to the candidate path

        Comparison to existing splitters

        Existing splitters operate by the following ideas

        • divide by 2 if the amount seems to large after several attampts (I think this is the LND rational)
        • define a fixed number of parts one wishes to have and divide into that many parts (I think this is LDK)
        • define a payment size for the parts and split down to that size ( this is one of the rationals by core lightning)

        Non of the above mentioned ideas start with reliability and can be used to derrive service level objectives. With the method that I proposed one can start with a clear service level objective and get single parts that have all the same success probability and obviously the single parts can be derrived with cost functions that focus more on fees or more on reliability or any other feature that one may find desireable

        While this is not directly an issue I thought I drop this here as there was previously the discussion about splitting heuristics and as mentioned I have to withdraw some of by too strong claims statements.

        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

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Some thoughts on payment splitting heuristics for multi part payments · Issue #2276 · lightningdevkit/rust-lightning · GitHub
          Skip to content

          Some thoughts on payment splitting heuristics for multi part payments #2276

          Description

          @renepickhardt

          This is based on some out of band communication with @TheBlueMatt:

          In #1276 there was the damand to revisit the splitting heuristic of payments in LDK. Back at that day I argued that the splitting problem is exactly what whould be solved throuph optimally reliable payment flows which are proposed to be added in #1668. However I think I have to withdraw or at least weaken some of my claims from before as I will lay out in this issue.

          The following originated from the comments by @TheBlueMatt on the mailinglist :

          While its much less capital-effecient, the ability to over-commit upfront and then only allow the
          recipient to claim a portion of the total committed funds would substantially reduce the impact of
          failed HTLCs on payment latency. Of course the extra round-trip to request the "unlock keys" for the
          correct set of HTLCs adds a chunk to total latency, so senders will have to be careful about
          deciding when to do this or not.

          Still, now that we have onion messages, we should do (well, try) this! Its not super complicated to
          implement (like everything it seems, the obvious implementation forgoes proof-of-payment, and like
          everything the obvious solution is PTLCs, I think). Its not clear to me how we get good data from
          trials, though, we'd need a sufficient set of the network to support this that we could actually
          test it, which is hard to get for a test.

          Maybe someone (anyone?) wants to do some experiments doing simulations using real probing success
          rates to figure out how successful this would be and propose a concrete sender strategy that would
          improve success rates.

          While digging into redundant overpayments I figured out several noteworthy things:

          1. Minimum cost flows may not yield the maximum expected value to be delivered. A counterexample can be seen at: https://github.com/renepickhardt/Maximum-Expected-Value-Flows-For-Redundant-Overpayments/blob/main/img/counterExample.png
          2. Redundant overpayments can be understood as: "At least k out of n payment parts need to successfully reach the recipient". Thus the method of bernoulli trials can be applied (as orginially suggested in the probabilistic path finding paper for non redundant payments)
          3. While in the above mentioned paper I made poor / strange assumptions to the cost function and channel size to develope the theory I now observed that the only neccessary variable for a bernoulli trial is that the success probability for each path has the be (roughly) the same which can be controlled for by defining a target probability for the various paths and assign the sats for that onion / path such that the estimated success probability reaches the target probability.
          4. These observations lead to a natural splitting heuristic - which seems reasonable (in particular but not only for redundant overpayments) and useful in simulations but I don't have the infrastructure or resources to test this in mainnet.

          Summary of the splitting algorithm

          This is currently WIP and many choices are adhoc but it shows the princible. the foolowing is a summary of: renepickhardt/pickhardtpayments#36

          We use dijkstra to compute candidate paths as shortest paths with respect to our cost function

          1. Use a cost function for a unit that is the combination of linearized routing cost and linearized uncertainty cost
          2. smooth the routing cost (currently laplace smoothing with +100. The exact value needs to be found through tests and feature engineering
          3. thus: cost = (ppm + 100) * 1/capacity
          4. After a path is planned increase cost of each edge with a multiplier

          with respect to allocation of funds to paths

          The cost function favors paths with low routing costs thus the only question is how many sats to allocate?
          The following idea shall be used for motivation:

          • We want each path to have a success probability of at least x%
          • Thus let l be the length of the planned path and c be the capacity of the smallest channel.
          • Then s = (c+1-a)/(c+1) is the success probability for the allocated amount a (Of course one does not have to use a uniform distribution to estimate the success probabilities but use a different prior. the following fomulars would however change)
          • We require s >= x ** (1/l) which means the path has a probability of at least x
          • For now we ignore prior knowledge and believe (Thus one reason for this to be WIP)
          • knowing s at equality we solve for a --> a = (c+1) - s*(c+1) = (c+1)*(1-s)
          • we allocate a sats to the candidate path

          Comparison to existing splitters

          Existing splitters operate by the following ideas

          • divide by 2 if the amount seems to large after several attampts (I think this is the LND rational)
          • define a fixed number of parts one wishes to have and divide into that many parts (I think this is LDK)
          • define a payment size for the parts and split down to that size ( this is one of the rationals by core lightning)

          Non of the above mentioned ideas start with reliability and can be used to derrive service level objectives. With the method that I proposed one can start with a clear service level objective and get single parts that have all the same success probability and obviously the single parts can be derrived with cost functions that focus more on fees or more on reliability or any other feature that one may find desireable

          While this is not directly an issue I thought I drop this here as there was previously the discussion about splitting heuristics and as mentioned I have to withdraw some of by too strong claims statements.

          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

            , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Some thoughts on payment splitting heuristics for multi part payments · Issue #2276 · lightningdevkit/rust-lightning · GitHub
            Skip to content

            Some thoughts on payment splitting heuristics for multi part payments #2276

            Description

            @renepickhardt

            This is based on some out of band communication with @TheBlueMatt:

            In #1276 there was the damand to revisit the splitting heuristic of payments in LDK. Back at that day I argued that the splitting problem is exactly what whould be solved throuph optimally reliable payment flows which are proposed to be added in #1668. However I think I have to withdraw or at least weaken some of my claims from before as I will lay out in this issue.

            The following originated from the comments by @TheBlueMatt on the mailinglist :

            While its much less capital-effecient, the ability to over-commit upfront and then only allow the
            recipient to claim a portion of the total committed funds would substantially reduce the impact of
            failed HTLCs on payment latency. Of course the extra round-trip to request the "unlock keys" for the
            correct set of HTLCs adds a chunk to total latency, so senders will have to be careful about
            deciding when to do this or not.

            Still, now that we have onion messages, we should do (well, try) this! Its not super complicated to
            implement (like everything it seems, the obvious implementation forgoes proof-of-payment, and like
            everything the obvious solution is PTLCs, I think). Its not clear to me how we get good data from
            trials, though, we'd need a sufficient set of the network to support this that we could actually
            test it, which is hard to get for a test.

            Maybe someone (anyone?) wants to do some experiments doing simulations using real probing success
            rates to figure out how successful this would be and propose a concrete sender strategy that would
            improve success rates.

            While digging into redundant overpayments I figured out several noteworthy things:

            1. Minimum cost flows may not yield the maximum expected value to be delivered. A counterexample can be seen at: https://github.com/renepickhardt/Maximum-Expected-Value-Flows-For-Redundant-Overpayments/blob/main/img/counterExample.png
            2. Redundant overpayments can be understood as: "At least k out of n payment parts need to successfully reach the recipient". Thus the method of bernoulli trials can be applied (as orginially suggested in the probabilistic path finding paper for non redundant payments)
            3. While in the above mentioned paper I made poor / strange assumptions to the cost function and channel size to develope the theory I now observed that the only neccessary variable for a bernoulli trial is that the success probability for each path has the be (roughly) the same which can be controlled for by defining a target probability for the various paths and assign the sats for that onion / path such that the estimated success probability reaches the target probability.
            4. These observations lead to a natural splitting heuristic - which seems reasonable (in particular but not only for redundant overpayments) and useful in simulations but I don't have the infrastructure or resources to test this in mainnet.

            Summary of the splitting algorithm

            This is currently WIP and many choices are adhoc but it shows the princible. the foolowing is a summary of: renepickhardt/pickhardtpayments#36

            We use dijkstra to compute candidate paths as shortest paths with respect to our cost function

            1. Use a cost function for a unit that is the combination of linearized routing cost and linearized uncertainty cost
            2. smooth the routing cost (currently laplace smoothing with +100. The exact value needs to be found through tests and feature engineering
            3. thus: cost = (ppm + 100) * 1/capacity
            4. After a path is planned increase cost of each edge with a multiplier

            with respect to allocation of funds to paths

            The cost function favors paths with low routing costs thus the only question is how many sats to allocate?
            The following idea shall be used for motivation:

            • We want each path to have a success probability of at least x%
            • Thus let l be the length of the planned path and c be the capacity of the smallest channel.
            • Then s = (c+1-a)/(c+1) is the success probability for the allocated amount a (Of course one does not have to use a uniform distribution to estimate the success probabilities but use a different prior. the following fomulars would however change)
            • We require s >= x ** (1/l) which means the path has a probability of at least x
            • For now we ignore prior knowledge and believe (Thus one reason for this to be WIP)
            • knowing s at equality we solve for a --> a = (c+1) - s*(c+1) = (c+1)*(1-s)
            • we allocate a sats to the candidate path

            Comparison to existing splitters

            Existing splitters operate by the following ideas

            • divide by 2 if the amount seems to large after several attampts (I think this is the LND rational)
            • define a fixed number of parts one wishes to have and divide into that many parts (I think this is LDK)
            • define a payment size for the parts and split down to that size ( this is one of the rationals by core lightning)

            Non of the above mentioned ideas start with reliability and can be used to derrive service level objectives. With the method that I proposed one can start with a clear service level objective and get single parts that have all the same success probability and obviously the single parts can be derrived with cost functions that focus more on fees or more on reliability or any other feature that one may find desireable

            While this is not directly an issue I thought I drop this here as there was previously the discussion about splitting heuristics and as mentioned I have to withdraw some of by too strong claims statements.

            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

              , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Some thoughts on payment splitting heuristics for multi part payments · Issue #2276 · lightningdevkit/rust-lightning · GitHub
              Skip to content

              Some thoughts on payment splitting heuristics for multi part payments #2276

              Description

              @renepickhardt

              This is based on some out of band communication with @TheBlueMatt:

              In #1276 there was the damand to revisit the splitting heuristic of payments in LDK. Back at that day I argued that the splitting problem is exactly what whould be solved throuph optimally reliable payment flows which are proposed to be added in #1668. However I think I have to withdraw or at least weaken some of my claims from before as I will lay out in this issue.

              The following originated from the comments by @TheBlueMatt on the mailinglist :

              While its much less capital-effecient, the ability to over-commit upfront and then only allow the
              recipient to claim a portion of the total committed funds would substantially reduce the impact of
              failed HTLCs on payment latency. Of course the extra round-trip to request the "unlock keys" for the
              correct set of HTLCs adds a chunk to total latency, so senders will have to be careful about
              deciding when to do this or not.

              Still, now that we have onion messages, we should do (well, try) this! Its not super complicated to
              implement (like everything it seems, the obvious implementation forgoes proof-of-payment, and like
              everything the obvious solution is PTLCs, I think). Its not clear to me how we get good data from
              trials, though, we'd need a sufficient set of the network to support this that we could actually
              test it, which is hard to get for a test.

              Maybe someone (anyone?) wants to do some experiments doing simulations using real probing success
              rates to figure out how successful this would be and propose a concrete sender strategy that would
              improve success rates.

              While digging into redundant overpayments I figured out several noteworthy things:

              1. Minimum cost flows may not yield the maximum expected value to be delivered. A counterexample can be seen at: https://github.com/renepickhardt/Maximum-Expected-Value-Flows-For-Redundant-Overpayments/blob/main/img/counterExample.png
              2. Redundant overpayments can be understood as: "At least k out of n payment parts need to successfully reach the recipient". Thus the method of bernoulli trials can be applied (as orginially suggested in the probabilistic path finding paper for non redundant payments)
              3. While in the above mentioned paper I made poor / strange assumptions to the cost function and channel size to develope the theory I now observed that the only neccessary variable for a bernoulli trial is that the success probability for each path has the be (roughly) the same which can be controlled for by defining a target probability for the various paths and assign the sats for that onion / path such that the estimated success probability reaches the target probability.
              4. These observations lead to a natural splitting heuristic - which seems reasonable (in particular but not only for redundant overpayments) and useful in simulations but I don't have the infrastructure or resources to test this in mainnet.

              Summary of the splitting algorithm

              This is currently WIP and many choices are adhoc but it shows the princible. the foolowing is a summary of: renepickhardt/pickhardtpayments#36

              We use dijkstra to compute candidate paths as shortest paths with respect to our cost function

              1. Use a cost function for a unit that is the combination of linearized routing cost and linearized uncertainty cost
              2. smooth the routing cost (currently laplace smoothing with +100. The exact value needs to be found through tests and feature engineering
              3. thus: cost = (ppm + 100) * 1/capacity
              4. After a path is planned increase cost of each edge with a multiplier

              with respect to allocation of funds to paths

              The cost function favors paths with low routing costs thus the only question is how many sats to allocate?
              The following idea shall be used for motivation:

              • We want each path to have a success probability of at least x%
              • Thus let l be the length of the planned path and c be the capacity of the smallest channel.
              • Then s = (c+1-a)/(c+1) is the success probability for the allocated amount a (Of course one does not have to use a uniform distribution to estimate the success probabilities but use a different prior. the following fomulars would however change)
              • We require s >= x ** (1/l) which means the path has a probability of at least x
              • For now we ignore prior knowledge and believe (Thus one reason for this to be WIP)
              • knowing s at equality we solve for a --> a = (c+1) - s*(c+1) = (c+1)*(1-s)
              • we allocate a sats to the candidate path

              Comparison to existing splitters

              Existing splitters operate by the following ideas

              • divide by 2 if the amount seems to large after several attampts (I think this is the LND rational)
              • define a fixed number of parts one wishes to have and divide into that many parts (I think this is LDK)
              • define a payment size for the parts and split down to that size ( this is one of the rationals by core lightning)

              Non of the above mentioned ideas start with reliability and can be used to derrive service level objectives. With the method that I proposed one can start with a clear service level objective and get single parts that have all the same success probability and obviously the single parts can be derrived with cost functions that focus more on fees or more on reliability or any other feature that one may find desireable

              While this is not directly an issue I thought I drop this here as there was previously the discussion about splitting heuristics and as mentioned I have to withdraw some of by too strong claims statements.

              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