mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
Merge pull request #533 from sputn1ck/lnd0.15.3fix
utils: fix SelectHopHints for lnd0.15.3
This commit is contained in:
commit
0d887ac173
3 changed files with 357 additions and 21 deletions
4
go.mod
4
go.mod
|
|
@ -1,7 +1,7 @@
|
|||
module github.com/lightninglabs/loop
|
||||
|
||||
require (
|
||||
github.com/btcsuite/btcd v0.23.1
|
||||
github.com/btcsuite/btcd v0.23.2
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.1
|
||||
github.com/btcsuite/btcd/btcutil v1.1.2
|
||||
github.com/btcsuite/btcd/btcutil/psbt v1.1.5
|
||||
|
|
@ -18,7 +18,7 @@ require (
|
|||
github.com/lightninglabs/lndclient v0.15.1-5
|
||||
github.com/lightninglabs/loop/swapserverrpc v1.0.1
|
||||
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display
|
||||
github.com/lightningnetwork/lnd v0.15.1-beta
|
||||
github.com/lightningnetwork/lnd v0.15.3-beta
|
||||
github.com/lightningnetwork/lnd/cert v1.1.1
|
||||
github.com/lightningnetwork/lnd/clock v1.1.0
|
||||
github.com/lightningnetwork/lnd/queue v1.1.0
|
||||
|
|
|
|||
16
go.sum
16
go.sum
|
|
@ -78,8 +78,9 @@ github.com/btcsuite/btcd v0.22.0-beta.0.20220204213055-eaf0459ff879/go.mod h1:os
|
|||
github.com/btcsuite/btcd v0.22.0-beta.0.20220207191057-4dc4ff7963b4/go.mod h1:7alexyj/lHlOtr2PJK7L/+HDJZpcGDn/pAU98r7DY08=
|
||||
github.com/btcsuite/btcd v0.22.0-beta.0.20220316175102-8d5c75c28923/go.mod h1:taIcYprAW2g6Z9S0gGUxyR+zDwimyDMK5ePOX+iJ2ds=
|
||||
github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
|
||||
github.com/btcsuite/btcd v0.23.1 h1:IB8cVQcC2X5mHbnfirLG5IZnkWYNTPlLZVrxUYSotbE=
|
||||
github.com/btcsuite/btcd v0.23.1/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
|
||||
github.com/btcsuite/btcd v0.23.2 h1:/YOgUp25sdCnP5ho6Hl3s0E438zlX+Kak7E6TgBgoT0=
|
||||
github.com/btcsuite/btcd v0.23.2/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.1/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||
|
|
@ -101,15 +102,19 @@ github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9
|
|||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcwallet v0.14.0/go.mod h1:KFR1x3ZH7c31i4qA34XIvcsnhrEBLK1SHli52lN8E54=
|
||||
github.com/btcsuite/btcwallet v0.15.1 h1:SKfh/l2Bgz9sJwHZvfiVbZ8Pl3N/8fFcWWXzsAPz9GU=
|
||||
github.com/btcsuite/btcwallet v0.15.1/go.mod h1:7OFsQ8ypiRwmr67hE0z98uXgJgXGAihE79jCib9x6ag=
|
||||
github.com/btcsuite/btcwallet v0.16.1 h1:nD8qXJeAU8c7a0Jlx5jwI2ufbf/9ouy29XGapRLTmos=
|
||||
github.com/btcsuite/btcwallet v0.16.1/go.mod h1:NCO8+5rIcbUm5CtVNSQM0xrtK4iYprlyuvpGzhkejaM=
|
||||
github.com/btcsuite/btcwallet/wallet/txauthor v1.2.1/go.mod h1:/74bubxX5Js48d76nf/TsNabpYp/gndUuJw4chzCmhU=
|
||||
github.com/btcsuite/btcwallet/wallet/txauthor v1.2.3 h1:M2yr5UlULvpqtxUqpMxTME/pA92Z9cpqeyvAFk9lAg0=
|
||||
github.com/btcsuite/btcwallet/wallet/txauthor v1.2.3/go.mod h1:T2xSiKGpUkSLCh68aF+FMXmKK9mFqNdHl9VaqOr+JjU=
|
||||
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 h1:etuLgGEojecsDOYTII8rYiGHjGyV5xTqsXi+ZQ715UU=
|
||||
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2/go.mod h1:Zpk/LOb2sKqwP2lmHjaZT9AdaKsHPSbNLm2Uql5IQ/0=
|
||||
github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 h1:BtEN5Empw62/RVnZ0VcJaVtVlBijnLlJY+dwjAye2Bg=
|
||||
github.com/btcsuite/btcwallet/wallet/txrules v1.2.0/go.mod h1:AtkqiL7ccKWxuLYtZm8Bu8G6q82w4yIZdgq6riy60z0=
|
||||
github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0 h1:wZnOolEAeNOHzHTnznw/wQv+j35ftCIokNrnOTOU5o8=
|
||||
github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
|
||||
github.com/btcsuite/btcwallet/wallet/txsizes v1.2.2/go.mod h1:q08Rms52VyWyXcp5zDc4tdFRKkFgNsMQrv3/LvE1448=
|
||||
github.com/btcsuite/btcwallet/wallet/txsizes v1.2.3 h1:PszOub7iXVYbtGybym5TGCp9Dv1h1iX4rIC3HICZGLg=
|
||||
github.com/btcsuite/btcwallet/wallet/txsizes v1.2.3/go.mod h1:q08Rms52VyWyXcp5zDc4tdFRKkFgNsMQrv3/LvE1448=
|
||||
github.com/btcsuite/btcwallet/walletdb v1.3.5/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
|
||||
github.com/btcsuite/btcwallet/walletdb v1.3.6-0.20210803004036-eebed51155ec/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
|
||||
github.com/btcsuite/btcwallet/walletdb v1.4.0 h1:/C5JRF+dTuE2CNMCO/or5N8epsrhmSM4710uBQoYPTQ=
|
||||
|
|
@ -523,8 +528,9 @@ github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display/go.mod h1:2oKOB
|
|||
github.com/lightningnetwork/lightning-onion v1.0.2-0.20220211021909-bb84a1ccb0c5 h1:TkKwqFcQTGYoI+VEqyxA8rxpCin8qDaYX0AfVRinT3k=
|
||||
github.com/lightningnetwork/lightning-onion v1.0.2-0.20220211021909-bb84a1ccb0c5/go.mod h1:7dDx73ApjEZA0kcknI799m2O5kkpfg4/gr7N092ojNo=
|
||||
github.com/lightningnetwork/lnd v0.14.1-beta.0.20220324135938-0dcaa511a249/go.mod h1:Tp3ZxsfioUl6kQ30RrbMqWoZyZ4K+fv/o1lMEU8U7rA=
|
||||
github.com/lightningnetwork/lnd v0.15.1-beta h1:XR6L/TM3IzWqziS8DgsXLlDsu2/4EMK4WzvZpyYhrdM=
|
||||
github.com/lightningnetwork/lnd v0.15.1-beta/go.mod h1:21UpSyTj8n94nsaJ0OFRXk4yOEkE7xA9JEX5QS4oMy4=
|
||||
github.com/lightningnetwork/lnd v0.15.3-beta h1:mm7fyXMgZPRyh0fFLO3tnvfvXszp/kVnGGciS76Wefs=
|
||||
github.com/lightningnetwork/lnd v0.15.3-beta/go.mod h1:UaCwJBMCJbwPMsUjfTIaKPKF8K79btRPnhqfiNPyKtA=
|
||||
github.com/lightningnetwork/lnd/cert v1.1.1 h1:Nsav0RlIDRbOnzz2Yu69SQlK939IKya3Q2S0mDviIN8=
|
||||
github.com/lightningnetwork/lnd/cert v1.1.1/go.mod h1:1P46svkkd73oSoeI4zjkVKgZNwGq8bkGuPR8z+5vQUs=
|
||||
github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg=
|
||||
|
|
|
|||
358
utils.go
358
utils.go
|
|
@ -1,6 +1,7 @@
|
|||
package loop
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
|
@ -12,7 +13,6 @@ import (
|
|||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightninglabs/lndclient"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/zpay32"
|
||||
|
|
@ -21,6 +21,11 @@ import (
|
|||
var (
|
||||
// DefaultMaxHopHints is set to 20 as that is the default set in LND.
|
||||
DefaultMaxHopHints = 20
|
||||
|
||||
// hopHintFactor is factor by which we scale the total amount of
|
||||
// inbound capacity we want our hop hints to represent, allowing us to
|
||||
// have some leeway if peers go offline.
|
||||
hopHintFactor = 2
|
||||
)
|
||||
|
||||
// isPublicNode checks if a node is public, by simply checking if there's any
|
||||
|
|
@ -106,30 +111,33 @@ func parseOutPoint(s string) (*wire.OutPoint, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// getAlias tries to get the ShortChannelId from the passed ChannelId and
|
||||
// aliasCache.
|
||||
func getAlias(aliasCache map[lnwire.ChannelID]lnwire.ShortChannelID,
|
||||
channelID lnwire.ChannelID) (lnwire.ShortChannelID, error) {
|
||||
|
||||
if channelID, ok := aliasCache[channelID]; ok {
|
||||
return channelID, nil
|
||||
}
|
||||
|
||||
return lnwire.ShortChannelID{}, fmt.Errorf("can't find channelId")
|
||||
}
|
||||
|
||||
// SelectHopHints calls into LND's exposed SelectHopHints prefiltered to the
|
||||
// includeNodes map (unless it's empty).
|
||||
func SelectHopHints(ctx context.Context, lnd *lndclient.LndServices,
|
||||
amt btcutil.Amount, numMaxHophints int,
|
||||
includeNodes map[route.Vertex]struct{}) ([][]zpay32.HopHint, error) {
|
||||
|
||||
cfg := &invoicesrpc.SelectHopHintsCfg{
|
||||
IsPublicNode: func(pubKey [33]byte) (bool, error) {
|
||||
return isPublicNode(ctx, lnd, pubKey)
|
||||
},
|
||||
FetchChannelEdgesByID: func(chanID uint64) (
|
||||
*channeldb.ChannelEdgeInfo, *channeldb.ChannelEdgePolicy,
|
||||
*channeldb.ChannelEdgePolicy, error) {
|
||||
aliasCache := make(map[lnwire.ChannelID]lnwire.ShortChannelID)
|
||||
|
||||
return fetchChannelEdgesByID(ctx, lnd, chanID)
|
||||
},
|
||||
}
|
||||
// Fetch all active and public channels.
|
||||
channels, err := lnd.Client.ListChannels(ctx, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
openChannels := []*invoicesrpc.HopHintInfo{}
|
||||
openChannels := []*HopHintInfo{}
|
||||
for _, channel := range channels {
|
||||
if len(includeNodes) > 0 {
|
||||
if _, ok := includeNodes[channel.PubKeyBytes]; !ok {
|
||||
|
|
@ -148,7 +156,7 @@ func SelectHopHints(ctx context.Context, lnd *lndclient.LndServices,
|
|||
}
|
||||
|
||||
openChannels = append(
|
||||
openChannels, &invoicesrpc.HopHintInfo{
|
||||
openChannels, &HopHintInfo{
|
||||
IsPublic: !channel.Private,
|
||||
IsActive: channel.Active,
|
||||
FundingOutpoint: *outPoint,
|
||||
|
|
@ -159,11 +167,333 @@ func SelectHopHints(ctx context.Context, lnd *lndclient.LndServices,
|
|||
ShortChannelID: channel.ChannelID,
|
||||
},
|
||||
)
|
||||
|
||||
channelID := lnwire.NewChanIDFromOutPoint(outPoint)
|
||||
scID := lnwire.NewShortChanIDFromInt(channel.ChannelID)
|
||||
aliasCache[channelID] = scID
|
||||
}
|
||||
|
||||
routeHints := invoicesrpc.SelectHopHints(
|
||||
cfg := &SelectHopHintsCfg{
|
||||
IsPublicNode: func(pubKey [33]byte) (bool, error) {
|
||||
return isPublicNode(ctx, lnd, pubKey)
|
||||
},
|
||||
FetchChannelEdgesByID: func(chanID uint64) (
|
||||
*channeldb.ChannelEdgeInfo, *channeldb.ChannelEdgePolicy,
|
||||
*channeldb.ChannelEdgePolicy, error) {
|
||||
|
||||
return fetchChannelEdgesByID(ctx, lnd, chanID)
|
||||
},
|
||||
GetAlias: func(id lnwire.ChannelID) (
|
||||
lnwire.ShortChannelID, error) {
|
||||
|
||||
return getAlias(aliasCache, id)
|
||||
},
|
||||
}
|
||||
|
||||
routeHints := invoicesrpcSelectHopHints(
|
||||
lnwire.MilliSatoshi(amt*1000), cfg, openChannels, numMaxHophints,
|
||||
)
|
||||
|
||||
return routeHints, nil
|
||||
}
|
||||
|
||||
// chanCanBeHopHint returns true if the target channel is eligible to be a hop
|
||||
// hint.
|
||||
func chanCanBeHopHint(channel *HopHintInfo, cfg *SelectHopHintsCfg) (
|
||||
*channeldb.ChannelEdgePolicy, bool) {
|
||||
|
||||
// Since we're only interested in our private channels, we'll skip
|
||||
// public ones.
|
||||
if channel.IsPublic {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Make sure the channel is active.
|
||||
if !channel.IsActive {
|
||||
log.Debugf("Skipping channel %v due to not "+
|
||||
"being eligible to forward payments",
|
||||
channel.ShortChannelID)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// To ensure we don't leak unadvertised nodes, we'll make sure our
|
||||
// counterparty is publicly advertised within the network. Otherwise,
|
||||
// we'll end up leaking information about nodes that intend to stay
|
||||
// unadvertised, like in the case of a node only having private
|
||||
// channels.
|
||||
var remotePub [33]byte
|
||||
copy(remotePub[:], channel.RemotePubkey.SerializeCompressed())
|
||||
isRemoteNodePublic, err := cfg.IsPublicNode(remotePub)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to determine if node %x "+
|
||||
"is advertised: %v", remotePub, err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if !isRemoteNodePublic {
|
||||
log.Debugf("Skipping channel %v due to "+
|
||||
"counterparty %x being unadvertised",
|
||||
channel.ShortChannelID, remotePub)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Fetch the policies for each end of the channel.
|
||||
info, p1, p2, err := cfg.FetchChannelEdgesByID(channel.ShortChannelID)
|
||||
if err != nil {
|
||||
// In the case of zero-conf channels, it may be the case that
|
||||
// the alias SCID was deleted from the graph, and replaced by
|
||||
// the confirmed SCID. Check the Graph for the confirmed SCID.
|
||||
confirmedScid := channel.ConfirmedScidZC
|
||||
info, p1, p2, err = cfg.FetchChannelEdgesByID(confirmedScid)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to fetch the routing policies for "+
|
||||
"the edges of the channel %v: %v",
|
||||
channel.ShortChannelID, err)
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Now, we'll need to determine which is the correct policy for HTLCs
|
||||
// being sent from the remote node.
|
||||
var remotePolicy *channeldb.ChannelEdgePolicy
|
||||
if bytes.Equal(remotePub[:], info.NodeKey1Bytes[:]) {
|
||||
remotePolicy = p1
|
||||
} else {
|
||||
remotePolicy = p2
|
||||
}
|
||||
|
||||
return remotePolicy, true
|
||||
}
|
||||
|
||||
// addHopHint creates a hop hint out of the passed channel and channel policy.
|
||||
// The new hop hint is appended to the passed slice.
|
||||
func addHopHint(hopHints *[][]zpay32.HopHint,
|
||||
channel *HopHintInfo, chanPolicy *channeldb.ChannelEdgePolicy,
|
||||
aliasScid lnwire.ShortChannelID) {
|
||||
|
||||
hopHint := zpay32.HopHint{
|
||||
NodeID: channel.RemotePubkey,
|
||||
ChannelID: channel.ShortChannelID,
|
||||
FeeBaseMSat: uint32(chanPolicy.FeeBaseMSat),
|
||||
FeeProportionalMillionths: uint32(
|
||||
chanPolicy.FeeProportionalMillionths,
|
||||
),
|
||||
CLTVExpiryDelta: chanPolicy.TimeLockDelta,
|
||||
}
|
||||
|
||||
var defaultScid lnwire.ShortChannelID
|
||||
if aliasScid != defaultScid {
|
||||
hopHint.ChannelID = aliasScid.ToUint64()
|
||||
}
|
||||
|
||||
*hopHints = append(*hopHints, []zpay32.HopHint{hopHint})
|
||||
}
|
||||
|
||||
// HopHintInfo contains the channel information required to create a hop hint.
|
||||
type HopHintInfo struct {
|
||||
// IsPublic indicates whether a channel is advertised to the network.
|
||||
IsPublic bool
|
||||
|
||||
// IsActive indicates whether the channel is online and available for
|
||||
// use.
|
||||
IsActive bool
|
||||
|
||||
// FundingOutpoint is the funding txid:index for the channel.
|
||||
FundingOutpoint wire.OutPoint
|
||||
|
||||
// RemotePubkey is the public key of the remote party that this channel
|
||||
// is in.
|
||||
RemotePubkey *btcec.PublicKey
|
||||
|
||||
// RemoteBalance is the remote party's balance (our current incoming
|
||||
// capacity).
|
||||
RemoteBalance lnwire.MilliSatoshi
|
||||
|
||||
// ShortChannelID is the short channel ID of the channel.
|
||||
ShortChannelID uint64
|
||||
|
||||
// ConfirmedScidZC is the confirmed SCID of a zero-conf channel. This
|
||||
// may be used for looking up a channel in the graph.
|
||||
ConfirmedScidZC uint64
|
||||
|
||||
// ScidAliasFeature denotes whether the channel has negotiated the
|
||||
// option-scid-alias feature bit.
|
||||
ScidAliasFeature bool
|
||||
}
|
||||
|
||||
// SelectHopHintsCfg contains the dependencies required to obtain hop hints
|
||||
// for an invoice.
|
||||
type SelectHopHintsCfg struct {
|
||||
// IsPublicNode is returns a bool indicating whether the node with the
|
||||
// given public key is seen as a public node in the graph from the
|
||||
// graph's source node's point of view.
|
||||
IsPublicNode func(pubKey [33]byte) (bool, error)
|
||||
|
||||
// FetchChannelEdgesByID attempts to lookup the two directed edges for
|
||||
// the channel identified by the channel ID.
|
||||
FetchChannelEdgesByID func(chanID uint64) (*channeldb.ChannelEdgeInfo,
|
||||
*channeldb.ChannelEdgePolicy, *channeldb.ChannelEdgePolicy,
|
||||
error)
|
||||
|
||||
// GetAlias allows the peer's alias SCID to be retrieved for private
|
||||
// option_scid_alias channels.
|
||||
GetAlias func(lnwire.ChannelID) (lnwire.ShortChannelID, error)
|
||||
}
|
||||
|
||||
// sufficientHints checks whether we have sufficient hop hints, based on the
|
||||
// following criteria:
|
||||
// - Hop hint count: limit to a set number of hop hints, regardless of whether
|
||||
// we've reached our invoice amount or not.
|
||||
// - Total incoming capacity: limit to our invoice amount * scaling factor to
|
||||
// allow for some of our links going offline.
|
||||
//
|
||||
// We limit our number of hop hints like this to keep our invoice size down,
|
||||
// and to avoid leaking all our private channels when we don't need to.
|
||||
func sufficientHints(numHints, maxHints, scalingFactor int, amount,
|
||||
totalHintAmount lnwire.MilliSatoshi) bool {
|
||||
|
||||
if numHints >= maxHints {
|
||||
log.Debug("Reached maximum number of hop hints")
|
||||
return true
|
||||
}
|
||||
|
||||
requiredAmount := amount * lnwire.MilliSatoshi(scalingFactor)
|
||||
if totalHintAmount >= requiredAmount {
|
||||
log.Debugf("Total hint amount: %v has reached target hint "+
|
||||
"bandwidth: %v (invoice amount: %v * factor: %v)",
|
||||
totalHintAmount, requiredAmount, amount,
|
||||
scalingFactor)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SelectHopHints will select up to numMaxHophints from the set of passed open
|
||||
// channels. The set of hop hints will be returned as a slice of functional
|
||||
// options that'll append the route hint to the set of all route hints.
|
||||
//
|
||||
// TODO(sputn1ck): remove when https://github.com/lightningnetwork/lnd/pull/7065
|
||||
// is merged to a new lnd release.
|
||||
func invoicesrpcSelectHopHints(amtMSat lnwire.MilliSatoshi, cfg *SelectHopHintsCfg,
|
||||
openChannels []*HopHintInfo,
|
||||
numMaxHophints int) [][]zpay32.HopHint {
|
||||
|
||||
// We'll add our hop hints in two passes, first we'll add all channels
|
||||
// that are eligible to be hop hints, and also have a local balance
|
||||
// above the payment amount.
|
||||
var totalHintBandwidth lnwire.MilliSatoshi
|
||||
hopHintChans := make(map[wire.OutPoint]struct{})
|
||||
hopHints := make([][]zpay32.HopHint, 0, numMaxHophints)
|
||||
for _, channel := range openChannels {
|
||||
enoughHopHints := sufficientHints(
|
||||
len(hopHints), numMaxHophints, hopHintFactor, amtMSat,
|
||||
totalHintBandwidth,
|
||||
)
|
||||
if enoughHopHints {
|
||||
log.Debugf("First pass of hop selection has " +
|
||||
"sufficient hints")
|
||||
|
||||
return hopHints
|
||||
}
|
||||
|
||||
// If this channel can't be a hop hint, then skip it.
|
||||
edgePolicy, canBeHopHint := chanCanBeHopHint(channel, cfg)
|
||||
if edgePolicy == nil || !canBeHopHint {
|
||||
continue
|
||||
}
|
||||
|
||||
// Similarly, in this first pass, we'll ignore all channels in
|
||||
// isolation can't satisfy this payment.
|
||||
if channel.RemoteBalance < amtMSat {
|
||||
continue
|
||||
}
|
||||
|
||||
// Lookup and see if there is an alias SCID that exists.
|
||||
chanID := lnwire.NewChanIDFromOutPoint(
|
||||
&channel.FundingOutpoint,
|
||||
)
|
||||
alias, _ := cfg.GetAlias(chanID)
|
||||
|
||||
// If this is a channel where the option-scid-alias feature bit
|
||||
// was negotiated and the alias is not yet assigned, we cannot
|
||||
// issue an invoice. Doing so might expose the confirmed SCID
|
||||
// of a private channel.
|
||||
if channel.ScidAliasFeature {
|
||||
var defaultScid lnwire.ShortChannelID
|
||||
if alias == defaultScid {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we now this channel use usable, add it as a hop
|
||||
// hint and the indexes we'll use later.
|
||||
addHopHint(&hopHints, channel, edgePolicy, alias)
|
||||
|
||||
hopHintChans[channel.FundingOutpoint] = struct{}{}
|
||||
totalHintBandwidth += channel.RemoteBalance
|
||||
}
|
||||
|
||||
// In this second pass we'll add channels, and we'll either stop when
|
||||
// we have 20 hop hints, we've run through all the available channels,
|
||||
// or if the sum of available bandwidth in the routing hints exceeds 2x
|
||||
// the payment amount. We do 2x here to account for a margin of error
|
||||
// if some of the selected channels no longer become operable.
|
||||
for i := 0; i < len(openChannels); i++ {
|
||||
enoughHopHints := sufficientHints(
|
||||
len(hopHints), numMaxHophints, hopHintFactor, amtMSat,
|
||||
totalHintBandwidth,
|
||||
)
|
||||
if enoughHopHints {
|
||||
log.Debugf("Second pass of hop selection has " +
|
||||
"sufficient hints")
|
||||
|
||||
return hopHints
|
||||
}
|
||||
|
||||
channel := openChannels[i]
|
||||
|
||||
// Skip the channel if we already selected it.
|
||||
if _, ok := hopHintChans[channel.FundingOutpoint]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the channel can't be a hop hint, then we'll skip it.
|
||||
// Otherwise, we'll use the policy information to populate the
|
||||
// hop hint.
|
||||
remotePolicy, canBeHopHint := chanCanBeHopHint(channel, cfg)
|
||||
if !canBeHopHint || remotePolicy == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Lookup and see if there's an alias SCID that exists.
|
||||
chanID := lnwire.NewChanIDFromOutPoint(
|
||||
&channel.FundingOutpoint,
|
||||
)
|
||||
alias, _ := cfg.GetAlias(chanID)
|
||||
|
||||
// If this is a channel where the option-scid-alias feature bit
|
||||
// was negotiated and the alias is not yet assigned, we cannot
|
||||
// issue an invoice. Doing so might expose the confirmed SCID
|
||||
// of a private channel.
|
||||
if channel.ScidAliasFeature {
|
||||
var defaultScid lnwire.ShortChannelID
|
||||
if alias == defaultScid {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Include the route hint in our set of options that will be
|
||||
// used when creating the invoice.
|
||||
addHopHint(&hopHints, channel, remotePolicy, alias)
|
||||
|
||||
// As we've just added a new hop hint, we'll accumulate it's
|
||||
// available balance now to update our tally.
|
||||
//
|
||||
// TODO(roasbeef): have a cut off based on min bandwidth?
|
||||
totalHintBandwidth += channel.RemoteBalance
|
||||
}
|
||||
|
||||
return hopHints
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue