|
5 | 5 | "context" |
6 | 6 | "fmt" |
7 | 7 | "math" |
| 8 | + "math/big" |
8 | 9 | "sort" |
9 | 10 | "sync" |
10 | 11 | "sync/atomic" |
@@ -836,6 +837,7 @@ func generateSphinxPacket(rt *route.Route, paymentHash []byte, |
836 | 837 | hopCopy := sphinxPath[i] |
837 | 838 | path[i] = hopCopy |
838 | 839 | } |
| 840 | + |
839 | 841 | return spew.Sdump(path) |
840 | 842 | }), |
841 | 843 | ) |
@@ -1670,3 +1672,224 @@ func receiverAmtForwardPass(runningAmt lnwire.MilliSatoshi, |
1670 | 1672 |
|
1671 | 1673 | return runningAmt, nil |
1672 | 1674 | } |
| 1675 | + |
| 1676 | +// incomingFromOutgoing computes the incoming amount based on the outgoing |
| 1677 | +// amount by adding fees to the outgoing amount, replicating the path finding |
| 1678 | +// and routing process, see also CheckHtlcForward. |
| 1679 | +func incomingFromOutgoing(outgoingAmt lnwire.MilliSatoshi, |
| 1680 | + incoming, outgoing *unifiedEdge) lnwire.MilliSatoshi { |
| 1681 | + |
| 1682 | + outgoingFee := outgoing.policy.ComputeFee(outgoingAmt) |
| 1683 | + |
| 1684 | + // Net amount is the amount the inbound fees are calculated with. |
| 1685 | + netAmount := outgoingAmt + outgoingFee |
| 1686 | + |
| 1687 | + inboundFee := incoming.inboundFees.CalcFee(netAmount) |
| 1688 | + |
| 1689 | + // The inbound fee is not allowed to reduce the incoming amount below |
| 1690 | + // the outgoing amount. |
| 1691 | + if int64(outgoingFee)+inboundFee < 0 { |
| 1692 | + return outgoingAmt |
| 1693 | + } |
| 1694 | + |
| 1695 | + return netAmount + lnwire.MilliSatoshi(inboundFee) |
| 1696 | +} |
| 1697 | + |
| 1698 | +// outgoingFromIncoming computes the outgoing amount based on the incoming |
| 1699 | +// amount by subtracting fees from the incoming amount. Note that this is not |
| 1700 | +// exactly the inverse of incomingFromOutgoing, because of some rounding. |
| 1701 | +func outgoingFromIncoming(incomingAmt lnwire.MilliSatoshi, |
| 1702 | + incoming, outgoing *unifiedEdge) lnwire.MilliSatoshi { |
| 1703 | + |
| 1704 | + // Convert all quantities to big.Int to be able to hande negative |
| 1705 | + // values. The formulas to compute the outgoing amount involve terms |
| 1706 | + // with PPM*PPM*A, which can easily overflow an int64. |
| 1707 | + A := big.NewInt(int64(incomingAmt)) |
| 1708 | + Ro := big.NewInt(int64(outgoing.policy.FeeProportionalMillionths)) |
| 1709 | + Bo := big.NewInt(int64(outgoing.policy.FeeBaseMSat)) |
| 1710 | + Ri := big.NewInt(int64(incoming.inboundFees.Rate)) |
| 1711 | + Bi := big.NewInt(int64(incoming.inboundFees.Base)) |
| 1712 | + PPM := big.NewInt(1_000_000) |
| 1713 | + |
| 1714 | + // The following discussion was contributed by user feelancer21, see |
| 1715 | + //nolint:lll |
| 1716 | + // https://github.com/feelancer21/lnd/commit/f6f05fa930985aac0d27c3f6681aada1b599162a. |
| 1717 | + |
| 1718 | + // The incoming amount Ai based on the outgoing amount Ao is computed by |
| 1719 | + // Ai = max(Ai(Ao), Ao), which caps the incoming amount such that the |
| 1720 | + // total node fee (Ai - Ao) is non-negative. This is commonly enforced |
| 1721 | + // by routing nodes. |
| 1722 | + |
| 1723 | + // The function Ai(Ao) is given by: |
| 1724 | + // Ai(Ao) = (Ao + Bo + Ro/PPM) + (Bi + (Ao + Ro/PPM + Bo)*Ri/PPM), where |
| 1725 | + // the first term is the net amount (the outgoing amount plus the |
| 1726 | + // outbound fee), and the second is the inbound fee computed based on |
| 1727 | + // the net amount. |
| 1728 | + |
| 1729 | + // Ai(Ao) can potentially become more negative in absolute value than |
| 1730 | + // Ao, which is why the above mentioned capping is needed. We can |
| 1731 | + // abbreviate Ai(Ao) with Ai(Ao) = m*Ao + n, where m and n are: |
| 1732 | + // m := (1 + Ro/PPM) * (1 + Ri/PPM) |
| 1733 | + // n := Bi + Bo*(1 + Ri/PPM) |
| 1734 | + |
| 1735 | + // If we know that m > 0, this is equivalent of Ri/PPM > -1, because Ri |
| 1736 | + // is the only factor that can become negative. A value or Ri/PPM = -1, |
| 1737 | + // means that the routing node is willing to give up on 100% of the |
| 1738 | + // net amount (based on the fee rate), which is likely to not happen in |
| 1739 | + // practice. This condition will be important for a later trick. |
| 1740 | + |
| 1741 | + // If we want to compute the incoming amount based on the outgoing |
| 1742 | + // amount, which is the reverse problem, we need to solve Ai = |
| 1743 | + // max(Ai(Ao), Ao) for Ao(Ai). Given an incoming amount A, |
| 1744 | + // we look for an Ao such that A = max(Ai(Ao), Ao). |
| 1745 | + |
| 1746 | + // The max function separates this into two cases. The case to take is |
| 1747 | + // not clear yet, because we don't know Ao, but later we see a trick |
| 1748 | + // how to determine which case is the one to take. |
| 1749 | + |
| 1750 | + // first case: Ai(Ao) <= Ao: |
| 1751 | + // Therefore, A = max(Ai(Ao), Ao) = Ao, we find Ao = A. |
| 1752 | + // This also leads to Ai(A) <= A by substitution into the condition. |
| 1753 | + |
| 1754 | + // second case: Ai(Ao) > Ao: |
| 1755 | + // Therefore, A = max(Ai(Ao), Ao) = Ai(Ao) = m*Ao + n. Solving for Ao |
| 1756 | + // gives Ao = (A - n)/m. |
| 1757 | + // |
| 1758 | + // We know |
| 1759 | + // Ai(Ao) > Ao <=> A = Ai(Ao) > Ao = (A - n)/m, |
| 1760 | + // so A > (A - n)/m. |
| 1761 | + // |
| 1762 | + // **Assuming m > 0**, by multiplying with m, we can transform this to |
| 1763 | + // A * m + n > A. |
| 1764 | + // |
| 1765 | + // We know Ai(A) = A*m + n, therefore Ai(A) > A. |
| 1766 | + // |
| 1767 | + // This means that if we apply the incoming amount calculation to the |
| 1768 | + // **incoming** amount, and this condition holds, then we know that we |
| 1769 | + // deal with the second case, being able to compute the outgoing amount |
| 1770 | + // based off the formula Ao = (A - n)/m, otherwise we will just return |
| 1771 | + // the incoming amount. |
| 1772 | + |
| 1773 | + // In case the inbound fee rate is less than -1 (-100%), we fail to |
| 1774 | + // compute the outbound amount and return the incoming amount. This also |
| 1775 | + // protects against zero division later. |
| 1776 | + |
| 1777 | + // We compute m in terms of big.Int to be safe from overflows and to be |
| 1778 | + // consistent with later calculations. |
| 1779 | + // m := (PPM*PPM + Ri*PPM + Ro*PPM + Ro*Ri)/(PPM*PPM) |
| 1780 | + |
| 1781 | + // Compute terms in (PPM*PPM + Ri*PPM + Ro*PPM + Ro*Ri). |
| 1782 | + m1 := new(big.Int).Mul(PPM, PPM) |
| 1783 | + m2 := new(big.Int).Mul(Ri, PPM) |
| 1784 | + m3 := new(big.Int).Mul(Ro, PPM) |
| 1785 | + m4 := new(big.Int).Mul(Ro, Ri) |
| 1786 | + |
| 1787 | + // Add up terms m1..m4. |
| 1788 | + m := big.NewInt(0) |
| 1789 | + m.Add(m, m1) |
| 1790 | + m.Add(m, m2) |
| 1791 | + m.Add(m, m3) |
| 1792 | + m.Add(m, m4) |
| 1793 | + |
| 1794 | + // Since we compare to 0, we can multiply by PPM*PPM to avoid the |
| 1795 | + // division. |
| 1796 | + if m.Int64() <= 0 { |
| 1797 | + return incomingAmt |
| 1798 | + } |
| 1799 | + |
| 1800 | + // In order to decide if the total fee is negative, we apply the fee |
| 1801 | + // to the *incoming* amount as mentioned before. |
| 1802 | + |
| 1803 | + // We compute the test amount in terms of big.Int to be safe from |
| 1804 | + // overflows and to be consistent later calculations. |
| 1805 | + // testAmtF := A*m + n = |
| 1806 | + // = A + Bo + Bi + (PPM*(A*Ri + A*Ro + Ro*Ri) + A*Ri*Ro)/(PPM*PPM) |
| 1807 | + |
| 1808 | + // Compute terms in (A*Ri + A*Ro + Ro*Ri). |
| 1809 | + t1 := new(big.Int).Mul(A, Ri) |
| 1810 | + t2 := new(big.Int).Mul(A, Ro) |
| 1811 | + t3 := new(big.Int).Mul(Ro, Ri) |
| 1812 | + |
| 1813 | + // Sum up terms t1-t3. |
| 1814 | + t4 := big.NewInt(0) |
| 1815 | + t4.Add(t4, t1) |
| 1816 | + t4.Add(t4, t2) |
| 1817 | + t4.Add(t4, t3) |
| 1818 | + |
| 1819 | + // Compute PPM*(A*Ri + A*Ro + Ro*Ri). |
| 1820 | + t6 := new(big.Int).Mul(PPM, t4) |
| 1821 | + |
| 1822 | + // Compute A*Ri*Ro. |
| 1823 | + t7 := new(big.Int).Mul(A, Ri) |
| 1824 | + t7.Mul(t7, Ro) |
| 1825 | + |
| 1826 | + // Compute (PPM*(A*Ri + A*Ro + Ro*Ri) + A*Ri*Ro)/(PPM*PPM). |
| 1827 | + num := new(big.Int).Add(t6, t7) |
| 1828 | + denom := new(big.Int).Mul(PPM, PPM) |
| 1829 | + fraction := new(big.Int).Div(num, denom) |
| 1830 | + |
| 1831 | + // Sum up all terms. |
| 1832 | + testAmt := big.NewInt(0) |
| 1833 | + testAmt.Add(testAmt, A) |
| 1834 | + testAmt.Add(testAmt, Bo) |
| 1835 | + testAmt.Add(testAmt, Bi) |
| 1836 | + testAmt.Add(testAmt, fraction) |
| 1837 | + |
| 1838 | + // Protect against negative values for the integer cast to Msat. |
| 1839 | + if testAmt.Int64() < 0 { |
| 1840 | + return incomingAmt |
| 1841 | + } |
| 1842 | + |
| 1843 | + // If the second case holds, we have to compute the outgoing amount. |
| 1844 | + if lnwire.MilliSatoshi(testAmt.Int64()) > incomingAmt { |
| 1845 | + // Compute the outgoing amount by integer ceiling division. This |
| 1846 | + // precision is needed because PPM*PPM*A and other terms can |
| 1847 | + // easily overflow with int64, which happens with about |
| 1848 | + // A = 10_000 sat. |
| 1849 | + |
| 1850 | + // out := (A - n) / m = numerator / denominator |
| 1851 | + // numerator := PPM*(PPM*(A - Bo - Bi) - Bo*Ri) |
| 1852 | + // denominator := PPM*(PPM + Ri + Ro) + Ri*Ro |
| 1853 | + |
| 1854 | + var numerator big.Int |
| 1855 | + |
| 1856 | + // Compute (A - Bo - Bi). |
| 1857 | + temp1 := new(big.Int).Sub(A, Bo) |
| 1858 | + temp2 := new(big.Int).Sub(temp1, Bi) |
| 1859 | + |
| 1860 | + // Compute terms in (PPM*(A - Bo - Bi) - Bo*Ri). |
| 1861 | + temp3 := new(big.Int).Mul(PPM, temp2) |
| 1862 | + temp4 := new(big.Int).Mul(Bo, Ri) |
| 1863 | + |
| 1864 | + // Compute PPM*(PPM*(A - Bo - Bi) - Bo*Ri) |
| 1865 | + temp5 := new(big.Int).Sub(temp3, temp4) |
| 1866 | + numerator.Mul(PPM, temp5) |
| 1867 | + |
| 1868 | + var denominator big.Int |
| 1869 | + |
| 1870 | + // Compute (PPM + Ri + Ro). |
| 1871 | + temp1 = new(big.Int).Add(PPM, Ri) |
| 1872 | + temp2 = new(big.Int).Add(temp1, Ro) |
| 1873 | + |
| 1874 | + // Compute PPM*(PPM + Ri + Ro) + Ri*Ro. |
| 1875 | + temp3 = new(big.Int).Mul(PPM, temp2) |
| 1876 | + temp4 = new(big.Int).Mul(Ri, Ro) |
| 1877 | + denominator.Add(temp3, temp4) |
| 1878 | + |
| 1879 | + // We overestimate the outgoing amount by taking the ceiling of |
| 1880 | + // the division. This means that we may round slightly up by a |
| 1881 | + // MilliSatoshi, but this helps to ensure that we don't hit min |
| 1882 | + // HTLC constrains in the context of finding the minimum amount |
| 1883 | + // of a route. |
| 1884 | + // ceil = floor((numerator + denominator - 1) / denominator) |
| 1885 | + ceil := new(big.Int).Add(&numerator, &denominator) |
| 1886 | + ceil.Sub(ceil, big.NewInt(1)) |
| 1887 | + ceil.Div(ceil, &denominator) |
| 1888 | + |
| 1889 | + return lnwire.MilliSatoshi(ceil.Int64()) |
| 1890 | + } |
| 1891 | + |
| 1892 | + // Otherwise the inbound fee made up for the outbound fee, which is why |
| 1893 | + // we just return the incoming amount. |
| 1894 | + return incomingAmt |
| 1895 | +} |
0 commit comments