routing: update path finding and notifications to use mSAT
This commit is contained in:
parent
862af6f2d4
commit
6467fdd829
@ -9,6 +9,7 @@ import (
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/roasbeef/btcd/btcec"
|
||||
"github.com/roasbeef/btcd/wire"
|
||||
"github.com/roasbeef/btcutil"
|
||||
@ -254,15 +255,15 @@ type ChannelEdgeUpdate struct {
|
||||
Capacity btcutil.Amount
|
||||
|
||||
// MinHTLC is the minimum HTLC amount that this channel will forward.
|
||||
MinHTLC btcutil.Amount
|
||||
MinHTLC lnwire.MilliSatoshi
|
||||
|
||||
// BaseFee is the base fee that will charged for all HTLC's forwarded
|
||||
// across the this channel direction.
|
||||
BaseFee btcutil.Amount
|
||||
BaseFee lnwire.MilliSatoshi
|
||||
|
||||
// FeeRate is the fee rate that will be shared for all HTLC's forwarded
|
||||
// across this channel direction.
|
||||
FeeRate btcutil.Amount
|
||||
FeeRate lnwire.MilliSatoshi
|
||||
|
||||
// TimeLockDelta is the time-lock expressed in blocks that will be
|
||||
// added to outgoing HTLC's from incoming HTLC's. This value is the
|
||||
|
@ -71,22 +71,22 @@ func randEdgePolicy(chanID *lnwire.ShortChannelID,
|
||||
ChannelID: chanID.ToUint64(),
|
||||
LastUpdate: time.Unix(int64(prand.Int31()), 0),
|
||||
TimeLockDelta: uint16(prand.Int63()),
|
||||
MinHTLC: btcutil.Amount(prand.Int31()),
|
||||
FeeBaseMSat: btcutil.Amount(prand.Int31()),
|
||||
FeeProportionalMillionths: btcutil.Amount(prand.Int31()),
|
||||
MinHTLC: lnwire.MilliSatoshi(prand.Int31()),
|
||||
FeeBaseMSat: lnwire.MilliSatoshi(prand.Int31()),
|
||||
FeeProportionalMillionths: lnwire.MilliSatoshi(prand.Int31()),
|
||||
Node: node,
|
||||
}
|
||||
}
|
||||
|
||||
func createChannelEdge(ctx *testCtx, bitcoinKey1, bitcoinKey2 []byte,
|
||||
chanValue int64, fundingHeight uint32) (*wire.MsgTx, *wire.OutPoint,
|
||||
chanValue btcutil.Amount, fundingHeight uint32) (*wire.MsgTx, *wire.OutPoint,
|
||||
*lnwire.ShortChannelID, error) {
|
||||
|
||||
fundingTx := wire.NewMsgTx(2)
|
||||
_, tx, err := lnwallet.GenFundingPkScript(
|
||||
bitcoinKey1,
|
||||
bitcoinKey2,
|
||||
chanValue,
|
||||
int64(chanValue),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
@ -365,17 +365,17 @@ func TestEdgeUpdateNotification(t *testing.T) {
|
||||
t.Fatalf("capacity of edge doesn't match: "+
|
||||
"expected %v, got %v", chanValue, edgeUpdate.Capacity)
|
||||
}
|
||||
if edgeUpdate.MinHTLC != btcutil.Amount(edgeAnn.MinHTLC) {
|
||||
if edgeUpdate.MinHTLC != edgeAnn.MinHTLC {
|
||||
t.Fatalf("min HTLC of edge doesn't match: "+
|
||||
"expected %v, got %v", btcutil.Amount(edgeAnn.MinHTLC),
|
||||
"expected %v, got %v", edgeAnn.MinHTLC,
|
||||
edgeUpdate.MinHTLC)
|
||||
}
|
||||
if edgeUpdate.BaseFee != btcutil.Amount(edgeAnn.FeeBaseMSat) {
|
||||
if edgeUpdate.BaseFee != edgeAnn.FeeBaseMSat {
|
||||
t.Fatalf("base fee of edge doesn't match: "+
|
||||
"expected %v, got %v", edgeAnn.FeeBaseMSat,
|
||||
edgeUpdate.BaseFee)
|
||||
}
|
||||
if edgeUpdate.FeeRate != btcutil.Amount(edgeAnn.FeeProportionalMillionths) {
|
||||
if edgeUpdate.FeeRate != edgeAnn.FeeProportionalMillionths {
|
||||
t.Fatalf("fee rate of edge doesn't match: "+
|
||||
"expected %v, got %v", edgeAnn.FeeProportionalMillionths,
|
||||
edgeUpdate.FeeRate)
|
||||
|
@ -2,6 +2,7 @@ package routing
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"container/heap"
|
||||
@ -9,6 +10,7 @@ import (
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/roasbeef/btcd/btcec"
|
||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||
"github.com/roasbeef/btcutil"
|
||||
@ -60,18 +62,18 @@ type Hop struct {
|
||||
// AmtToForward is the amount that this hop will forward to the next
|
||||
// hop. This value is less than the value that the incoming HTLC
|
||||
// carries as a fee will be subtracted by the hop.
|
||||
AmtToForward btcutil.Amount
|
||||
AmtToForward lnwire.MilliSatoshi
|
||||
|
||||
// Fee is the total fee that this hop will subtract from the incoming
|
||||
// payment, this difference nets the hop fees for forwarding the
|
||||
// payment.
|
||||
Fee btcutil.Amount
|
||||
Fee lnwire.MilliSatoshi
|
||||
}
|
||||
|
||||
// computeFee computes the fee to forward an HTLC of `amt` satoshis over the
|
||||
// passed active payment channel. This value is currently computed as specified
|
||||
// in BOLT07, but will likely change in the near future.
|
||||
func computeFee(amt btcutil.Amount, edge *ChannelHop) btcutil.Amount {
|
||||
// computeFee computes the fee to forward an HTLC of `amt` milli-satoshis over
|
||||
// the passed active payment channel. This value is currently computed as
|
||||
// specified in BOLT07, but will likely change in the near future.
|
||||
func computeFee(amt lnwire.MilliSatoshi, edge *ChannelHop) lnwire.MilliSatoshi {
|
||||
return edge.FeeBaseMSat + (amt*edge.FeeProportionalMillionths)/1000000
|
||||
}
|
||||
|
||||
@ -108,7 +110,7 @@ type Route struct {
|
||||
// TotalFees is the sum of the fees paid at each hop within the final
|
||||
// route. In the case of a one-hop payment, this value will be zero as
|
||||
// we don't need to pay a fee it ourself.
|
||||
TotalFees btcutil.Amount
|
||||
TotalFees lnwire.MilliSatoshi
|
||||
|
||||
// TotalAmount is the total amount of funds required to complete a
|
||||
// payment over this route. This value includes the cumulative fees at
|
||||
@ -116,7 +118,7 @@ type Route struct {
|
||||
// route will need to have at least this many satoshis, otherwise the
|
||||
// route will fail at an intermediate node due to an insufficient
|
||||
// amount of fees.
|
||||
TotalAmount btcutil.Amount
|
||||
TotalAmount lnwire.MilliSatoshi
|
||||
|
||||
// Hops contains details concerning the specific forwarding details at
|
||||
// each hop.
|
||||
@ -199,7 +201,7 @@ func (s sortableRoutes) Swap(i, j int) {
|
||||
//
|
||||
// NOTE: The passed slice of ChannelHops MUST be sorted in forward order: from
|
||||
// the source to the target node of the path finding attempt.
|
||||
func newRoute(amtToSend btcutil.Amount, pathEdges []*ChannelHop,
|
||||
func newRoute(amtToSend lnwire.MilliSatoshi, pathEdges []*ChannelHop,
|
||||
currentHeight uint32) (*Route, error) {
|
||||
|
||||
// First, we'll create a new empty route with enough hops to match the
|
||||
@ -236,9 +238,13 @@ func newRoute(amtToSend btcutil.Amount, pathEdges []*ChannelHop,
|
||||
// As a sanity check, we ensure that the selected channel has
|
||||
// enough capacity to forward the required amount which
|
||||
// includes the fee dictated at each hop.
|
||||
if nextHop.AmtToForward > nextHop.Channel.Capacity {
|
||||
return nil, newErrf(ErrInsufficientCapacity, "channel graph has "+
|
||||
"insufficient capacity for the payment")
|
||||
if nextHop.AmtToForward.ToSatoshis() > nextHop.Channel.Capacity {
|
||||
err := fmt.Sprintf("channel graph has insufficient "+
|
||||
"capacity for the payment: need %v, have %v",
|
||||
nextHop.AmtToForward.ToSatoshis(),
|
||||
nextHop.Channel.Capacity)
|
||||
|
||||
return nil, newErrf(ErrInsufficientCapacity, err)
|
||||
}
|
||||
|
||||
// We don't pay any fees to ourselves on the first-hop channel,
|
||||
@ -329,7 +335,7 @@ func edgeWeight(e *channeldb.ChannelEdgePolicy) float64 {
|
||||
// from the target to the source.
|
||||
func findPath(graph *channeldb.ChannelGraph, sourceNode *channeldb.LightningNode,
|
||||
target *btcec.PublicKey, ignoredNodes map[vertex]struct{},
|
||||
ignoredEdges map[uint64]struct{}, amt btcutil.Amount) ([]*ChannelHop, error) {
|
||||
ignoredEdges map[uint64]struct{}, amt lnwire.MilliSatoshi) ([]*ChannelHop, error) {
|
||||
|
||||
// First we'll initialize an empty heap which'll help us to quickly
|
||||
// locate the next edge we should visit next during our graph
|
||||
@ -414,7 +420,7 @@ func findPath(graph *channeldb.ChannelGraph, sourceNode *channeldb.LightningNode
|
||||
// off irrelevant edges by adding the sufficient
|
||||
// capacity of an edge to our relaxation condition.
|
||||
if tempDist < distance[v].dist &&
|
||||
edgeInfo.Capacity >= amt {
|
||||
edgeInfo.Capacity >= amt.ToSatoshis() {
|
||||
|
||||
// TODO(roasbeef): need to also account
|
||||
// for min HTLC
|
||||
@ -497,7 +503,7 @@ func findPath(graph *channeldb.ChannelGraph, sourceNode *channeldb.LightningNode
|
||||
// algorithm, rather than attempting to use an unmodified path finding
|
||||
// algorithm in a block box manner.
|
||||
func findPaths(graph *channeldb.ChannelGraph, source *channeldb.LightningNode,
|
||||
target *btcec.PublicKey, amt btcutil.Amount) ([][]*ChannelHop, error) {
|
||||
target *btcec.PublicKey, amt lnwire.MilliSatoshi) ([][]*ChannelHop, error) {
|
||||
|
||||
ignoredEdges := make(map[uint64]struct{})
|
||||
ignoredVertexes := make(map[vertex]struct{})
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/roasbeef/btcd/btcec"
|
||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||
"github.com/roasbeef/btcd/wire"
|
||||
@ -265,9 +266,9 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err
|
||||
ChannelID: edge.ChannelID,
|
||||
LastUpdate: time.Now(),
|
||||
TimeLockDelta: edge.Expiry,
|
||||
MinHTLC: btcutil.Amount(edge.MinHTLC),
|
||||
FeeBaseMSat: btcutil.Amount(edge.FeeBaseMsat),
|
||||
FeeProportionalMillionths: btcutil.Amount(edge.FeeRate),
|
||||
MinHTLC: lnwire.MilliSatoshi(edge.MinHTLC),
|
||||
FeeBaseMSat: lnwire.MilliSatoshi(edge.FeeBaseMsat),
|
||||
FeeProportionalMillionths: lnwire.MilliSatoshi(edge.FeeRate),
|
||||
}
|
||||
|
||||
// As the graph itself is directed, we need to insert two edges
|
||||
@ -312,7 +313,7 @@ func TestBasicGraphPathFinding(t *testing.T) {
|
||||
// finding.
|
||||
const startingHeight = 100
|
||||
|
||||
const paymentAmt = btcutil.Amount(100)
|
||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||
target := aliases["sophon"]
|
||||
path, err := findPath(graph, sourceNode, target, ignoredVertexes,
|
||||
ignoredEdges, paymentAmt)
|
||||
@ -465,7 +466,7 @@ func TestKShortestPathFinding(t *testing.T) {
|
||||
// ji. Our algorithm should properly find both paths, and also rank
|
||||
// them in order of their total "distance".
|
||||
|
||||
const paymentAmt = btcutil.Amount(100)
|
||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||
target := aliases["luoji"]
|
||||
paths, err := findPaths(graph, sourceNode, target, paymentAmt)
|
||||
if err != nil {
|
||||
@ -523,7 +524,7 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
||||
ignoredEdges := make(map[uint64]struct{})
|
||||
ignoredVertexes := make(map[vertex]struct{})
|
||||
|
||||
const paymentAmt = btcutil.Amount(100)
|
||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||
|
||||
// We start by confirminig that routing a payment 20 hops away is possible.
|
||||
// Alice should be able to find a valid route to ursula.
|
||||
|
@ -71,19 +71,16 @@ type ChannelGraphSource interface {
|
||||
// FeeSchema is the set fee configuration for a Lighting Node on the network.
|
||||
// Using the coefficients described within he schema, the required fee to
|
||||
// forward outgoing payments can be derived.
|
||||
//
|
||||
// TODO(roasbeef): should be in switch instead?
|
||||
type FeeSchema struct {
|
||||
// TODO(rosbeef): all these should be in msat instead
|
||||
|
||||
// BaseFee is the base amount that will be chained for ANY payment
|
||||
// forwarded.
|
||||
BaseFee btcutil.Amount
|
||||
// BaseFee is the base amount of milli-satoshis that will be chained
|
||||
// for ANY payment forwarded.
|
||||
BaseFee lnwire.MilliSatoshi
|
||||
|
||||
// FeeRate is the rate that will be charged for forwarding payments.
|
||||
// The fee rate has a granularity of 1/1000 th of a mili-satoshi, or a
|
||||
// millionth of a satoshi.
|
||||
FeeRate btcutil.Amount
|
||||
// This value should be interpreted as the numerator for a fraction
|
||||
// whose denominator is 1 million. As a result the effective fee rate
|
||||
// charged per mSAT will be: (amount * FeeRate/1,000,000)
|
||||
FeeRate uint32
|
||||
}
|
||||
|
||||
// Config defines the configuration for the ChannelRouter. ALL elements within
|
||||
@ -105,11 +102,6 @@ type Config struct {
|
||||
// we need in order to properly maintain the channel graph.
|
||||
ChainView chainview.FilteredChainView
|
||||
|
||||
// FeeSchema is the set fee schema that will be announced on to the
|
||||
// network.
|
||||
// TODO(roasbeef): should either be in discovery or switch
|
||||
FeeSchema *FeeSchema
|
||||
|
||||
// SendToSwitch is a function that directs a link-layer switch to
|
||||
// forward a fully encoded payment to the first hop in the route
|
||||
// denoted by its public key. A non-nil error is to be returned if the
|
||||
@ -123,12 +115,12 @@ type Config struct {
|
||||
// amount. We required the target amount as that will influence the available
|
||||
// set of paths for a payment.
|
||||
type routeTuple struct {
|
||||
amt btcutil.Amount
|
||||
amt lnwire.MilliSatoshi
|
||||
dest [33]byte
|
||||
}
|
||||
|
||||
// newRouteTuple creates a new route tuple from the target and amount.
|
||||
func newRouteTuple(amt btcutil.Amount, dest *btcec.PublicKey) routeTuple {
|
||||
func newRouteTuple(amt lnwire.MilliSatoshi, dest *btcec.PublicKey) routeTuple {
|
||||
r := routeTuple{
|
||||
amt: amt,
|
||||
}
|
||||
@ -388,6 +380,8 @@ func (r *ChannelRouter) syncGraphWithChain() error {
|
||||
func (r *ChannelRouter) networkHandler() {
|
||||
defer r.wg.Done()
|
||||
|
||||
// TODO(roasbeef): ticker to check if should prune in two weeks or not
|
||||
|
||||
for {
|
||||
select {
|
||||
// A new fully validated network update has just arrived. As a
|
||||
@ -812,9 +806,10 @@ type routingMsg struct {
|
||||
// required fee and time lock values running backwards along the route. The
|
||||
// route that will be ranked the highest is the one with the lowest cumulative
|
||||
// fee along the route.
|
||||
func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey, amt btcutil.Amount) ([]*Route, error) {
|
||||
dest := target.SerializeCompressed()
|
||||
func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
|
||||
amt lnwire.MilliSatoshi) ([]*Route, error) {
|
||||
|
||||
dest := target.SerializeCompressed()
|
||||
log.Debugf("Searching for path to %x, sending %v", dest, amt)
|
||||
|
||||
// We can short circuit the routing by opportunistically checking to
|
||||
@ -953,9 +948,8 @@ type LightningPayment struct {
|
||||
Target *btcec.PublicKey
|
||||
|
||||
// Amount is the value of the payment to send through the network in
|
||||
// satoshis.
|
||||
// TODO(roasbeef): this should be milli satoshis
|
||||
Amount btcutil.Amount
|
||||
// milli-satoshis.
|
||||
Amount lnwire.MilliSatoshi
|
||||
|
||||
// PaymentHash is the r-hash value to use within the HTLC extended to
|
||||
// the first hop.
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
"github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/roasbeef/btcd/btcec"
|
||||
"github.com/roasbeef/btcutil"
|
||||
)
|
||||
|
||||
type testCtx struct {
|
||||
@ -126,7 +125,7 @@ func TestFindRoutesFeeSorting(t *testing.T) {
|
||||
// selection.
|
||||
|
||||
// Execute a query for all possible routes between roasbeef and luo ji.
|
||||
const paymentAmt = btcutil.Amount(100)
|
||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||
target := ctx.aliases["luoji"]
|
||||
routes, err := ctx.router.FindRoutes(target, paymentAmt)
|
||||
if err != nil {
|
||||
@ -166,7 +165,7 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) {
|
||||
var payHash [32]byte
|
||||
payment := LightningPayment{
|
||||
Target: ctx.aliases["luoji"],
|
||||
Amount: btcutil.Amount(1000),
|
||||
Amount: lnwire.NewMSatFromSatoshis(1000),
|
||||
PaymentHash: payHash,
|
||||
}
|
||||
|
||||
@ -341,7 +340,8 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
// that the nodes are found after the fact.
|
||||
fundingTx, _, chanID, err := createChannelEdge(ctx,
|
||||
bitcoinKey1.SerializeCompressed(),
|
||||
bitcoinKey2.SerializeCompressed(), 10000, 500)
|
||||
bitcoinKey2.SerializeCompressed(),
|
||||
10000, 500)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create channel edge: %v", err)
|
||||
}
|
||||
@ -370,9 +370,9 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
ChannelID: edge.ChannelID,
|
||||
LastUpdate: time.Now(),
|
||||
TimeLockDelta: 10,
|
||||
MinHTLC: btcutil.Amount(1),
|
||||
FeeBaseMSat: btcutil.Amount(10),
|
||||
FeeProportionalMillionths: btcutil.Amount(10000),
|
||||
MinHTLC: 1,
|
||||
FeeBaseMSat: 10,
|
||||
FeeProportionalMillionths: 10000,
|
||||
}
|
||||
edgePolicy.Flags = 0
|
||||
|
||||
@ -386,9 +386,9 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
ChannelID: edge.ChannelID,
|
||||
LastUpdate: time.Now(),
|
||||
TimeLockDelta: 10,
|
||||
MinHTLC: btcutil.Amount(1),
|
||||
FeeBaseMSat: btcutil.Amount(10),
|
||||
FeeProportionalMillionths: btcutil.Amount(10000),
|
||||
MinHTLC: 1,
|
||||
FeeBaseMSat: 10,
|
||||
FeeProportionalMillionths: 10000,
|
||||
}
|
||||
edgePolicy.Flags = 1
|
||||
|
||||
@ -466,9 +466,9 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
ChannelID: edge.ChannelID,
|
||||
LastUpdate: time.Now(),
|
||||
TimeLockDelta: 10,
|
||||
MinHTLC: btcutil.Amount(1),
|
||||
FeeBaseMSat: btcutil.Amount(10),
|
||||
FeeProportionalMillionths: btcutil.Amount(10000),
|
||||
MinHTLC: 1,
|
||||
FeeBaseMSat: 10,
|
||||
FeeProportionalMillionths: 10000,
|
||||
}
|
||||
edgePolicy.Flags = 0
|
||||
|
||||
@ -481,9 +481,9 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
ChannelID: edge.ChannelID,
|
||||
LastUpdate: time.Now(),
|
||||
TimeLockDelta: 10,
|
||||
MinHTLC: btcutil.Amount(1),
|
||||
FeeBaseMSat: btcutil.Amount(10),
|
||||
FeeProportionalMillionths: btcutil.Amount(10000),
|
||||
MinHTLC: 1,
|
||||
FeeBaseMSat: 10,
|
||||
FeeProportionalMillionths: 10000,
|
||||
}
|
||||
edgePolicy.Flags = 1
|
||||
|
||||
@ -492,7 +492,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
}
|
||||
|
||||
// We should now be able to find one route to node 2.
|
||||
const paymentAmt = btcutil.Amount(100)
|
||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||
targetNode := priv2.PubKey()
|
||||
routes, err := ctx.router.FindRoutes(targetNode, paymentAmt)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user