mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
refactor: move various duties from ChannelRouter to graph.Builder
This commit is a large refactor that moves over various responsibilities from the ChannelRouter to the graph.Builder. These include all graph related tasks such as: - graph pruning - validation of new network updates & persisting new updates - notifying topology update clients of any changes. This is a large commit but: - many of the files are purely moved from `routing` to `graph` - the business logic put in the graph Builder is copied exactly as is from the ChannelRouter with one exception: - The ChannelRouter just needs to be able to call the Builder's `ApplyChannelUpdate` method. So this is now exported and provided to the ChannelRouter as a config option. - The trickiest part was just moving over the test code since quite a bit had to be duplicated.
This commit is contained in:
parent
0b7364f54b
commit
7f1be39d45
@ -6,9 +6,9 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/lightningnetwork/lnd/graph"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ManagerCfg houses a set of values and methods that is passed to the Manager
|
// ManagerCfg houses a set of values and methods that is passed to the Manager
|
||||||
@ -36,7 +36,7 @@ type ManagerCfg struct {
|
|||||||
|
|
||||||
// SubscribeTopology is used to get a subscription for topology changes
|
// SubscribeTopology is used to get a subscription for topology changes
|
||||||
// on the network.
|
// on the network.
|
||||||
SubscribeTopology func() (*routing.TopologyClient, error)
|
SubscribeTopology func() (*graph.TopologyClient, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manager is struct that manages an autopilot agent, making it possible to
|
// Manager is struct that manages an autopilot agent, making it possible to
|
||||||
|
@ -5,9 +5,9 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/graph"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash,
|
|||||||
if edge1 != nil {
|
if edge1 != nil {
|
||||||
// We don't want to send channel updates that don't
|
// We don't want to send channel updates that don't
|
||||||
// conform to the spec (anymore).
|
// conform to the spec (anymore).
|
||||||
err := routing.ValidateChannelUpdateFields(0, edge1)
|
err := graph.ValidateChannelUpdateFields(0, edge1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("not sending invalid channel "+
|
log.Errorf("not sending invalid channel "+
|
||||||
"update %v: %v", edge1, err)
|
"update %v: %v", edge1, err)
|
||||||
@ -145,7 +145,7 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if edge2 != nil {
|
if edge2 != nil {
|
||||||
err := routing.ValidateChannelUpdateFields(0, edge2)
|
err := graph.ValidateChannelUpdateFields(0, edge2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("not sending invalid channel "+
|
log.Errorf("not sending invalid channel "+
|
||||||
"update %v: %v", edge2, err)
|
"update %v: %v", edge2, err)
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/multimutex"
|
"github.com/lightningnetwork/lnd/multimutex"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
@ -1361,7 +1360,7 @@ func (d *AuthenticatedGossiper) networkHandler() {
|
|||||||
|
|
||||||
// We'll use this validation to ensure that we process jobs in their
|
// We'll use this validation to ensure that we process jobs in their
|
||||||
// dependency order during parallel validation.
|
// dependency order during parallel validation.
|
||||||
validationBarrier := routing.NewValidationBarrier(1000, d.quit)
|
validationBarrier := graph.NewValidationBarrier(1000, d.quit)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -1486,7 +1485,7 @@ func (d *AuthenticatedGossiper) networkHandler() {
|
|||||||
//
|
//
|
||||||
// NOTE: must be run as a goroutine.
|
// NOTE: must be run as a goroutine.
|
||||||
func (d *AuthenticatedGossiper) handleNetworkMessages(nMsg *networkMsg,
|
func (d *AuthenticatedGossiper) handleNetworkMessages(nMsg *networkMsg,
|
||||||
deDuped *deDupedAnnouncements, vb *routing.ValidationBarrier) {
|
deDuped *deDupedAnnouncements, vb *graph.ValidationBarrier) {
|
||||||
|
|
||||||
defer d.wg.Done()
|
defer d.wg.Done()
|
||||||
defer vb.CompleteJob()
|
defer vb.CompleteJob()
|
||||||
@ -1502,10 +1501,10 @@ func (d *AuthenticatedGossiper) handleNetworkMessages(nMsg *networkMsg,
|
|||||||
log.Debugf("Validating network message %s got err: %v",
|
log.Debugf("Validating network message %s got err: %v",
|
||||||
nMsg.msg.MsgType(), err)
|
nMsg.msg.MsgType(), err)
|
||||||
|
|
||||||
if !routing.IsError(
|
if !graph.IsError(
|
||||||
err,
|
err,
|
||||||
routing.ErrVBarrierShuttingDown,
|
graph.ErrVBarrierShuttingDown,
|
||||||
routing.ErrParentValidationFailed,
|
graph.ErrParentValidationFailed,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
log.Warnf("unexpected error during validation "+
|
log.Warnf("unexpected error during validation "+
|
||||||
@ -1861,7 +1860,7 @@ func (d *AuthenticatedGossiper) processRejectedEdge(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = routing.ValidateChannelAnn(chanAnn)
|
err = graph.ValidateChannelAnn(chanAnn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("assembled channel announcement proof "+
|
err := fmt.Errorf("assembled channel announcement proof "+
|
||||||
"for shortChanID=%v isn't valid: %v",
|
"for shortChanID=%v isn't valid: %v",
|
||||||
@ -1910,7 +1909,7 @@ func (d *AuthenticatedGossiper) processRejectedEdge(
|
|||||||
func (d *AuthenticatedGossiper) addNode(msg *lnwire.NodeAnnouncement,
|
func (d *AuthenticatedGossiper) addNode(msg *lnwire.NodeAnnouncement,
|
||||||
op ...batch.SchedulerOption) error {
|
op ...batch.SchedulerOption) error {
|
||||||
|
|
||||||
if err := routing.ValidateNodeAnn(msg); err != nil {
|
if err := graph.ValidateNodeAnn(msg); err != nil {
|
||||||
return fmt.Errorf("unable to validate node announcement: %w",
|
return fmt.Errorf("unable to validate node announcement: %w",
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
@ -2064,7 +2063,7 @@ func (d *AuthenticatedGossiper) processZombieUpdate(
|
|||||||
"with chan_id=%v", msg.ShortChannelID)
|
"with chan_id=%v", msg.ShortChannelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := routing.VerifyChannelUpdateSignature(msg, pubKey)
|
err := graph.VerifyChannelUpdateSignature(msg, pubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to verify channel "+
|
return fmt.Errorf("unable to verify channel "+
|
||||||
"update signature: %v", err)
|
"update signature: %v", err)
|
||||||
@ -2201,7 +2200,7 @@ func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo,
|
|||||||
|
|
||||||
// To ensure that our signature is valid, we'll verify it ourself
|
// To ensure that our signature is valid, we'll verify it ourself
|
||||||
// before committing it to the slice returned.
|
// before committing it to the slice returned.
|
||||||
err = routing.ValidateChannelUpdateAnn(d.selfKey, info.Capacity, chanUpdate)
|
err = graph.ValidateChannelUpdateAnn(d.selfKey, info.Capacity, chanUpdate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("generated invalid channel "+
|
return nil, nil, fmt.Errorf("generated invalid channel "+
|
||||||
"update sig: %v", err)
|
"update sig: %v", err)
|
||||||
@ -2338,11 +2337,11 @@ func (d *AuthenticatedGossiper) handleNodeAnnouncement(nMsg *networkMsg,
|
|||||||
log.Debugf("Adding node: %x got error: %v", nodeAnn.NodeID,
|
log.Debugf("Adding node: %x got error: %v", nodeAnn.NodeID,
|
||||||
err)
|
err)
|
||||||
|
|
||||||
if !routing.IsError(
|
if !graph.IsError(
|
||||||
err,
|
err,
|
||||||
routing.ErrOutdated,
|
graph.ErrOutdated,
|
||||||
routing.ErrIgnored,
|
graph.ErrIgnored,
|
||||||
routing.ErrVBarrierShuttingDown,
|
graph.ErrVBarrierShuttingDown,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@ -2457,7 +2456,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
|
|||||||
// the signatures within the proof as it should be well formed.
|
// the signatures within the proof as it should be well formed.
|
||||||
var proof *models.ChannelAuthProof
|
var proof *models.ChannelAuthProof
|
||||||
if nMsg.isRemote {
|
if nMsg.isRemote {
|
||||||
if err := routing.ValidateChannelAnn(ann); err != nil {
|
if err := graph.ValidateChannelAnn(ann); err != nil {
|
||||||
err := fmt.Errorf("unable to validate announcement: "+
|
err := fmt.Errorf("unable to validate announcement: "+
|
||||||
"%v", err)
|
"%v", err)
|
||||||
|
|
||||||
@ -2538,7 +2537,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
|
|||||||
// If the edge was rejected due to already being known, then it
|
// If the edge was rejected due to already being known, then it
|
||||||
// may be the case that this new message has a fresh channel
|
// may be the case that this new message has a fresh channel
|
||||||
// proof, so we'll check.
|
// proof, so we'll check.
|
||||||
if routing.IsError(err, routing.ErrIgnored) {
|
if graph.IsError(err, graph.ErrIgnored) {
|
||||||
// Attempt to process the rejected message to see if we
|
// Attempt to process the rejected message to see if we
|
||||||
// get any new announcements.
|
// get any new announcements.
|
||||||
anns, rErr := d.processRejectedEdge(ann, proof)
|
anns, rErr := d.processRejectedEdge(ann, proof)
|
||||||
@ -2862,7 +2861,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg,
|
|||||||
// Validate the channel announcement with the expected public key and
|
// Validate the channel announcement with the expected public key and
|
||||||
// channel capacity. In the case of an invalid channel update, we'll
|
// channel capacity. In the case of an invalid channel update, we'll
|
||||||
// return an error to the caller and exit early.
|
// return an error to the caller and exit early.
|
||||||
err = routing.ValidateChannelUpdateAnn(pubKey, chanInfo.Capacity, upd)
|
err = graph.ValidateChannelUpdateAnn(pubKey, chanInfo.Capacity, upd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rErr := fmt.Errorf("unable to validate channel update "+
|
rErr := fmt.Errorf("unable to validate channel update "+
|
||||||
"announcement for short_chan_id=%v: %v",
|
"announcement for short_chan_id=%v: %v",
|
||||||
@ -2947,10 +2946,10 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := d.cfg.Router.UpdateEdge(update, ops...); err != nil {
|
if err := d.cfg.Router.UpdateEdge(update, ops...); err != nil {
|
||||||
if routing.IsError(
|
if graph.IsError(
|
||||||
err, routing.ErrOutdated,
|
err, graph.ErrOutdated,
|
||||||
routing.ErrIgnored,
|
graph.ErrIgnored,
|
||||||
routing.ErrVBarrierShuttingDown,
|
graph.ErrVBarrierShuttingDown,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
log.Debugf("Update edge for short_chan_id(%v) got: %v",
|
log.Debugf("Update edge for short_chan_id(%v) got: %v",
|
||||||
@ -3268,7 +3267,7 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg,
|
|||||||
|
|
||||||
// With all the necessary components assembled validate the full
|
// With all the necessary components assembled validate the full
|
||||||
// channel announcement proof.
|
// channel announcement proof.
|
||||||
if err := routing.ValidateChannelAnn(chanAnn); err != nil {
|
if err := graph.ValidateChannelAnn(chanAnn); err != nil {
|
||||||
err := fmt.Errorf("channel announcement proof for "+
|
err := fmt.Errorf("channel announcement proof for "+
|
||||||
"short_chan_id=%v isn't valid: %v", shortChanID, err)
|
"short_chan_id=%v isn't valid: %v", shortChanID, err)
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -351,7 +350,7 @@ func (r *mockGraphSource) IsStaleEdgePolicy(chanID lnwire.ShortChannelID,
|
|||||||
// Since it exists within our zombie index, we'll check that it
|
// Since it exists within our zombie index, we'll check that it
|
||||||
// respects the router's live edge horizon to determine whether
|
// respects the router's live edge horizon to determine whether
|
||||||
// it is stale or not.
|
// it is stale or not.
|
||||||
return time.Since(timestamp) > routing.DefaultChannelPruneExpiry
|
return time.Since(timestamp) > graph.DefaultChannelPruneExpiry
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@ -2258,7 +2257,7 @@ func TestProcessZombieEdgeNowLive(t *testing.T) {
|
|||||||
|
|
||||||
// We'll generate a channel update with a timestamp far enough in the
|
// We'll generate a channel update with a timestamp far enough in the
|
||||||
// past to consider it a zombie.
|
// past to consider it a zombie.
|
||||||
zombieTimestamp := time.Now().Add(-routing.DefaultChannelPruneExpiry)
|
zombieTimestamp := time.Now().Add(-graph.DefaultChannelPruneExpiry)
|
||||||
batch.chanUpdAnn2.Timestamp = uint32(zombieTimestamp.Unix())
|
batch.chanUpdAnn2.Timestamp = uint32(zombieTimestamp.Unix())
|
||||||
if err := signUpdate(remoteKeyPriv2, batch.chanUpdAnn2); err != nil {
|
if err := signUpdate(remoteKeyPriv2, batch.chanUpdAnn2); err != nil {
|
||||||
t.Fatalf("unable to sign update with new timestamp: %v", err)
|
t.Fatalf("unable to sign update with new timestamp: %v", err)
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||||
"github.com/lightningnetwork/lnd/discovery"
|
"github.com/lightningnetwork/lnd/discovery"
|
||||||
|
"github.com/lightningnetwork/lnd/graph"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/labels"
|
"github.com/lightningnetwork/lnd/labels"
|
||||||
@ -33,7 +34,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
|
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
|
||||||
"golang.org/x/crypto/salsa20"
|
"golang.org/x/crypto/salsa20"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -3415,10 +3415,10 @@ func (f *Manager) addToRouterGraph(completeChan *channeldb.OpenChannel,
|
|||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if routing.IsError(err, routing.ErrOutdated,
|
if graph.IsError(err, graph.ErrOutdated,
|
||||||
routing.ErrIgnored) {
|
graph.ErrIgnored) {
|
||||||
|
|
||||||
log.Debugf("Router rejected "+
|
log.Debugf("Graph rejected "+
|
||||||
"ChannelAnnouncement: %v", err)
|
"ChannelAnnouncement: %v", err)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("error sending channel "+
|
return fmt.Errorf("error sending channel "+
|
||||||
@ -3435,10 +3435,10 @@ func (f *Manager) addToRouterGraph(completeChan *channeldb.OpenChannel,
|
|||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if routing.IsError(err, routing.ErrOutdated,
|
if graph.IsError(err, graph.ErrOutdated,
|
||||||
routing.ErrIgnored) {
|
graph.ErrIgnored) {
|
||||||
|
|
||||||
log.Debugf("Router rejected "+
|
log.Debugf("Graph rejected "+
|
||||||
"ChannelUpdate: %v", err)
|
"ChannelUpdate: %v", err)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("error sending channel "+
|
return fmt.Errorf("error sending channel "+
|
||||||
@ -4354,10 +4354,10 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
|
|||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if routing.IsError(err, routing.ErrOutdated,
|
if graph.IsError(err, graph.ErrOutdated,
|
||||||
routing.ErrIgnored) {
|
graph.ErrIgnored) {
|
||||||
|
|
||||||
log.Debugf("Router rejected "+
|
log.Debugf("Graph rejected "+
|
||||||
"AnnounceSignatures: %v", err)
|
"AnnounceSignatures: %v", err)
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("Unable to send channel "+
|
log.Errorf("Unable to send channel "+
|
||||||
@ -4384,10 +4384,10 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
|
|||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if routing.IsError(err, routing.ErrOutdated,
|
if graph.IsError(err, graph.ErrOutdated,
|
||||||
routing.ErrIgnored) {
|
graph.ErrIgnored) {
|
||||||
|
|
||||||
log.Debugf("Router rejected "+
|
log.Debugf("Graph rejected "+
|
||||||
"NodeAnnouncement: %v", err)
|
"NodeAnnouncement: %v", err)
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("Unable to send node "+
|
log.Errorf("Unable to send node "+
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package routing
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
1753
graph/builder.go
1753
graph/builder.go
File diff suppressed because it is too large
Load Diff
2051
graph/builder_test.go
Normal file
2051
graph/builder_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
package routing
|
package graph
|
||||||
|
|
||||||
import "github.com/go-errors/errors"
|
import "github.com/go-errors/errors"
|
||||||
|
|
||||||
@ -39,27 +39,27 @@ const (
|
|||||||
ErrParentValidationFailed
|
ErrParentValidationFailed
|
||||||
)
|
)
|
||||||
|
|
||||||
// routerError is a structure that represent the error inside the routing package,
|
// graphError is a structure that represent the error inside the graph package,
|
||||||
// this structure carries additional information about error code in order to
|
// this structure carries additional information about error code in order to
|
||||||
// be able distinguish errors outside of the current package.
|
// be able distinguish errors outside of the current package.
|
||||||
type routerError struct {
|
type graphError struct {
|
||||||
err *errors.Error
|
err *errors.Error
|
||||||
code errorCode
|
code errorCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error represents errors as the string
|
// Error represents errors as the string
|
||||||
// NOTE: Part of the error interface.
|
// NOTE: Part of the error interface.
|
||||||
func (e *routerError) Error() string {
|
func (e *graphError) Error() string {
|
||||||
return e.err.Error()
|
return e.err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// A compile time check to ensure routerError implements the error interface.
|
// A compile time check to ensure graphError implements the error interface.
|
||||||
var _ error = (*routerError)(nil)
|
var _ error = (*graphError)(nil)
|
||||||
|
|
||||||
// newErrf creates a routerError by the given error formatted description and
|
// newErrf creates a graphError by the given error formatted description and
|
||||||
// its corresponding error code.
|
// its corresponding error code.
|
||||||
func newErrf(code errorCode, format string, a ...interface{}) *routerError {
|
func newErrf(code errorCode, format string, a ...interface{}) *graphError {
|
||||||
return &routerError{
|
return &graphError{
|
||||||
code: code,
|
code: code,
|
||||||
err: errors.Errorf(format, a...),
|
err: errors.Errorf(format, a...),
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ func newErrf(code errorCode, format string, a ...interface{}) *routerError {
|
|||||||
// IsError is a helper function which is needed to have ability to check that
|
// IsError is a helper function which is needed to have ability to check that
|
||||||
// returned error has specific error code.
|
// returned error has specific error code.
|
||||||
func IsError(e interface{}, codes ...errorCode) bool {
|
func IsError(e interface{}, codes ...errorCode) bool {
|
||||||
err, ok := e.(*routerError)
|
err, ok := e.(*graphError)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package routing
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||||
"github.com/lightningnetwork/lnd/graph"
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,16 +56,16 @@ type topologyClientUpdate struct {
|
|||||||
// topology occurs. Changes that will be sent at notifications include: new
|
// topology occurs. Changes that will be sent at notifications include: new
|
||||||
// nodes appearing, node updating their attributes, new channels, channels
|
// nodes appearing, node updating their attributes, new channels, channels
|
||||||
// closing, and updates in the routing policies of a channel's directed edges.
|
// closing, and updates in the routing policies of a channel's directed edges.
|
||||||
func (r *ChannelRouter) SubscribeTopology() (*TopologyClient, error) {
|
func (b *Builder) SubscribeTopology() (*TopologyClient, error) {
|
||||||
// If the router is not yet started, return an error to avoid a
|
// If the router is not yet started, return an error to avoid a
|
||||||
// deadlock waiting for it to handle the subscription request.
|
// deadlock waiting for it to handle the subscription request.
|
||||||
if atomic.LoadUint32(&r.started) == 0 {
|
if !b.started.Load() {
|
||||||
return nil, fmt.Errorf("router not started")
|
return nil, fmt.Errorf("router not started")
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll first atomically obtain the next ID for this client from the
|
// We'll first atomically obtain the next ID for this client from the
|
||||||
// incrementing client ID counter.
|
// incrementing client ID counter.
|
||||||
clientID := atomic.AddUint64(&r.ntfnClientCounter, 1)
|
clientID := atomic.AddUint64(&b.ntfnClientCounter, 1)
|
||||||
|
|
||||||
log.Debugf("New graph topology client subscription, client %v",
|
log.Debugf("New graph topology client subscription, client %v",
|
||||||
clientID)
|
clientID)
|
||||||
@ -74,12 +73,12 @@ func (r *ChannelRouter) SubscribeTopology() (*TopologyClient, error) {
|
|||||||
ntfnChan := make(chan *TopologyChange, 10)
|
ntfnChan := make(chan *TopologyChange, 10)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case r.ntfnClientUpdates <- &topologyClientUpdate{
|
case b.ntfnClientUpdates <- &topologyClientUpdate{
|
||||||
cancel: false,
|
cancel: false,
|
||||||
clientID: clientID,
|
clientID: clientID,
|
||||||
ntfnChan: ntfnChan,
|
ntfnChan: ntfnChan,
|
||||||
}:
|
}:
|
||||||
case <-r.quit:
|
case <-b.quit:
|
||||||
return nil, errors.New("ChannelRouter shutting down")
|
return nil, errors.New("ChannelRouter shutting down")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,11 +86,11 @@ func (r *ChannelRouter) SubscribeTopology() (*TopologyClient, error) {
|
|||||||
TopologyChanges: ntfnChan,
|
TopologyChanges: ntfnChan,
|
||||||
Cancel: func() {
|
Cancel: func() {
|
||||||
select {
|
select {
|
||||||
case r.ntfnClientUpdates <- &topologyClientUpdate{
|
case b.ntfnClientUpdates <- &topologyClientUpdate{
|
||||||
cancel: true,
|
cancel: true,
|
||||||
clientID: clientID,
|
clientID: clientID,
|
||||||
}:
|
}:
|
||||||
case <-r.quit:
|
case <-b.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -117,7 +116,7 @@ type topologyClient struct {
|
|||||||
|
|
||||||
// notifyTopologyChange notifies all registered clients of a new change in
|
// notifyTopologyChange notifies all registered clients of a new change in
|
||||||
// graph topology in a non-blocking.
|
// graph topology in a non-blocking.
|
||||||
func (r *ChannelRouter) notifyTopologyChange(topologyDiff *TopologyChange) {
|
func (b *Builder) notifyTopologyChange(topologyDiff *TopologyChange) {
|
||||||
|
|
||||||
// notifyClient is a helper closure that will send topology updates to
|
// notifyClient is a helper closure that will send topology updates to
|
||||||
// the given client.
|
// the given client.
|
||||||
@ -146,7 +145,7 @@ func (r *ChannelRouter) notifyTopologyChange(topologyDiff *TopologyChange) {
|
|||||||
|
|
||||||
// Similarly, if the ChannelRouter itself exists early,
|
// Similarly, if the ChannelRouter itself exists early,
|
||||||
// then we'll also exit ourselves.
|
// then we'll also exit ourselves.
|
||||||
case <-r.quit:
|
case <-b.quit:
|
||||||
|
|
||||||
}
|
}
|
||||||
}(client)
|
}(client)
|
||||||
@ -158,7 +157,7 @@ func (r *ChannelRouter) notifyTopologyChange(topologyDiff *TopologyChange) {
|
|||||||
|
|
||||||
// Range over the set of active clients, and attempt to send the
|
// Range over the set of active clients, and attempt to send the
|
||||||
// topology updates.
|
// topology updates.
|
||||||
r.topologyClients.Range(notifyClient)
|
b.topologyClients.Range(notifyClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TopologyChange represents a new set of modifications to the channel graph.
|
// TopologyChange represents a new set of modifications to the channel graph.
|
||||||
@ -314,7 +313,7 @@ type ChannelEdgeUpdate struct {
|
|||||||
// constitutes. This function will also fetch any required auxiliary
|
// constitutes. This function will also fetch any required auxiliary
|
||||||
// information required to create the topology change update from the graph
|
// information required to create the topology change update from the graph
|
||||||
// database.
|
// database.
|
||||||
func addToTopologyChange(graph graph.DB, update *TopologyChange,
|
func addToTopologyChange(graph DB, update *TopologyChange,
|
||||||
msg interface{}) error {
|
msg interface{}) error {
|
||||||
|
|
||||||
switch m := msg.(type) {
|
switch m := msg.(type) {
|
@ -1,7 +1,8 @@
|
|||||||
package routing
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
prand "math/rand"
|
prand "math/rand"
|
||||||
@ -11,13 +12,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
|
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/go-errors/errors"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||||
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
|
lnmock "github.com/lightningnetwork/lnd/lntest/mock"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
@ -49,15 +54,28 @@ var (
|
|||||||
bitcoinKey2 = priv2.PubKey()
|
bitcoinKey2 = priv2.PubKey()
|
||||||
|
|
||||||
timeout = time.Second * 5
|
timeout = time.Second * 5
|
||||||
|
|
||||||
|
testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18e949ddfa2965fb6caa1bf0314f882d7")
|
||||||
|
testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a88121167221b6700d72a0ead154c03be696a292d24ae")
|
||||||
|
testRScalar = new(btcec.ModNScalar)
|
||||||
|
testSScalar = new(btcec.ModNScalar)
|
||||||
|
_ = testRScalar.SetByteSlice(testRBytes)
|
||||||
|
_ = testSScalar.SetByteSlice(testSBytes)
|
||||||
|
testSig = ecdsa.NewSignature(testRScalar, testSScalar)
|
||||||
|
|
||||||
|
testAuthProof = models.ChannelAuthProof{
|
||||||
|
NodeSig1Bytes: testSig.Serialize(),
|
||||||
|
NodeSig2Bytes: testSig.Serialize(),
|
||||||
|
BitcoinSig1Bytes: testSig.Serialize(),
|
||||||
|
BitcoinSig2Bytes: testSig.Serialize(),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func createTestNode() (*channeldb.LightningNode, error) {
|
func createTestNode(t *testing.T) *channeldb.LightningNode {
|
||||||
updateTime := prand.Int63()
|
updateTime := prand.Int63()
|
||||||
|
|
||||||
priv, err := btcec.NewPrivateKey()
|
priv, err := btcec.NewPrivateKey()
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
return nil, errors.Errorf("unable create private key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub := priv.PubKey().SerializeCompressed()
|
pub := priv.PubKey().SerializeCompressed()
|
||||||
n := &channeldb.LightningNode{
|
n := &channeldb.LightningNode{
|
||||||
@ -71,7 +89,7 @@ func createTestNode() (*channeldb.LightningNode, error) {
|
|||||||
}
|
}
|
||||||
copy(n.PubKeyBytes[:], pub)
|
copy(n.PubKeyBytes[:], pub)
|
||||||
|
|
||||||
return n, nil
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func randEdgePolicy(chanID *lnwire.ShortChannelID,
|
func randEdgePolicy(chanID *lnwire.ShortChannelID,
|
||||||
@ -271,7 +289,7 @@ type mockChainView struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A compile time check to ensure mockChainView implements the
|
// A compile time check to ensure mockChainView implements the
|
||||||
// chainview.FilteredChainView.
|
// chainview.FilteredChainViewReader.
|
||||||
var _ chainview.FilteredChainView = (*mockChainView)(nil)
|
var _ chainview.FilteredChainView = (*mockChainView)(nil)
|
||||||
|
|
||||||
func newMockChainView(chain lnwallet.BlockChainIO) *mockChainView {
|
func newMockChainView(chain lnwallet.BlockChainIO) *mockChainView {
|
||||||
@ -302,6 +320,15 @@ func (m *mockChainView) UpdateFilter(ops []channeldb.EdgePoint, updateHeight uin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockChainView) Start() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockChainView) Stop() error {
|
||||||
|
close(m.quit)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockChainView) notifyBlock(hash chainhash.Hash, height uint32,
|
func (m *mockChainView) notifyBlock(hash chainhash.Hash, height uint32,
|
||||||
txns []*wire.MsgTx, t *testing.T) {
|
txns []*wire.MsgTx, t *testing.T) {
|
||||||
|
|
||||||
@ -405,15 +432,6 @@ func (m *mockChainView) FilterBlock(blockHash *chainhash.Hash) (*chainview.Filte
|
|||||||
return filteredBlock, nil
|
return filteredBlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockChainView) Start() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockChainView) Stop() error {
|
|
||||||
close(m.quit)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestEdgeUpdateNotification tests that when edges are updated or added,
|
// TestEdgeUpdateNotification tests that when edges are updated or added,
|
||||||
// a proper notification is sent of to all registered clients.
|
// a proper notification is sent of to all registered clients.
|
||||||
func TestEdgeUpdateNotification(t *testing.T) {
|
func TestEdgeUpdateNotification(t *testing.T) {
|
||||||
@ -437,10 +455,8 @@ func TestEdgeUpdateNotification(t *testing.T) {
|
|||||||
|
|
||||||
// Next we'll create two test nodes that the fake channel will be open
|
// Next we'll create two test nodes that the fake channel will be open
|
||||||
// between.
|
// between.
|
||||||
node1, err := createTestNode()
|
node1 := createTestNode(t)
|
||||||
require.NoError(t, err, "unable to create test node")
|
node2 := createTestNode(t)
|
||||||
node2, err := createTestNode()
|
|
||||||
require.NoError(t, err, "unable to create test node")
|
|
||||||
|
|
||||||
// Finally, to conclude our test set up, we'll create a channel
|
// Finally, to conclude our test set up, we'll create a channel
|
||||||
// update to announce the created channel between the two nodes.
|
// update to announce the created channel between the two nodes.
|
||||||
@ -458,13 +474,13 @@ func TestEdgeUpdateNotification(t *testing.T) {
|
|||||||
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
|
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
|
||||||
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
|
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
|
||||||
|
|
||||||
if err := ctx.router.AddEdge(edge); err != nil {
|
if err := ctx.builder.AddEdge(edge); err != nil {
|
||||||
t.Fatalf("unable to add edge: %v", err)
|
t.Fatalf("unable to add edge: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// With the channel edge now in place, we'll subscribe for topology
|
// With the channel edge now in place, we'll subscribe for topology
|
||||||
// notifications.
|
// notifications.
|
||||||
ntfnClient, err := ctx.router.SubscribeTopology()
|
ntfnClient, err := ctx.builder.SubscribeTopology()
|
||||||
require.NoError(t, err, "unable to subscribe for channel notifications")
|
require.NoError(t, err, "unable to subscribe for channel notifications")
|
||||||
|
|
||||||
// Create random policy edges that are stemmed to the channel id
|
// Create random policy edges that are stemmed to the channel id
|
||||||
@ -477,10 +493,10 @@ func TestEdgeUpdateNotification(t *testing.T) {
|
|||||||
require.NoError(t, err, "unable to create a random chan policy")
|
require.NoError(t, err, "unable to create a random chan policy")
|
||||||
edge2.ChannelFlags = 1
|
edge2.ChannelFlags = 1
|
||||||
|
|
||||||
if err := ctx.router.UpdateEdge(edge1); err != nil {
|
if err := ctx.builder.UpdateEdge(edge1); err != nil {
|
||||||
t.Fatalf("unable to add edge update: %v", err)
|
t.Fatalf("unable to add edge update: %v", err)
|
||||||
}
|
}
|
||||||
if err := ctx.router.UpdateEdge(edge2); err != nil {
|
if err := ctx.builder.UpdateEdge(edge2); err != nil {
|
||||||
t.Fatalf("unable to add edge update: %v", err)
|
t.Fatalf("unable to add edge update: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,10 +641,8 @@ func TestNodeUpdateNotification(t *testing.T) {
|
|||||||
// Create two nodes acting as endpoints in the created channel, and use
|
// Create two nodes acting as endpoints in the created channel, and use
|
||||||
// them to trigger notifications by sending updated node announcement
|
// them to trigger notifications by sending updated node announcement
|
||||||
// messages.
|
// messages.
|
||||||
node1, err := createTestNode()
|
node1 := createTestNode(t)
|
||||||
require.NoError(t, err, "unable to create test node")
|
node2 := createTestNode(t)
|
||||||
node2, err := createTestNode()
|
|
||||||
require.NoError(t, err, "unable to create test node")
|
|
||||||
|
|
||||||
testFeaturesBuf := new(bytes.Buffer)
|
testFeaturesBuf := new(bytes.Buffer)
|
||||||
require.NoError(t, testFeatures.Encode(testFeaturesBuf))
|
require.NoError(t, testFeatures.Encode(testFeaturesBuf))
|
||||||
@ -649,20 +663,20 @@ func TestNodeUpdateNotification(t *testing.T) {
|
|||||||
|
|
||||||
// Adding the edge will add the nodes to the graph, but with no info
|
// Adding the edge will add the nodes to the graph, but with no info
|
||||||
// except the pubkey known.
|
// except the pubkey known.
|
||||||
if err := ctx.router.AddEdge(edge); err != nil {
|
if err := ctx.builder.AddEdge(edge); err != nil {
|
||||||
t.Fatalf("unable to add edge: %v", err)
|
t.Fatalf("unable to add edge: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new client to receive notifications.
|
// Create a new client to receive notifications.
|
||||||
ntfnClient, err := ctx.router.SubscribeTopology()
|
ntfnClient, err := ctx.builder.SubscribeTopology()
|
||||||
require.NoError(t, err, "unable to subscribe for channel notifications")
|
require.NoError(t, err, "unable to subscribe for channel notifications")
|
||||||
|
|
||||||
// Change network topology by adding the updated info for the two nodes
|
// Change network topology by adding the updated info for the two nodes
|
||||||
// to the channel router.
|
// to the channel router.
|
||||||
if err := ctx.router.AddNode(node1); err != nil {
|
if err := ctx.builder.AddNode(node1); err != nil {
|
||||||
t.Fatalf("unable to add node: %v", err)
|
t.Fatalf("unable to add node: %v", err)
|
||||||
}
|
}
|
||||||
if err := ctx.router.AddNode(node2); err != nil {
|
if err := ctx.builder.AddNode(node2); err != nil {
|
||||||
t.Fatalf("unable to add node: %v", err)
|
t.Fatalf("unable to add node: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,7 +770,7 @@ func TestNodeUpdateNotification(t *testing.T) {
|
|||||||
nodeUpdateAnn.LastUpdate = node1.LastUpdate.Add(300 * time.Millisecond)
|
nodeUpdateAnn.LastUpdate = node1.LastUpdate.Add(300 * time.Millisecond)
|
||||||
|
|
||||||
// Add new node topology update to the channel router.
|
// Add new node topology update to the channel router.
|
||||||
if err := ctx.router.AddNode(&nodeUpdateAnn); err != nil {
|
if err := ctx.builder.AddNode(&nodeUpdateAnn); err != nil {
|
||||||
t.Fatalf("unable to add node: %v", err)
|
t.Fatalf("unable to add node: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,7 +802,7 @@ func TestNotificationCancellation(t *testing.T) {
|
|||||||
ctx := createTestCtxSingleNode(t, startingBlockHeight)
|
ctx := createTestCtxSingleNode(t, startingBlockHeight)
|
||||||
|
|
||||||
// Create a new client to receive notifications.
|
// Create a new client to receive notifications.
|
||||||
ntfnClient, err := ctx.router.SubscribeTopology()
|
ntfnClient, err := ctx.builder.SubscribeTopology()
|
||||||
require.NoError(t, err, "unable to subscribe for channel notifications")
|
require.NoError(t, err, "unable to subscribe for channel notifications")
|
||||||
|
|
||||||
// We'll create the utxo for a new channel.
|
// We'll create the utxo for a new channel.
|
||||||
@ -808,10 +822,8 @@ func TestNotificationCancellation(t *testing.T) {
|
|||||||
|
|
||||||
// We'll create a fresh new node topology update to feed to the channel
|
// We'll create a fresh new node topology update to feed to the channel
|
||||||
// router.
|
// router.
|
||||||
node1, err := createTestNode()
|
node1 := createTestNode(t)
|
||||||
require.NoError(t, err, "unable to create test node")
|
node2 := createTestNode(t)
|
||||||
node2, err := createTestNode()
|
|
||||||
require.NoError(t, err, "unable to create test node")
|
|
||||||
|
|
||||||
// Before we send the message to the channel router, we'll cancel the
|
// Before we send the message to the channel router, we'll cancel the
|
||||||
// notifications for this client. As a result, the notification
|
// notifications for this client. As a result, the notification
|
||||||
@ -832,15 +844,15 @@ func TestNotificationCancellation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
|
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
|
||||||
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
|
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
|
||||||
if err := ctx.router.AddEdge(edge); err != nil {
|
if err := ctx.builder.AddEdge(edge); err != nil {
|
||||||
t.Fatalf("unable to add edge: %v", err)
|
t.Fatalf("unable to add edge: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ctx.router.AddNode(node1); err != nil {
|
if err := ctx.builder.AddNode(node1); err != nil {
|
||||||
t.Fatalf("unable to add node: %v", err)
|
t.Fatalf("unable to add node: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ctx.router.AddNode(node2); err != nil {
|
if err := ctx.builder.AddNode(node2); err != nil {
|
||||||
t.Fatalf("unable to add node: %v", err)
|
t.Fatalf("unable to add node: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -883,10 +895,8 @@ func TestChannelCloseNotification(t *testing.T) {
|
|||||||
|
|
||||||
// Next we'll create two test nodes that the fake channel will be open
|
// Next we'll create two test nodes that the fake channel will be open
|
||||||
// between.
|
// between.
|
||||||
node1, err := createTestNode()
|
node1 := createTestNode(t)
|
||||||
require.NoError(t, err, "unable to create test node")
|
node2 := createTestNode(t)
|
||||||
node2, err := createTestNode()
|
|
||||||
require.NoError(t, err, "unable to create test node")
|
|
||||||
|
|
||||||
// Finally, to conclude our test set up, we'll create a channel
|
// Finally, to conclude our test set up, we'll create a channel
|
||||||
// announcement to announce the created channel between the two nodes.
|
// announcement to announce the created channel between the two nodes.
|
||||||
@ -903,13 +913,13 @@ func TestChannelCloseNotification(t *testing.T) {
|
|||||||
}
|
}
|
||||||
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
|
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
|
||||||
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
|
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
|
||||||
if err := ctx.router.AddEdge(edge); err != nil {
|
if err := ctx.builder.AddEdge(edge); err != nil {
|
||||||
t.Fatalf("unable to add edge: %v", err)
|
t.Fatalf("unable to add edge: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// With the channel edge now in place, we'll subscribe for topology
|
// With the channel edge now in place, we'll subscribe for topology
|
||||||
// notifications.
|
// notifications.
|
||||||
ntfnClient, err := ctx.router.SubscribeTopology()
|
ntfnClient, err := ctx.builder.SubscribeTopology()
|
||||||
require.NoError(t, err, "unable to subscribe for channel notifications")
|
require.NoError(t, err, "unable to subscribe for channel notifications")
|
||||||
|
|
||||||
// Next, we'll simulate the closure of our channel by generating a new
|
// Next, we'll simulate the closure of our channel by generating a new
|
||||||
@ -999,3 +1009,200 @@ func TestEncodeHexColor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testCtx struct {
|
||||||
|
builder *Builder
|
||||||
|
|
||||||
|
graph *channeldb.ChannelGraph
|
||||||
|
|
||||||
|
aliases map[string]route.Vertex
|
||||||
|
|
||||||
|
privKeys map[string]*btcec.PrivateKey
|
||||||
|
|
||||||
|
channelIDs map[route.Vertex]map[route.Vertex]uint64
|
||||||
|
|
||||||
|
chain *mockChain
|
||||||
|
chainView *mockChainView
|
||||||
|
|
||||||
|
notifier *lnmock.ChainNotifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testCtx) getChannelIDFromAlias(t *testing.T, a, b string) uint64 {
|
||||||
|
vertexA, ok := c.aliases[a]
|
||||||
|
require.True(t, ok, "cannot find aliases for %s", a)
|
||||||
|
|
||||||
|
vertexB, ok := c.aliases[b]
|
||||||
|
require.True(t, ok, "cannot find aliases for %s", b)
|
||||||
|
|
||||||
|
channelIDMap, ok := c.channelIDs[vertexA]
|
||||||
|
require.True(t, ok, "cannot find channelID map %s(%s)", vertexA, a)
|
||||||
|
|
||||||
|
channelID, ok := channelIDMap[vertexB]
|
||||||
|
require.True(t, ok, "cannot find channelID using %s(%s)", vertexB, b)
|
||||||
|
|
||||||
|
return channelID
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTestCtxSingleNode(t *testing.T,
|
||||||
|
startingHeight uint32) *testCtx {
|
||||||
|
|
||||||
|
graph, graphBackend, err := makeTestGraph(t, true)
|
||||||
|
require.NoError(t, err, "failed to make test graph")
|
||||||
|
|
||||||
|
sourceNode := createTestNode(t)
|
||||||
|
|
||||||
|
require.NoError(t,
|
||||||
|
graph.SetSourceNode(sourceNode), "failed to set source node",
|
||||||
|
)
|
||||||
|
|
||||||
|
graphInstance := &testGraphInstance{
|
||||||
|
graph: graph,
|
||||||
|
graphBackend: graphBackend,
|
||||||
|
}
|
||||||
|
|
||||||
|
return createTestCtxFromGraphInstance(
|
||||||
|
t, startingHeight, graphInstance, false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testCtx) RestartBuilder(t *testing.T) {
|
||||||
|
c.chainView.Reset()
|
||||||
|
|
||||||
|
selfNode, err := c.graph.SourceNode()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// With the chainView reset, we'll now re-create the builder itself, and
|
||||||
|
// start it.
|
||||||
|
builder, err := NewBuilder(&Config{
|
||||||
|
SelfNode: selfNode.PubKeyBytes,
|
||||||
|
Graph: c.graph,
|
||||||
|
Chain: c.chain,
|
||||||
|
ChainView: c.chainView,
|
||||||
|
Notifier: c.builder.cfg.Notifier,
|
||||||
|
ChannelPruneExpiry: time.Hour * 24,
|
||||||
|
GraphPruneInterval: time.Hour * 2,
|
||||||
|
AssumeChannelValid: c.builder.cfg.AssumeChannelValid,
|
||||||
|
FirstTimePruneDelay: c.builder.cfg.FirstTimePruneDelay,
|
||||||
|
StrictZombiePruning: c.builder.cfg.StrictZombiePruning,
|
||||||
|
IsAlias: func(scid lnwire.ShortChannelID) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, builder.Start())
|
||||||
|
|
||||||
|
// Finally, we'll swap out the pointer in the testCtx with this fresh
|
||||||
|
// instance of the router.
|
||||||
|
c.builder = builder
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeTestGraph creates a new instance of a channeldb.ChannelGraph for testing
|
||||||
|
// purposes.
|
||||||
|
func makeTestGraph(t *testing.T, useCache bool) (*channeldb.ChannelGraph,
|
||||||
|
kvdb.Backend, error) {
|
||||||
|
|
||||||
|
// Create channelgraph for the first time.
|
||||||
|
backend, backendCleanup, err := kvdb.GetTestBackend(t.TempDir(), "cgr")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(backendCleanup)
|
||||||
|
|
||||||
|
opts := channeldb.DefaultOptions()
|
||||||
|
graph, err := channeldb.NewChannelGraph(
|
||||||
|
backend, opts.RejectCacheSize, opts.ChannelCacheSize,
|
||||||
|
opts.BatchCommitInterval, opts.PreAllocCacheNumNodes,
|
||||||
|
useCache, false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return graph, backend, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testGraphInstance struct {
|
||||||
|
graph *channeldb.ChannelGraph
|
||||||
|
graphBackend kvdb.Backend
|
||||||
|
|
||||||
|
// aliasMap is a map from a node's alias to its public key. This type is
|
||||||
|
// provided in order to allow easily look up from the human memorable alias
|
||||||
|
// to an exact node's public key.
|
||||||
|
aliasMap map[string]route.Vertex
|
||||||
|
|
||||||
|
// privKeyMap maps a node alias to its private key. This is used to be
|
||||||
|
// able to mock a remote node's signing behaviour.
|
||||||
|
privKeyMap map[string]*btcec.PrivateKey
|
||||||
|
|
||||||
|
// channelIDs stores the channel ID for each node.
|
||||||
|
channelIDs map[route.Vertex]map[route.Vertex]uint64
|
||||||
|
|
||||||
|
// links maps channel ids to a mock channel update handler.
|
||||||
|
links map[lnwire.ShortChannelID]htlcswitch.ChannelLink
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTestCtxFromGraphInstance(t *testing.T,
|
||||||
|
startingHeight uint32, graphInstance *testGraphInstance,
|
||||||
|
strictPruning bool) *testCtx {
|
||||||
|
|
||||||
|
return createTestCtxFromGraphInstanceAssumeValid(
|
||||||
|
t, startingHeight, graphInstance, false, strictPruning,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTestCtxFromGraphInstanceAssumeValid(t *testing.T,
|
||||||
|
startingHeight uint32, graphInstance *testGraphInstance,
|
||||||
|
assumeValid bool, strictPruning bool) *testCtx {
|
||||||
|
|
||||||
|
// We'll initialize an instance of the channel router with mock
|
||||||
|
// versions of the chain and channel notifier. As we don't need to test
|
||||||
|
// any p2p functionality, the peer send and switch send messages won't
|
||||||
|
// be populated.
|
||||||
|
chain := newMockChain(startingHeight)
|
||||||
|
chainView := newMockChainView(chain)
|
||||||
|
|
||||||
|
notifier := &lnmock.ChainNotifier{
|
||||||
|
EpochChan: make(chan *chainntnfs.BlockEpoch),
|
||||||
|
SpendChan: make(chan *chainntnfs.SpendDetail),
|
||||||
|
ConfChan: make(chan *chainntnfs.TxConfirmation),
|
||||||
|
}
|
||||||
|
|
||||||
|
selfnode, err := graphInstance.graph.SourceNode()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
graphBuilder, err := NewBuilder(&Config{
|
||||||
|
SelfNode: selfnode.PubKeyBytes,
|
||||||
|
Graph: graphInstance.graph,
|
||||||
|
Chain: chain,
|
||||||
|
ChainView: chainView,
|
||||||
|
Notifier: notifier,
|
||||||
|
ChannelPruneExpiry: time.Hour * 24,
|
||||||
|
GraphPruneInterval: time.Hour * 2,
|
||||||
|
AssumeChannelValid: assumeValid,
|
||||||
|
FirstTimePruneDelay: 0,
|
||||||
|
StrictZombiePruning: strictPruning,
|
||||||
|
IsAlias: func(scid lnwire.ShortChannelID) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, graphBuilder.Start())
|
||||||
|
|
||||||
|
ctx := &testCtx{
|
||||||
|
builder: graphBuilder,
|
||||||
|
graph: graphInstance.graph,
|
||||||
|
aliases: graphInstance.aliasMap,
|
||||||
|
privKeys: graphInstance.privKeyMap,
|
||||||
|
channelIDs: graphInstance.channelIDs,
|
||||||
|
chain: chain,
|
||||||
|
chainView: chainView,
|
||||||
|
notifier: notifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
graphBuilder.Stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
}
|
11
graph/setup_test.go
Normal file
11
graph/setup_test.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package graph
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
kvdb.RunTests(m)
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package routing
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
298
graph/testdata/basic_graph.json
vendored
Normal file
298
graph/testdata/basic_graph.json
vendored
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
{
|
||||||
|
"info": [
|
||||||
|
"This file encodes a basic graph that resembles the following ascii graph:",
|
||||||
|
"",
|
||||||
|
" 50k satoshis ┌──────┐ ",
|
||||||
|
" ┌───────────────────▶│luo ji│◀─┐ ",
|
||||||
|
" │ └──────┘ │ ┌──────┐ ",
|
||||||
|
" │ │ | elst | ",
|
||||||
|
" │ │ └──────┘ ",
|
||||||
|
" │ │ ▲ ",
|
||||||
|
" │ │ | 100k sat ",
|
||||||
|
" │ │ ▼ ",
|
||||||
|
" ▼ │ ┌──────┐ ",
|
||||||
|
" ┌────────┐ │ │sophon│◀┐ ",
|
||||||
|
" │satoshi │ │ └──────┘ │ ",
|
||||||
|
" └────────┘ │ ▲ │ ",
|
||||||
|
" ▲ │ | │ 110k satoshis ",
|
||||||
|
" │ ┌───────────────────┘ | │ ",
|
||||||
|
" │ │ 100k satoshis | │ ",
|
||||||
|
" │ │ | │ ",
|
||||||
|
" │ │ 120k sat | │ ┌────────┐ ",
|
||||||
|
" └──────────┤ (hi fee) ▼ └─▶│son goku│ ",
|
||||||
|
" 10k satoshis │ ┌────────────┐ └────────┘ ",
|
||||||
|
" │ | pham nuwen | ▲ ",
|
||||||
|
" │ └────────────┘ │ ",
|
||||||
|
" │ ▲ │ ",
|
||||||
|
" ▼ | 120k sat (hi fee) │ ",
|
||||||
|
" ┌──────────┐ | │ ",
|
||||||
|
" │ roasbeef │◀──────────────┴──────────────────────┘ ",
|
||||||
|
" └──────────┘ 100k satoshis ",
|
||||||
|
|
||||||
|
" the graph also includes a channel from roasbeef to sophon via pham nuwen"
|
||||||
|
],
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"source": true,
|
||||||
|
"pubkey": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"alias": "roasbeef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "026c43a8ac1cd8519985766e90748e1e06871dab0ff6b8af27e8c1a61640481318",
|
||||||
|
"privkey": "82b266f659bd83a976bac11b2cc442baec5508e84e61085d7ec2b0fc52156c87",
|
||||||
|
"alias": "songoku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"alias": "satoshi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"alias": "luoji"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "036264734b40c9e91d3d990a8cdfbbe23b5b0b7ad3cd0e080a25dcd05d39eeb7eb",
|
||||||
|
"alias": "sophon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "02a1d2856be336a58af08989aea0d8c41e072ccc392c46f8ce0e6e069f002035f3",
|
||||||
|
"alias": "phamnuwen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "02a4b236b69b09b8efe6ccf822fa95ee95a0196451f4d066a450b7489e2e354a64",
|
||||||
|
"alias": "elst"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"node_1": "02a4b236b69b09b8efe6ccf822fa95ee95a0196451f4d066a450b7489e2e354a64",
|
||||||
|
"node_2": "036264734b40c9e91d3d990a8cdfbbe23b5b0b7ad3cd0e080a25dcd05d39eeb7eb",
|
||||||
|
"channel_id": 15433,
|
||||||
|
"channel_point": "33bd5d49a50e284221561b91e781f1fca0d60341c9f9dd785b5e379a6d88af3d:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1000,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 200,
|
||||||
|
"fee_rate": 0,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02a4b236b69b09b8efe6ccf822fa95ee95a0196451f4d066a450b7489e2e354a64",
|
||||||
|
"node_2": "036264734b40c9e91d3d990a8cdfbbe23b5b0b7ad3cd0e080a25dcd05d39eeb7eb",
|
||||||
|
"channel_id": 15433,
|
||||||
|
"channel_point": "33bd5d49a50e284221561b91e781f1fca0d60341c9f9dd785b5e379a6d88af3d:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1000,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 200,
|
||||||
|
"fee_rate": 0,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02a1d2856be336a58af08989aea0d8c41e072ccc392c46f8ce0e6e069f002035f3",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 999991,
|
||||||
|
"channel_point": "48a0e8b856fef01d9feda7d25a4fac6dae48749e28ba356b92d712ab7f5bd2d0:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1000,
|
||||||
|
"max_htlc": 120000000,
|
||||||
|
"fee_base_msat": 10000,
|
||||||
|
"fee_rate": 100000,
|
||||||
|
"capacity": 120000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02a1d2856be336a58af08989aea0d8c41e072ccc392c46f8ce0e6e069f002035f3",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 999991,
|
||||||
|
"channel_point": "48a0e8b856fef01d9feda7d25a4fac6dae48749e28ba356b92d712ab7f5bd2d0:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1000,
|
||||||
|
"max_htlc": 120000000,
|
||||||
|
"fee_base_msat": 10000,
|
||||||
|
"fee_rate": 100000,
|
||||||
|
"capacity": 120000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02a1d2856be336a58af08989aea0d8c41e072ccc392c46f8ce0e6e069f002035f3",
|
||||||
|
"node_2": "036264734b40c9e91d3d990a8cdfbbe23b5b0b7ad3cd0e080a25dcd05d39eeb7eb",
|
||||||
|
"channel_id": 99999,
|
||||||
|
"channel_point": "05ffda8890d0a4fffe0ddca0b1932ba0415b1d5868a99515384a4e7883d96b88:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1000,
|
||||||
|
"max_htlc": 120000000,
|
||||||
|
"fee_base_msat": 10000,
|
||||||
|
"fee_rate": 100000,
|
||||||
|
"capacity": 120000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02a1d2856be336a58af08989aea0d8c41e072ccc392c46f8ce0e6e069f002035f3",
|
||||||
|
"node_2": "036264734b40c9e91d3d990a8cdfbbe23b5b0b7ad3cd0e080a25dcd05d39eeb7eb",
|
||||||
|
"channel_id": 99999,
|
||||||
|
"channel_point": "05ffda8890d0a4fffe0ddca0b1932ba0415b1d5868a99515384a4e7883d96b88:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1000,
|
||||||
|
"max_htlc": 120000000,
|
||||||
|
"fee_base_msat": 10000,
|
||||||
|
"fee_rate": 100000,
|
||||||
|
"capacity": 120000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "026c43a8ac1cd8519985766e90748e1e06871dab0ff6b8af27e8c1a61640481318",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 12345,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1000,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "026c43a8ac1cd8519985766e90748e1e06871dab0ff6b8af27e8c1a61640481318",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 12345,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "026c43a8ac1cd8519985766e90748e1e06871dab0ff6b8af27e8c1a61640481318",
|
||||||
|
"node_2": "036264734b40c9e91d3d990a8cdfbbe23b5b0b7ad3cd0e080a25dcd05d39eeb7eb",
|
||||||
|
"channel_id": 3495345,
|
||||||
|
"channel_point": "9f155756b33a0a6827713965babbd561b55f9520444ac5db0cf7cb2eb0deb5bc:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 110000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 110000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "026c43a8ac1cd8519985766e90748e1e06871dab0ff6b8af27e8c1a61640481318",
|
||||||
|
"node_2": "036264734b40c9e91d3d990a8cdfbbe23b5b0b7ad3cd0e080a25dcd05d39eeb7eb",
|
||||||
|
"channel_id": 3495345,
|
||||||
|
"channel_point": "9f155756b33a0a6827713965babbd561b55f9520444ac5db0cf7cb2eb0deb5bc:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 110000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 110000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"node_2": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"channel_id": 2340213491,
|
||||||
|
"channel_point": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 10000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 10000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"node_2": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"channel_id": 2340213491,
|
||||||
|
"channel_point": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 10000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 10000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 689530843,
|
||||||
|
"channel_point": "25376aa6cb81913ad30416bd22d4083241bd6d68e811d0284d3c3a17795c458a:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 10,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 689530843,
|
||||||
|
"channel_point": "25376aa6cb81913ad30416bd22d4083241bd6d68e811d0284d3c3a17795c458a:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"node_2": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"channel_id": 523452362,
|
||||||
|
"channel_point": "704a5675c91b1c674309a6475fc51072c2913d6117ee6103c9f1b86956bcbe02:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 50000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 50000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_1": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"node_2": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"channel_id": 523452362,
|
||||||
|
"channel_point": "704a5675c91b1c674309a6475fc51072c2913d6117ee6103c9f1b86956bcbe02:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 1,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 50000000,
|
||||||
|
"fee_base_msat": 10,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 50000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
147
graph/testdata/spec_example.json
vendored
Normal file
147
graph/testdata/spec_example.json
vendored
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"alias": "A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": true,
|
||||||
|
"pubkey": "032b480de5d002f1a8fd1fe1bbf0a0f1b07760f65f052e66d56f15d71097c01add",
|
||||||
|
"alias": "B"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"alias": "C"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": false,
|
||||||
|
"pubkey": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"alias": "D"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
|
||||||
|
"comment": "A -> B channel",
|
||||||
|
"node_1": "032b480de5d002f1a8fd1fe1bbf0a0f1b07760f65f052e66d56f15d71097c01add",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 12345,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 10,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 100,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "B -> A channel",
|
||||||
|
"node_1": "032b480de5d002f1a8fd1fe1bbf0a0f1b07760f65f052e66d56f15d71097c01add",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 12345,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 20,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 200,
|
||||||
|
"fee_rate": 2000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "A -> D channel",
|
||||||
|
"node_1": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 12345839,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 10,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 100,
|
||||||
|
"fee_rate": 1000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "D -> A channel",
|
||||||
|
"node_1": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"node_2": "0367cec75158a4129177bfb8b269cb586efe93d751b43800d456485e81c2620ca6",
|
||||||
|
"channel_id": 12345839,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 40,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 400,
|
||||||
|
"fee_rate": 4000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "D -> C channel",
|
||||||
|
"node_1": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"node_2": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"channel_id": 1234583,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 40,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 400,
|
||||||
|
"fee_rate": 4000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "C -> D channel",
|
||||||
|
"node_1": "02e7b1aaac10977c38e9c61c74dc66840de211bcec3021603e7977bc5e28edabfd",
|
||||||
|
"node_2": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"channel_id": 1234583,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 30,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 300,
|
||||||
|
"fee_rate": 3000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "C -> B channel",
|
||||||
|
"node_1": "032b480de5d002f1a8fd1fe1bbf0a0f1b07760f65f052e66d56f15d71097c01add",
|
||||||
|
"node_2": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"channel_id": 1234589,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 1,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 30,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 300,
|
||||||
|
"fee_rate": 3000,
|
||||||
|
"capacity": 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "B -> C channel",
|
||||||
|
"node_1": "032b480de5d002f1a8fd1fe1bbf0a0f1b07760f65f052e66d56f15d71097c01add",
|
||||||
|
"node_2": "03c19f0027ffbb0ae0e14a4d958788793f9d74e107462473ec0c3891e4feb12e99",
|
||||||
|
"channel_id": 1234589,
|
||||||
|
"channel_point": "89dc56859c6a082d15ba1a7f6cb6be3fea62e1746e2cb8497b1189155c21a233:0",
|
||||||
|
"channel_flags": 0,
|
||||||
|
"message_flags": 1,
|
||||||
|
"expiry": 20,
|
||||||
|
"min_htlc": 1,
|
||||||
|
"max_htlc": 100000000,
|
||||||
|
"fee_base_msat": 200,
|
||||||
|
"fee_rate": 2000,
|
||||||
|
"capacity": 100000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package routing
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -1,12 +1,12 @@
|
|||||||
package routing_test
|
package graph_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/graph"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestValidationBarrierSemaphore checks basic properties of the validation
|
// TestValidationBarrierSemaphore checks basic properties of the validation
|
||||||
@ -21,7 +21,7 @@ func TestValidationBarrierSemaphore(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
quit := make(chan struct{})
|
quit := make(chan struct{})
|
||||||
barrier := routing.NewValidationBarrier(numTasks, quit)
|
barrier := graph.NewValidationBarrier(numTasks, quit)
|
||||||
|
|
||||||
// Saturate the semaphore with jobs.
|
// Saturate the semaphore with jobs.
|
||||||
for i := 0; i < numTasks; i++ {
|
for i := 0; i < numTasks; i++ {
|
||||||
@ -69,7 +69,7 @@ func TestValidationBarrierQuit(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
quit := make(chan struct{})
|
quit := make(chan struct{})
|
||||||
barrier := routing.NewValidationBarrier(2*numTasks, quit)
|
barrier := graph.NewValidationBarrier(2*numTasks, quit)
|
||||||
|
|
||||||
// Create a set of unique channel announcements that we will prep for
|
// Create a set of unique channel announcements that we will prep for
|
||||||
// validation.
|
// validation.
|
||||||
@ -141,8 +141,8 @@ func TestValidationBarrierQuit(t *testing.T) {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
// First half should return without failure.
|
// First half should return without failure.
|
||||||
case i < numTasks/4 && !routing.IsError(
|
case i < numTasks/4 && !graph.IsError(
|
||||||
err, routing.ErrParentValidationFailed,
|
err, graph.ErrParentValidationFailed,
|
||||||
):
|
):
|
||||||
t.Fatalf("unexpected failure while waiting: %v", err)
|
t.Fatalf("unexpected failure while waiting: %v", err)
|
||||||
|
|
||||||
@ -150,11 +150,11 @@ func TestValidationBarrierQuit(t *testing.T) {
|
|||||||
t.Fatalf("unexpected failure while waiting: %v", err)
|
t.Fatalf("unexpected failure while waiting: %v", err)
|
||||||
|
|
||||||
// Last half should return the shutdown error.
|
// Last half should return the shutdown error.
|
||||||
case i >= numTasks/2 && !routing.IsError(
|
case i >= numTasks/2 && !graph.IsError(
|
||||||
err, routing.ErrVBarrierShuttingDown,
|
err, graph.ErrVBarrierShuttingDown,
|
||||||
):
|
):
|
||||||
t.Fatalf("expected failure after quitting: want %v, "+
|
t.Fatalf("expected failure after quitting: want %v, "+
|
||||||
"got %v", routing.ErrVBarrierShuttingDown, err)
|
"got %v", graph.ErrVBarrierShuttingDown, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,11 +7,11 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||||
|
"github.com/lightningnetwork/lnd/graph"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockSigner struct {
|
type mockSigner struct {
|
||||||
@ -182,7 +182,7 @@ func TestUpdateDisableFlag(t *testing.T) {
|
|||||||
|
|
||||||
// Finally, validate the signature using the router's
|
// Finally, validate the signature using the router's
|
||||||
// verification logic.
|
// verification logic.
|
||||||
err = routing.VerifyChannelUpdateSignature(
|
err = graph.VerifyChannelUpdateSignature(
|
||||||
newUpdate, pubKey,
|
newUpdate, pubKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
2
pilot.go
2
pilot.go
@ -295,6 +295,6 @@ func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
|
|||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
SubscribeTransactions: svr.cc.Wallet.SubscribeTransactions,
|
SubscribeTransactions: svr.cc.Wallet.SubscribeTransactions,
|
||||||
SubscribeTopology: svr.chanRouter.SubscribeTopology,
|
SubscribeTopology: svr.graphBuilder.SubscribeTopology,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -1392,10 +1392,6 @@ func TestNewRoute(t *testing.T) {
|
|||||||
// to fail or succeed.
|
// to fail or succeed.
|
||||||
expectError bool
|
expectError bool
|
||||||
|
|
||||||
// expectedErrorCode indicates the expected error code when
|
|
||||||
// expectError is true.
|
|
||||||
expectedErrorCode errorCode
|
|
||||||
|
|
||||||
expectedMPP *record.MPP
|
expectedMPP *record.MPP
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -1606,23 +1602,9 @@ func TestNewRoute(t *testing.T) {
|
|||||||
metadata: testCase.metadata,
|
metadata: testCase.metadata,
|
||||||
}, nil,
|
}, nil,
|
||||||
)
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
if testCase.expectError {
|
|
||||||
expectedCode := testCase.expectedErrorCode
|
|
||||||
if err == nil || !IsError(err, expectedCode) {
|
|
||||||
t.Fatalf("expected newRoute to fail "+
|
|
||||||
"with error code %v but got "+
|
|
||||||
"%v instead",
|
|
||||||
expectedCode, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unable to create path: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
assertRoute(t, route)
|
assertRoute(t, route)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2232,8 +2214,8 @@ func TestPathFindSpecExample(t *testing.T) {
|
|||||||
carol := ctx.aliases["C"]
|
carol := ctx.aliases["C"]
|
||||||
const amt lnwire.MilliSatoshi = 4999999
|
const amt lnwire.MilliSatoshi = 4999999
|
||||||
req, err := NewRouteRequest(
|
req, err := NewRouteRequest(
|
||||||
bob, &carol, amt, 0, noRestrictions, nil, nil, nil,
|
bob, &carol, amt, 0, noRestrictions, nil, nil,
|
||||||
MinCLTVDelta,
|
nil, MinCLTVDelta,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "invalid route request")
|
require.NoError(t, err, "invalid route request")
|
||||||
|
|
||||||
@ -2244,33 +2226,18 @@ func TestPathFindSpecExample(t *testing.T) {
|
|||||||
//
|
//
|
||||||
// It should be sending the exact payment amount as there are no
|
// It should be sending the exact payment amount as there are no
|
||||||
// additional hops.
|
// additional hops.
|
||||||
if route.TotalAmount != amt {
|
require.Equal(t, amt, route.TotalAmount)
|
||||||
t.Fatalf("wrong total amount: got %v, expected %v",
|
require.Equal(t, amt, route.Hops[0].AmtToForward)
|
||||||
route.TotalAmount, amt)
|
require.Zero(t, route.HopFee(0))
|
||||||
}
|
|
||||||
if route.Hops[0].AmtToForward != amt {
|
|
||||||
t.Fatalf("wrong forward amount: got %v, expected %v",
|
|
||||||
route.Hops[0].AmtToForward, amt)
|
|
||||||
}
|
|
||||||
|
|
||||||
fee := route.HopFee(0)
|
|
||||||
if fee != 0 {
|
|
||||||
t.Fatalf("wrong hop fee: got %v, expected %v", fee, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The CLTV expiry should be the current height plus 18 (the expiry for
|
// The CLTV expiry should be the current height plus 18 (the expiry for
|
||||||
// the B -> C channel.
|
// the B -> C channel.
|
||||||
if route.TotalTimeLock !=
|
require.EqualValues(t, startingHeight+MinCLTVDelta, route.TotalTimeLock)
|
||||||
startingHeight+MinCLTVDelta {
|
|
||||||
|
|
||||||
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
||||||
route.TotalTimeLock,
|
|
||||||
startingHeight+MinCLTVDelta)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, we'll set A as the source node so we can assert that we create
|
// Next, we'll set A as the source node so we can assert that we create
|
||||||
// the proper route for any queries starting with Alice.
|
// the proper route for any queries starting with Alice.
|
||||||
alice := ctx.aliases["A"]
|
alice := ctx.aliases["A"]
|
||||||
|
ctx.router.cfg.SelfNode = alice
|
||||||
|
|
||||||
// We'll now request a route from A -> B -> C.
|
// We'll now request a route from A -> B -> C.
|
||||||
req, err = NewRouteRequest(
|
req, err = NewRouteRequest(
|
||||||
@ -2283,32 +2250,21 @@ func TestPathFindSpecExample(t *testing.T) {
|
|||||||
require.NoError(t, err, "unable to find routes")
|
require.NoError(t, err, "unable to find routes")
|
||||||
|
|
||||||
// The route should be two hops.
|
// The route should be two hops.
|
||||||
if len(route.Hops) != 2 {
|
require.Len(t, route.Hops, 2)
|
||||||
t.Fatalf("route should be %v hops, is instead %v", 2,
|
|
||||||
len(route.Hops))
|
|
||||||
}
|
|
||||||
|
|
||||||
// The total amount should factor in a fee of 10199 and also use a CLTV
|
// The total amount should factor in a fee of 10199 and also use a CLTV
|
||||||
// delta total of 38 (20 + 18),
|
// delta total of 38 (20 + 18),
|
||||||
expectedAmt := lnwire.MilliSatoshi(5010198)
|
expectedAmt := lnwire.MilliSatoshi(5010198)
|
||||||
if route.TotalAmount != expectedAmt {
|
require.Equal(t, expectedAmt, route.TotalAmount)
|
||||||
t.Fatalf("wrong amount: got %v, expected %v",
|
|
||||||
route.TotalAmount, expectedAmt)
|
|
||||||
}
|
|
||||||
expectedDelta := uint32(20 + MinCLTVDelta)
|
expectedDelta := uint32(20 + MinCLTVDelta)
|
||||||
if route.TotalTimeLock != startingHeight+expectedDelta {
|
require.Equal(t, startingHeight+expectedDelta, route.TotalTimeLock)
|
||||||
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
||||||
route.TotalTimeLock, startingHeight+expectedDelta)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the hops of the route are properly crafted.
|
// Ensure that the hops of the route are properly crafted.
|
||||||
//
|
//
|
||||||
// After taking the fee, Bob should be forwarding the remainder which
|
// After taking the fee, Bob should be forwarding the remainder which
|
||||||
// is the exact payment to Bob.
|
// is the exact payment to Bob.
|
||||||
if route.Hops[0].AmtToForward != amt {
|
require.Equal(t, amt, route.Hops[0].AmtToForward)
|
||||||
t.Fatalf("wrong forward amount: got %v, expected %v",
|
|
||||||
route.Hops[0].AmtToForward, amt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We shouldn't pay any fee for the first, hop, but the fee for the
|
// We shouldn't pay any fee for the first, hop, but the fee for the
|
||||||
// second hop posted fee should be exactly:
|
// second hop posted fee should be exactly:
|
||||||
@ -2317,59 +2273,31 @@ func TestPathFindSpecExample(t *testing.T) {
|
|||||||
// hop, so we should get a fee of exactly:
|
// hop, so we should get a fee of exactly:
|
||||||
//
|
//
|
||||||
// * 200 + 4999999 * 2000 / 1000000 = 10199
|
// * 200 + 4999999 * 2000 / 1000000 = 10199
|
||||||
|
require.EqualValues(t, 10199, route.HopFee(0))
|
||||||
fee = route.HopFee(0)
|
|
||||||
if fee != 10199 {
|
|
||||||
t.Fatalf("wrong hop fee: got %v, expected %v", fee, 10199)
|
|
||||||
}
|
|
||||||
|
|
||||||
// While for the final hop, as there's no additional hop afterwards, we
|
// While for the final hop, as there's no additional hop afterwards, we
|
||||||
// pay no fee.
|
// pay no fee.
|
||||||
fee = route.HopFee(1)
|
require.Zero(t, route.HopFee(1))
|
||||||
if fee != 0 {
|
|
||||||
t.Fatalf("wrong hop fee: got %v, expected %v", fee, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The outgoing CLTV value itself should be the current height plus 30
|
// The outgoing CLTV value itself should be the current height plus 30
|
||||||
// to meet Carol's requirements.
|
// to meet Carol's requirements.
|
||||||
if route.Hops[0].OutgoingTimeLock !=
|
require.EqualValues(t, startingHeight+MinCLTVDelta,
|
||||||
startingHeight+MinCLTVDelta {
|
route.Hops[0].OutgoingTimeLock)
|
||||||
|
|
||||||
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
||||||
route.Hops[0].OutgoingTimeLock,
|
|
||||||
startingHeight+MinCLTVDelta)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For B -> C, we assert that the final hop also has the proper
|
// For B -> C, we assert that the final hop also has the proper
|
||||||
// parameters.
|
// parameters.
|
||||||
lastHop := route.Hops[1]
|
lastHop := route.Hops[1]
|
||||||
if lastHop.AmtToForward != amt {
|
require.EqualValues(t, amt, lastHop.AmtToForward)
|
||||||
t.Fatalf("wrong forward amount: got %v, expected %v",
|
require.EqualValues(t, startingHeight+MinCLTVDelta, lastHop.OutgoingTimeLock)
|
||||||
lastHop.AmtToForward, amt)
|
|
||||||
}
|
|
||||||
if lastHop.OutgoingTimeLock !=
|
|
||||||
startingHeight+MinCLTVDelta {
|
|
||||||
|
|
||||||
t.Fatalf("wrong total time lock: got %v, expecting %v",
|
|
||||||
lastHop.OutgoingTimeLock,
|
|
||||||
startingHeight+MinCLTVDelta)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertExpectedPath(t *testing.T, aliasMap map[string]route.Vertex,
|
func assertExpectedPath(t *testing.T, aliasMap map[string]route.Vertex,
|
||||||
path []*unifiedEdge, nodeAliases ...string) {
|
path []*unifiedEdge, nodeAliases ...string) {
|
||||||
|
|
||||||
if len(path) != len(nodeAliases) {
|
require.Len(t, path, len(nodeAliases))
|
||||||
t.Fatalf("number of hops=(%v) and number of aliases=(%v) do "+
|
|
||||||
"not match", len(path), len(nodeAliases))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, hop := range path {
|
for i, hop := range path {
|
||||||
if hop.policy.ToNodePubKey() != aliasMap[nodeAliases[i]] {
|
require.Equal(t, aliasMap[nodeAliases[i]], hop.policy.ToNodePubKey())
|
||||||
t.Fatalf("expected %v to be pos #%v in hop, instead "+
|
|
||||||
"%v was", nodeAliases[i], i,
|
|
||||||
hop.policy.ToNodePubKey())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2380,9 +2308,7 @@ func TestNewRouteFromEmptyHops(t *testing.T) {
|
|||||||
|
|
||||||
var source route.Vertex
|
var source route.Vertex
|
||||||
_, err := route.NewRouteFromHops(0, 0, source, []*route.Hop{})
|
_, err := route.NewRouteFromHops(0, 0, source, []*route.Hop{})
|
||||||
if err != route.ErrNoRouteHopsProvided {
|
require.ErrorIs(t, err, route.ErrNoRouteHopsProvided)
|
||||||
t.Fatalf("expected empty hops error: instead got: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// runRestrictOutgoingChannel asserts that a outgoing channel restriction is
|
// runRestrictOutgoingChannel asserts that a outgoing channel restriction is
|
||||||
@ -2425,11 +2351,6 @@ func runRestrictOutgoingChannel(t *testing.T, useCache bool) {
|
|||||||
|
|
||||||
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef")
|
||||||
|
|
||||||
const (
|
|
||||||
startingHeight = 100
|
|
||||||
finalHopCLTV = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
paymentAmt := lnwire.NewMSatFromSatoshis(100)
|
||||||
target := ctx.keyFromAlias("target")
|
target := ctx.keyFromAlias("target")
|
||||||
outgoingChannelID := uint64(chanSourceB1)
|
outgoingChannelID := uint64(chanSourceB1)
|
||||||
|
@ -912,7 +912,7 @@ func (p *paymentLifecycle) handleFailureMessage(rt *route.Route,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply channel update to the channel edge policy in our db.
|
// Apply channel update to the channel edge policy in our db.
|
||||||
if !p.router.applyChannelUpdate(update) {
|
if !p.router.cfg.ApplyChannelUpdate(update) {
|
||||||
log.Debugf("Invalid channel update received: node=%v",
|
log.Debugf("Invalid channel update received: node=%v",
|
||||||
errVertex)
|
errVertex)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/build"
|
"github.com/lightningnetwork/lnd/build"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||||
|
"github.com/lightningnetwork/lnd/graph"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
)
|
)
|
||||||
@ -412,7 +413,7 @@ func (p *paymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate,
|
|||||||
pubKey *btcec.PublicKey, policy *models.CachedEdgePolicy) bool {
|
pubKey *btcec.PublicKey, policy *models.CachedEdgePolicy) bool {
|
||||||
|
|
||||||
// Validate the message signature.
|
// Validate the message signature.
|
||||||
if err := VerifyChannelUpdateSignature(msg, pubKey); err != nil {
|
if err := graph.VerifyChannelUpdateSignature(msg, pubKey); err != nil {
|
||||||
log.Errorf(
|
log.Errorf(
|
||||||
"Unable to validate channel update signature: %v", err,
|
"Unable to validate channel update signature: %v", err,
|
||||||
)
|
)
|
||||||
|
1746
routing/router.go
1746
routing/router.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
11
rpcserver.go
11
rpcserver.go
@ -49,6 +49,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/feature"
|
"github.com/lightningnetwork/lnd/feature"
|
||||||
"github.com/lightningnetwork/lnd/fn"
|
"github.com/lightningnetwork/lnd/fn"
|
||||||
"github.com/lightningnetwork/lnd/funding"
|
"github.com/lightningnetwork/lnd/funding"
|
||||||
|
"github.com/lightningnetwork/lnd/graph"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
@ -3075,7 +3076,7 @@ func (r *rpcServer) GetInfo(_ context.Context,
|
|||||||
// date, we add the router's state to it. So the flag will only toggle
|
// date, we add the router's state to it. So the flag will only toggle
|
||||||
// to true once the router was also able to catch up.
|
// to true once the router was also able to catch up.
|
||||||
if !r.cfg.Routing.AssumeChannelValid {
|
if !r.cfg.Routing.AssumeChannelValid {
|
||||||
routerHeight := r.server.chanRouter.SyncedHeight()
|
routerHeight := r.server.graphBuilder.SyncedHeight()
|
||||||
isSynced = isSynced && uint32(bestHeight) == routerHeight
|
isSynced = isSynced && uint32(bestHeight) == routerHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3118,7 +3119,7 @@ func (r *rpcServer) GetInfo(_ context.Context,
|
|||||||
// TODO(roasbeef): add synced height n stuff
|
// TODO(roasbeef): add synced height n stuff
|
||||||
|
|
||||||
isTestNet := chainreg.IsTestnet(&r.cfg.ActiveNetParams)
|
isTestNet := chainreg.IsTestnet(&r.cfg.ActiveNetParams)
|
||||||
nodeColor := routing.EncodeHexColor(nodeAnn.RGBColor)
|
nodeColor := graph.EncodeHexColor(nodeAnn.RGBColor)
|
||||||
version := build.Version() + " commit=" + build.Commit
|
version := build.Version() + " commit=" + build.Commit
|
||||||
|
|
||||||
return &lnrpc.GetInfoResponse{
|
return &lnrpc.GetInfoResponse{
|
||||||
@ -6418,7 +6419,7 @@ func marshalNode(node *channeldb.LightningNode) *lnrpc.LightningNode {
|
|||||||
PubKey: hex.EncodeToString(node.PubKeyBytes[:]),
|
PubKey: hex.EncodeToString(node.PubKeyBytes[:]),
|
||||||
Addresses: nodeAddrs,
|
Addresses: nodeAddrs,
|
||||||
Alias: node.Alias,
|
Alias: node.Alias,
|
||||||
Color: routing.EncodeHexColor(node.Color),
|
Color: graph.EncodeHexColor(node.Color),
|
||||||
Features: features,
|
Features: features,
|
||||||
CustomRecords: customRecords,
|
CustomRecords: customRecords,
|
||||||
}
|
}
|
||||||
@ -6613,7 +6614,7 @@ func (r *rpcServer) SubscribeChannelGraph(req *lnrpc.GraphTopologySubscription,
|
|||||||
|
|
||||||
// First, we start by subscribing to a new intent to receive
|
// First, we start by subscribing to a new intent to receive
|
||||||
// notifications from the channel router.
|
// notifications from the channel router.
|
||||||
client, err := r.server.chanRouter.SubscribeTopology()
|
client, err := r.server.graphBuilder.SubscribeTopology()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -6665,7 +6666,7 @@ func (r *rpcServer) SubscribeChannelGraph(req *lnrpc.GraphTopologySubscription,
|
|||||||
// marshallTopologyChange performs a mapping from the topology change struct
|
// marshallTopologyChange performs a mapping from the topology change struct
|
||||||
// returned by the router to the form of notifications expected by the current
|
// returned by the router to the form of notifications expected by the current
|
||||||
// gRPC service.
|
// gRPC service.
|
||||||
func marshallTopologyChange(topChange *routing.TopologyChange) *lnrpc.GraphTopologyUpdate {
|
func marshallTopologyChange(topChange *graph.TopologyChange) *lnrpc.GraphTopologyUpdate {
|
||||||
|
|
||||||
// encodeKey is a simple helper function that converts a live public
|
// encodeKey is a simple helper function that converts a live public
|
||||||
// key into a hex-encoded version of the compressed serialization for
|
// key into a hex-encoded version of the compressed serialization for
|
||||||
|
34
server.go
34
server.go
@ -342,7 +342,7 @@ type server struct {
|
|||||||
// updatePersistentPeerAddrs subscribes to topology changes and stores
|
// updatePersistentPeerAddrs subscribes to topology changes and stores
|
||||||
// advertised addresses for any NodeAnnouncements from our persisted peers.
|
// advertised addresses for any NodeAnnouncements from our persisted peers.
|
||||||
func (s *server) updatePersistentPeerAddrs() error {
|
func (s *server) updatePersistentPeerAddrs() error {
|
||||||
graphSub, err := s.chanRouter.SubscribeTopology()
|
graphSub, err := s.graphBuilder.SubscribeTopology()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -976,7 +976,19 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
strictPruning := cfg.Bitcoin.Node == "neutrino" ||
|
strictPruning := cfg.Bitcoin.Node == "neutrino" ||
|
||||||
cfg.Routing.StrictZombiePruning
|
cfg.Routing.StrictZombiePruning
|
||||||
|
|
||||||
s.graphBuilder, err = graph.NewBuilder(&graph.Config{})
|
s.graphBuilder, err = graph.NewBuilder(&graph.Config{
|
||||||
|
SelfNode: selfNode.PubKeyBytes,
|
||||||
|
Graph: chanGraph,
|
||||||
|
Chain: cc.ChainIO,
|
||||||
|
ChainView: cc.ChainView,
|
||||||
|
Notifier: cc.ChainNotifier,
|
||||||
|
ChannelPruneExpiry: graph.DefaultChannelPruneExpiry,
|
||||||
|
GraphPruneInterval: time.Hour,
|
||||||
|
FirstTimePruneDelay: graph.DefaultFirstTimePruneDelay,
|
||||||
|
AssumeChannelValid: cfg.Routing.AssumeChannelValid,
|
||||||
|
StrictZombiePruning: strictPruning,
|
||||||
|
IsAlias: aliasmgr.IsAlias,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't create graph builder: %w", err)
|
return nil, fmt.Errorf("can't create graph builder: %w", err)
|
||||||
}
|
}
|
||||||
@ -984,24 +996,16 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
s.chanRouter, err = routing.New(routing.Config{
|
s.chanRouter, err = routing.New(routing.Config{
|
||||||
SelfNode: selfNode.PubKeyBytes,
|
SelfNode: selfNode.PubKeyBytes,
|
||||||
RoutingGraph: graphsession.NewRoutingGraph(chanGraph),
|
RoutingGraph: graphsession.NewRoutingGraph(chanGraph),
|
||||||
Graph: chanGraph,
|
|
||||||
Chain: cc.ChainIO,
|
Chain: cc.ChainIO,
|
||||||
ChainView: cc.ChainView,
|
|
||||||
Notifier: cc.ChainNotifier,
|
|
||||||
Payer: s.htlcSwitch,
|
Payer: s.htlcSwitch,
|
||||||
Control: s.controlTower,
|
Control: s.controlTower,
|
||||||
MissionControl: s.missionControl,
|
MissionControl: s.missionControl,
|
||||||
SessionSource: paymentSessionSource,
|
SessionSource: paymentSessionSource,
|
||||||
ChannelPruneExpiry: routing.DefaultChannelPruneExpiry,
|
|
||||||
GraphPruneInterval: time.Hour,
|
|
||||||
FirstTimePruneDelay: routing.DefaultFirstTimePruneDelay,
|
|
||||||
GetLink: s.htlcSwitch.GetLinkByShortID,
|
GetLink: s.htlcSwitch.GetLinkByShortID,
|
||||||
AssumeChannelValid: cfg.Routing.AssumeChannelValid,
|
|
||||||
NextPaymentID: sequencer.NextID,
|
NextPaymentID: sequencer.NextID,
|
||||||
PathFindingConfig: pathFindingConfig,
|
PathFindingConfig: pathFindingConfig,
|
||||||
Clock: clock.NewDefaultClock(),
|
Clock: clock.NewDefaultClock(),
|
||||||
StrictZombiePruning: strictPruning,
|
ApplyChannelUpdate: s.graphBuilder.ApplyChannelUpdate,
|
||||||
IsAlias: aliasmgr.IsAlias,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't create router: %w", err)
|
return nil, fmt.Errorf("can't create router: %w", err)
|
||||||
@ -1018,7 +1022,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.authGossiper = discovery.New(discovery.Config{
|
s.authGossiper = discovery.New(discovery.Config{
|
||||||
Router: s.chanRouter,
|
Router: s.graphBuilder,
|
||||||
Notifier: s.cc.ChainNotifier,
|
Notifier: s.cc.ChainNotifier,
|
||||||
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
|
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
|
||||||
Broadcast: s.BroadcastMessage,
|
Broadcast: s.BroadcastMessage,
|
||||||
@ -1053,11 +1057,11 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
FindBaseByAlias: s.aliasMgr.FindBaseSCID,
|
FindBaseByAlias: s.aliasMgr.FindBaseSCID,
|
||||||
GetAlias: s.aliasMgr.GetPeerAlias,
|
GetAlias: s.aliasMgr.GetPeerAlias,
|
||||||
FindChannel: s.findChannel,
|
FindChannel: s.findChannel,
|
||||||
IsStillZombieChannel: s.chanRouter.IsZombieChannel,
|
IsStillZombieChannel: s.graphBuilder.IsZombieChannel,
|
||||||
}, nodeKeyDesc)
|
}, nodeKeyDesc)
|
||||||
|
|
||||||
s.localChanMgr = &localchans.Manager{
|
s.localChanMgr = &localchans.Manager{
|
||||||
ForAllOutgoingChannels: s.chanRouter.ForAllOutgoingChannels,
|
ForAllOutgoingChannels: s.graphBuilder.ForAllOutgoingChannels,
|
||||||
PropagateChanPolicyUpdate: s.authGossiper.PropagateChanPolicyUpdate,
|
PropagateChanPolicyUpdate: s.authGossiper.PropagateChanPolicyUpdate,
|
||||||
UpdateForwardingPolicies: s.htlcSwitch.UpdateForwardingPolicies,
|
UpdateForwardingPolicies: s.htlcSwitch.UpdateForwardingPolicies,
|
||||||
FetchChannel: s.chanStateDB.FetchChannel,
|
FetchChannel: s.chanStateDB.FetchChannel,
|
||||||
@ -4667,7 +4671,7 @@ func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) (
|
|||||||
|
|
||||||
ourPubKey := s.identityECDH.PubKey().SerializeCompressed()
|
ourPubKey := s.identityECDH.PubKey().SerializeCompressed()
|
||||||
return func(cid lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
|
return func(cid lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
|
||||||
info, edge1, edge2, err := s.chanRouter.GetChannelByID(cid)
|
info, edge1, edge2, err := s.graphBuilder.GetChannelByID(cid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user