Skip to content

Commit

Permalink
routing: simplify BuildRoute
Browse files Browse the repository at this point in the history
With newRoute being aware of min_htlc constraints, there
is no more need to do a forward pass in BuildRoute. This
also fixes potential edge cases where the forward pass
gets to a payment amount that still violates htlc ranges.

The downside of this simplification is that more value may
be dropped off along the path as fees rather than paying
extra to the final hop. However, as the primary intention
of the BuildRoute `min_amt` flag is to allow for cheap
probes, this change is likely to have no consequences.
  • Loading branch information
joostjager committed Sep 13, 2022
1 parent 3df0ff9 commit 4f6cde9
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 71 deletions.
16 changes: 0 additions & 16 deletions channeldb/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -3489,22 +3489,6 @@ func (c *ChannelEdgePolicy) ComputeFee(
return c.FeeBaseMSat + (amt*c.FeeProportionalMillionths)/feeRateParts
}

// divideCeil divides dividend by factor and rounds the result up.
func divideCeil(dividend, factor lnwire.MilliSatoshi) lnwire.MilliSatoshi {
return (dividend + factor - 1) / factor
}

// ComputeFeeFromIncoming computes the fee to forward an HTLC given the incoming
// amount.
func (c *ChannelEdgePolicy) ComputeFeeFromIncoming(
incomingAmt lnwire.MilliSatoshi) lnwire.MilliSatoshi {

return incomingAmt - divideCeil(
feeRateParts*(incomingAmt-c.FeeBaseMSat),
feeRateParts+c.FeeProportionalMillionths,
)
}

// FetchChannelEdgesByOutpoint attempts to lookup the two directed edges for
// the channel identified by the funding outpoint. If the channel can't be
// found, then ErrEdgeNotFound is returned. A struct which houses the general
Expand Down
11 changes: 0 additions & 11 deletions channeldb/graph_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,6 @@ func (c *CachedEdgePolicy) ComputeFee(
return c.FeeBaseMSat + (amt*c.FeeProportionalMillionths)/feeRateParts
}

// ComputeFeeFromIncoming computes the fee to forward an HTLC given the incoming
// amount.
func (c *CachedEdgePolicy) ComputeFeeFromIncoming(
incomingAmt lnwire.MilliSatoshi) lnwire.MilliSatoshi {

return incomingAmt - divideCeil(
feeRateParts*(incomingAmt-c.FeeBaseMSat),
feeRateParts+c.FeeProportionalMillionths,
)
}

// NewCachedPolicy turns a full policy into a minimal one that can be cached.
func NewCachedPolicy(policy *ChannelEdgePolicy) *CachedEdgePolicy {
return &CachedEdgePolicy{
Expand Down
5 changes: 0 additions & 5 deletions channeldb/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3264,11 +3264,6 @@ func TestComputeFee(t *testing.T) {
if fee != expectedFee {
t.Fatalf("expected fee %v, got %v", expectedFee, fee)
}

fwdFee := policy.ComputeFeeFromIncoming(outgoingAmt + fee)
if fwdFee != expectedFee {
t.Fatalf("expected fee %v, but got %v", fee, fwdFee)
}
}

// TestBatchedAddChannelEdge asserts that BatchedAddChannelEdge properly
Expand Down
52 changes: 13 additions & 39 deletions routing/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -2731,22 +2731,23 @@ func (r *ChannelRouter) BuildRoute(amt *lnwire.MilliSatoshi,

// Allocate a list that will contain the unified policies for this
// route.
edges := make([]*unifiedPolicy, len(hops))
edges := make([]*channeldb.CachedEdgePolicy, len(hops))

var runningAmt lnwire.MilliSatoshi
var paymentAmt lnwire.MilliSatoshi
if useMinAmt {
// For minimum amount routes, aim to deliver at least 1 msat to
// the destination. There are nodes in the wild that have a
// min_htlc channel policy of zero, which could lead to a zero
// amount payment being made.
runningAmt = 1
paymentAmt = 1
} else {
// If an amount is specified, we need to build a route that
// delivers exactly this amount to the final destination.
runningAmt = *amt
paymentAmt = *amt
}

// Traverse hops backwards to accumulate fees in the running amounts.
runningAmt := paymentAmt
source := r.selfNode.PubKeyBytes
for i := len(hops) - 1; i >= 0; i-- {
toNode := hops[i]
Expand Down Expand Up @@ -2778,12 +2779,10 @@ func (r *ChannelRouter) BuildRoute(amt *lnwire.MilliSatoshi,
}
}

// If using min amt, increase amt if needed.
if useMinAmt {
min := unifiedPolicy.minAmt()
if min > runningAmt {
runningAmt = min
}
// Increase amount if needed to satisfy minimum htlc size.
min := unifiedPolicy.minAmt()
if min > runningAmt {
runningAmt = min
}

// Get a forwarding policy for the specific amount that we want
Expand All @@ -2803,40 +2802,15 @@ func (r *ChannelRouter) BuildRoute(amt *lnwire.MilliSatoshi,

log.Tracef("Select channel %v at position %v", policy.ChannelID, i)

edges[i] = unifiedPolicy
}

// Now that we arrived at the start of the route and found out the route
// total amount, we make a forward pass. Because the amount may have
// been increased in the backward pass, fees need to be recalculated and
// amount ranges re-checked.
var pathEdges []*channeldb.CachedEdgePolicy
receiverAmt := runningAmt
for i, edge := range edges {
policy := edge.getPolicy(receiverAmt, bandwidthHints)
if policy == nil {
return nil, ErrNoChannel{
fromNode: hops[i-1],
position: i,
}
}

if i > 0 {
// Decrease the amount to send while going forward.
receiverAmt -= policy.ComputeFeeFromIncoming(
receiverAmt,
)
}

pathEdges = append(pathEdges, policy)
edges[i] = policy
}

// Build and return the final route.
return newRoute(
source, pathEdges, uint32(height),
source, edges, uint32(height),
finalHopParams{
amt: receiverAmt,
totalAmt: receiverAmt,
amt: paymentAmt,
totalAmt: paymentAmt,
cltvDelta: uint16(finalCltvDelta),
records: nil,
paymentAddr: payAddr,
Expand Down

0 comments on commit 4f6cde9

Please sign in to comment.