multi: add models.Node V1 constructor
Add a version field to models.Node and a V1 constructor for it.
This commit is contained in:
1 parent
8f205e2d1c
commit
80e70096cb
18 files changed
+443
-340
No files matched your search
@@ -417,20 +417,20 @@ func (d *testDBGraph) addRandChannel(node1, node2 *btcec.PublicKey,
|
||||
case errors.Is(err, graphdb.ErrGraphNodeNotFound):
|
||||
fallthrough
|
||||
case errors.Is(err, graphdb.ErrGraphNotFound):
|
||||
graphNode := &models.Node{
|
||||
Addresses: []net.Addr{&net.TCPAddr{
|
||||
IP: bytes.Repeat(
|
||||
[]byte("a"), 16,
|
||||
),
|
||||
}},
|
||||
Features: lnwire.NewFeatureVector(
|
||||
nil, lnwire.Features,
|
||||
),
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
}
|
||||
copy(
|
||||
graphNode.PubKeyBytes[:],
|
||||
pub.SerializeCompressed(),
|
||||
//nolint:ll
|
||||
graphNode := models.NewV1Node(
|
||||
route.NewVertex(pub),
|
||||
&models.NodeV1Fields{
|
||||
Addresses: []net.Addr{&net.TCPAddr{
|
||||
IP: bytes.Repeat(
|
||||
[]byte("a"), 16,
|
||||
),
|
||||
}},
|
||||
Features: lnwire.NewFeatureVector(
|
||||
nil, lnwire.Features,
|
||||
).RawFeatureVector,
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
},
|
||||
)
|
||||
err := d.db.AddNode(
|
||||
context.Background(), graphNode,
|
||||
@@ -449,18 +449,18 @@ func (d *testDBGraph) addRandChannel(node1, node2 *btcec.PublicKey,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbNode := &models.Node{
|
||||
Addresses: []net.Addr{
|
||||
&net.TCPAddr{
|
||||
|
||||
dbNode := models.NewV1Node(
|
||||
route.NewVertex(nodeKey), &models.NodeV1Fields{
|
||||
Addresses: []net.Addr{&net.TCPAddr{
|
||||
IP: bytes.Repeat([]byte("a"), 16),
|
||||
},
|
||||
}},
|
||||
Features: lnwire.NewFeatureVector(
|
||||
nil, lnwire.Features,
|
||||
).RawFeatureVector,
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
},
|
||||
Features: lnwire.NewFeatureVector(
|
||||
nil, lnwire.Features,
|
||||
),
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
}
|
||||
copy(dbNode.PubKeyBytes[:], nodeKey.SerializeCompressed())
|
||||
)
|
||||
if err := d.db.AddNode(
|
||||
context.Background(), dbNode,
|
||||
); err != nil {
|
||||
@@ -549,18 +549,19 @@ func (d *testDBGraph) addRandNode() (*btcec.PublicKey, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbNode := &models.Node{
|
||||
Addresses: []net.Addr{
|
||||
&net.TCPAddr{
|
||||
IP: bytes.Repeat([]byte("a"), 16),
|
||||
dbNode := models.NewV1Node(
|
||||
route.NewVertex(nodeKey), &models.NodeV1Fields{
|
||||
Addresses: []net.Addr{
|
||||
&net.TCPAddr{
|
||||
IP: bytes.Repeat([]byte("a"), 16),
|
||||
},
|
||||
},
|
||||
Features: lnwire.NewFeatureVector(
|
||||
nil, lnwire.Features,
|
||||
).RawFeatureVector,
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
},
|
||||
Features: lnwire.NewFeatureVector(
|
||||
nil, lnwire.Features,
|
||||
),
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
}
|
||||
copy(dbNode.PubKeyBytes[:], nodeKey.SerializeCompressed())
|
||||
)
|
||||
err = d.db.AddNode(context.Background(), dbNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+12
-9
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/shachain"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -811,15 +812,17 @@ func createNode(priv *btcec.PrivateKey) *models.Node {
|
||||
updateTime := rand.Int63()
|
||||
|
||||
pub := priv.PubKey().SerializeCompressed()
|
||||
n := &models.Node{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: time.Unix(updateTime, 0),
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek" + string(pub),
|
||||
Features: testFeatures,
|
||||
Addresses: testAddrs,
|
||||
}
|
||||
copy(n.PubKeyBytes[:], priv.PubKey().SerializeCompressed())
|
||||
n := models.NewV1Node(
|
||||
route.NewVertex(priv.PubKey()),
|
||||
&models.NodeV1Fields{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: time.Unix(updateTime, 0),
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek" + string(pub),
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
Addresses: testAddrs,
|
||||
},
|
||||
)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
+35
-31
@@ -97,15 +97,16 @@ func TestIgnoreNodeAnnouncement(t *testing.T) {
|
||||
ctx := createTestCtxFromFile(t, startingBlockHeight, basicGraphFilePath)
|
||||
|
||||
pub := priv1.PubKey()
|
||||
node := &models.Node{
|
||||
LastUpdate: time.Unix(123, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "node11",
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures,
|
||||
}
|
||||
copy(node.PubKeyBytes[:], pub.SerializeCompressed())
|
||||
node := models.NewV1Node(
|
||||
route.NewVertex(pub), &models.NodeV1Fields{
|
||||
Addresses: testAddrs,
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
LastUpdate: time.Unix(123, 0),
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "node11",
|
||||
},
|
||||
)
|
||||
|
||||
err := ctx.builder.AddNode(t.Context(), node)
|
||||
if !IsError(err, ErrIgnored) {
|
||||
@@ -1083,15 +1084,16 @@ func TestIsStaleNode(t *testing.T) {
|
||||
|
||||
// With the node stub in the database, we'll add the fully node
|
||||
// announcement to the database.
|
||||
n1 := &models.Node{
|
||||
LastUpdate: updateTimeStamp,
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "node11",
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures,
|
||||
}
|
||||
copy(n1.PubKeyBytes[:], priv1.PubKey().SerializeCompressed())
|
||||
n1 := models.NewV1Node(
|
||||
route.NewVertex(priv1.PubKey()), &models.NodeV1Fields{
|
||||
LastUpdate: updateTimeStamp,
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "node11",
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
},
|
||||
)
|
||||
if err := ctx.builder.AddNode(t.Context(), n1); err != nil {
|
||||
t.Fatalf("could not add node: %v", err)
|
||||
}
|
||||
@@ -1399,14 +1401,16 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dbNode := &models.Node{
|
||||
pubKey, err := route.NewVertexFromBytes(pubBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
dbNode := models.NewV1Node(pubKey, &models.NodeV1Fields{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: testTime,
|
||||
Addresses: testAddrs,
|
||||
Alias: node.Alias,
|
||||
Features: testFeatures,
|
||||
}
|
||||
copy(dbNode.PubKeyBytes[:], pubBytes)
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
})
|
||||
|
||||
// We require all aliases within the graph to be unique for our
|
||||
// tests.
|
||||
@@ -1784,15 +1788,15 @@ func createTestGraphFromChannels(t *testing.T, useCache bool,
|
||||
features = lnwire.EmptyFeatureVector()
|
||||
}
|
||||
|
||||
dbNode := &models.Node{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: testTime,
|
||||
Addresses: testAddrs,
|
||||
Alias: alias,
|
||||
Features: features,
|
||||
}
|
||||
|
||||
copy(dbNode.PubKeyBytes[:], pubKey.SerializeCompressed())
|
||||
dbNode := models.NewV1Node(
|
||||
route.NewVertex(pubKey), &models.NodeV1Fields{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: testTime,
|
||||
Addresses: testAddrs,
|
||||
Alias: alias,
|
||||
Features: features.RawFeatureVector,
|
||||
},
|
||||
)
|
||||
|
||||
privKeyMap[alias] = privKey
|
||||
|
||||
|
||||
+31
-37
@@ -70,18 +70,18 @@ var (
|
||||
)
|
||||
|
||||
func createNode(priv *btcec.PrivateKey) *models.Node {
|
||||
pub := priv.PubKey().SerializeCompressed()
|
||||
n := &models.Node{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: nextUpdateTime(),
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek" + hex.EncodeToString(pub),
|
||||
Features: testFeatures,
|
||||
Addresses: testAddrs,
|
||||
}
|
||||
copy(n.PubKeyBytes[:], priv.PubKey().SerializeCompressed())
|
||||
pubKey := route.NewVertex(priv.PubKey())
|
||||
|
||||
return n
|
||||
return models.NewV1Node(
|
||||
pubKey, &models.NodeV1Fields{
|
||||
LastUpdate: nextUpdateTime(),
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek" + hex.EncodeToString(pubKey[:]),
|
||||
Addresses: testAddrs,
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func createTestVertex(t testing.TB) *models.Node {
|
||||
@@ -105,16 +105,18 @@ func TestNodeInsertionAndDeletion(t *testing.T) {
|
||||
timeStamp := int64(1232342)
|
||||
nodeWithAddrs := func(addrs []net.Addr) *models.Node {
|
||||
timeStamp++
|
||||
return &models.Node{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: time.Unix(timeStamp, 0),
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek",
|
||||
Features: testFeatures,
|
||||
Addresses: addrs,
|
||||
ExtraOpaqueData: []byte{1, 1, 1, 2, 2, 2, 2},
|
||||
PubKeyBytes: testPub,
|
||||
}
|
||||
|
||||
return models.NewV1Node(
|
||||
testPub, &models.NodeV1Fields{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: time.Unix(timeStamp, 0),
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek",
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
Addresses: addrs,
|
||||
ExtraOpaqueData: []byte{1, 1, 1, 2, 2, 2, 2},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// First, insert the node into the graph DB. This should succeed
|
||||
@@ -313,11 +315,7 @@ func TestPartialNode(t *testing.T) {
|
||||
|
||||
// The two nodes should match exactly! (with default values for
|
||||
// LastUpdate and db set to satisfy compareNodes())
|
||||
expectedNode1 := &models.Node{
|
||||
LastUpdate: time.Unix(0, 0),
|
||||
PubKeyBytes: pubKey1,
|
||||
Features: lnwire.EmptyFeatureVector(),
|
||||
}
|
||||
expectedNode1 := models.NewV1ShellNode(pubKey1)
|
||||
compareNodes(t, expectedNode1, dbNode1)
|
||||
|
||||
_, exists, err = graph.HasNode(ctx, dbNode2.PubKeyBytes)
|
||||
@@ -326,11 +324,7 @@ func TestPartialNode(t *testing.T) {
|
||||
|
||||
// The two nodes should match exactly! (with default values for
|
||||
// LastUpdate and db set to satisfy compareNodes())
|
||||
expectedNode2 := &models.Node{
|
||||
LastUpdate: time.Unix(0, 0),
|
||||
PubKeyBytes: pubKey2,
|
||||
Features: lnwire.EmptyFeatureVector(),
|
||||
}
|
||||
expectedNode2 := models.NewV1ShellNode(pubKey2)
|
||||
compareNodes(t, expectedNode2, dbNode2)
|
||||
|
||||
// Next, delete the node from the graph, this should purge all data
|
||||
@@ -365,7 +359,7 @@ func TestAliasLookup(t *testing.T) {
|
||||
require.NoError(t, err, "unable to generate pubkey")
|
||||
dbAlias, err := graph.LookupAlias(ctx, nodePub)
|
||||
require.NoError(t, err, "unable to find alias")
|
||||
require.Equal(t, testNode.Alias, dbAlias)
|
||||
require.Equal(t, testNode.Alias.UnwrapOr(""), dbAlias)
|
||||
|
||||
// Ensure that looking up a non-existent alias results in an error.
|
||||
node := createTestVertex(t)
|
||||
@@ -1600,7 +1594,7 @@ func fillTestGraph(t testing.TB, graph *ChannelGraph, numNodes,
|
||||
node := createTestVertex(t)
|
||||
|
||||
nodes[i] = node
|
||||
nodeIndex[node.Alias] = struct{}{}
|
||||
nodeIndex[node.Alias.UnwrapOr("")] = struct{}{}
|
||||
}
|
||||
|
||||
// Add each of the nodes into the graph, they should be inserted
|
||||
@@ -1612,7 +1606,7 @@ func fillTestGraph(t testing.TB, graph *ChannelGraph, numNodes,
|
||||
// Iterate over each node as returned by the graph, if all nodes are
|
||||
// reached, then the map created above should be empty.
|
||||
err := graph.ForEachNode(ctx, func(n *models.Node) error {
|
||||
delete(nodeIndex, n.Alias)
|
||||
delete(nodeIndex, n.Alias.UnwrapOr(""))
|
||||
return nil
|
||||
}, func() {})
|
||||
require.NoError(t, err)
|
||||
@@ -2289,7 +2283,7 @@ func TestNodeUpdatesInHorizon(t *testing.T) {
|
||||
require.Len(t, resp, len(queryCase.resp))
|
||||
|
||||
for i := 0; i < len(resp); i++ {
|
||||
compareNodes(t, &queryCase.resp[i], &resp[i])
|
||||
compareNodes(t, &queryCase.resp[i], resp[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2487,7 +2481,7 @@ func TestNodeUpdatesInHorizonEarlyTermination(t *testing.T) {
|
||||
)
|
||||
|
||||
// Collect only up to stopAt nodes, breaking afterwards.
|
||||
var collected []models.Node
|
||||
var collected []*models.Node
|
||||
count := 0
|
||||
for node := range iter {
|
||||
if count >= stopAt {
|
||||
@@ -3824,7 +3818,7 @@ func TestNodePruningUpdateIndexDeletion(t *testing.T) {
|
||||
t.Fatalf("should have 1 nodes instead have: %v",
|
||||
len(nodesInHorizon))
|
||||
}
|
||||
compareNodes(t, node1, &nodesInHorizon[0])
|
||||
compareNodes(t, node1, nodesInHorizon[0])
|
||||
|
||||
// We'll now delete the node from the graph, this should result in it
|
||||
// being removed from the update index as well.
|
||||
|
||||
@@ -111,7 +111,7 @@ type V1Store interface { //nolint:interfacebloat
|
||||
// by two nodes to quickly determine if they have the same set of up to
|
||||
// date node announcements.
|
||||
NodeUpdatesInHorizon(startTime, endTime time.Time,
|
||||
opts ...IteratorOption) iter.Seq2[models.Node, error]
|
||||
opts ...IteratorOption) iter.Seq2[*models.Node, error]
|
||||
|
||||
// FetchNode attempts to look up a target node by its identity
|
||||
// public key. If the node isn't found in the database, then
|
||||
|
||||
+57
-57
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"io"
|
||||
"iter"
|
||||
"math"
|
||||
@@ -848,7 +849,7 @@ func forEachNode(db kvdb.Backend,
|
||||
|
||||
// Execute the callback, the transaction will abort if
|
||||
// this returns an error.
|
||||
return cb(tx, &node)
|
||||
return cb(tx, node)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -945,12 +946,7 @@ func sourceNodeWithTx(nodes kvdb.RBucket) (*models.Node, error) {
|
||||
|
||||
// With the pubKey of the source node retrieved, we're able to
|
||||
// fetch the full node information.
|
||||
node, err := fetchLightningNode(nodes, selfPub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &node, nil
|
||||
return fetchLightningNode(nodes, selfPub)
|
||||
}
|
||||
|
||||
// SetSourceNode sets the source node within the graph database. The source
|
||||
@@ -1205,10 +1201,9 @@ func (c *KVStore) addChannelEdge(tx kvdb.RwTx,
|
||||
_, node1Err := fetchLightningNode(nodes, edge.NodeKey1Bytes[:])
|
||||
switch {
|
||||
case errors.Is(node1Err, ErrGraphNodeNotFound):
|
||||
node1Shell := models.Node{
|
||||
PubKeyBytes: edge.NodeKey1Bytes,
|
||||
}
|
||||
err := addLightningNode(tx, &node1Shell)
|
||||
err := addLightningNode(
|
||||
tx, models.NewV1ShellNode(edge.NodeKey1Bytes),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create shell node "+
|
||||
"for: %x: %w", edge.NodeKey1Bytes, err)
|
||||
@@ -1220,10 +1215,9 @@ func (c *KVStore) addChannelEdge(tx kvdb.RwTx,
|
||||
_, node2Err := fetchLightningNode(nodes, edge.NodeKey2Bytes[:])
|
||||
switch {
|
||||
case errors.Is(node2Err, ErrGraphNodeNotFound):
|
||||
node2Shell := models.Node{
|
||||
PubKeyBytes: edge.NodeKey2Bytes,
|
||||
}
|
||||
err := addLightningNode(tx, &node2Shell)
|
||||
err := addLightningNode(
|
||||
tx, models.NewV1ShellNode(edge.NodeKey2Bytes),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create shell node "+
|
||||
"for: %x: %w", edge.NodeKey2Bytes, err)
|
||||
@@ -2247,8 +2241,8 @@ func (c *KVStore) fetchNextChanUpdateBatch(
|
||||
Info: &edgeInfo,
|
||||
Policy1: edge1,
|
||||
Policy2: edge2,
|
||||
Node1: &node1,
|
||||
Node2: &node2,
|
||||
Node1: node1,
|
||||
Node2: node2,
|
||||
}
|
||||
|
||||
state.edgesSeen[chanIDInt] = struct{}{}
|
||||
@@ -2394,10 +2388,10 @@ func newNodeUpdatesIterator(batchSize int, startTime, endTime time.Time,
|
||||
// fetchNextNodeBatch fetches the next batch of node announcements using the
|
||||
// iterator state.
|
||||
func (c *KVStore) fetchNextNodeBatch(
|
||||
state *nodeUpdatesIterator) ([]models.Node, bool, error) {
|
||||
state *nodeUpdatesIterator) ([]*models.Node, bool, error) {
|
||||
|
||||
var (
|
||||
nodeBatch []models.Node
|
||||
nodeBatch []*models.Node
|
||||
hasMore bool
|
||||
)
|
||||
|
||||
@@ -2536,14 +2530,14 @@ func (c *KVStore) fetchNextNodeBatch(
|
||||
// update timestamp within the passed range.
|
||||
func (c *KVStore) NodeUpdatesInHorizon(startTime,
|
||||
endTime time.Time,
|
||||
opts ...IteratorOption) iter.Seq2[models.Node, error] {
|
||||
opts ...IteratorOption) iter.Seq2[*models.Node, error] {
|
||||
|
||||
cfg := defaultIteratorConfig()
|
||||
for _, opt := range opts {
|
||||
opt(cfg)
|
||||
}
|
||||
|
||||
return func(yield func(models.Node, error) bool) {
|
||||
return func(yield func(*models.Node, error) bool) {
|
||||
// Initialize iterator state.
|
||||
state := newNodeUpdatesIterator(
|
||||
cfg.nodeUpdateIterBatchSize,
|
||||
@@ -2557,7 +2551,7 @@ func (c *KVStore) NodeUpdatesInHorizon(startTime,
|
||||
log.Errorf("unable to read node updates in "+
|
||||
"horizon: %v", err)
|
||||
|
||||
yield(models.Node{}, err)
|
||||
yield(&models.Node{}, err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -2945,8 +2939,8 @@ func (c *KVStore) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) (
|
||||
Info: &edgeInfo,
|
||||
Policy1: edge1,
|
||||
Policy2: edge2,
|
||||
Node1: &node1,
|
||||
Node2: &node2,
|
||||
Node1: node1,
|
||||
Node2: node2,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3411,7 +3405,7 @@ func (c *KVStore) fetchLightningNode(tx kvdb.RTx,
|
||||
return err
|
||||
}
|
||||
|
||||
node = &n
|
||||
node = n
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -3694,7 +3688,7 @@ func (c *KVStore) fetchOtherNode(tx kvdb.RTx,
|
||||
return err
|
||||
}
|
||||
|
||||
targetNode = &node
|
||||
targetNode = node
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -4383,17 +4377,20 @@ func putLightningNode(nodeBucket, aliasBucket, updateIndex kvdb.RwBucket,
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(&b, byteOrder, node.Color.R); err != nil {
|
||||
nodeColor := node.Color.UnwrapOr(color.RGBA{})
|
||||
|
||||
if err := binary.Write(&b, byteOrder, nodeColor.R); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(&b, byteOrder, node.Color.G); err != nil {
|
||||
if err := binary.Write(&b, byteOrder, nodeColor.G); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(&b, byteOrder, node.Color.B); err != nil {
|
||||
if err := binary.Write(&b, byteOrder, nodeColor.B); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := wire.WriteVarString(&b, 0, node.Alias); err != nil {
|
||||
err = wire.WriteVarString(&b, 0, node.Alias.UnwrapOr(""))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4432,7 +4429,8 @@ func putLightningNode(nodeBucket, aliasBucket, updateIndex kvdb.RwBucket,
|
||||
return err
|
||||
}
|
||||
|
||||
if err := aliasBucket.Put(nodePub, []byte(node.Alias)); err != nil {
|
||||
err = aliasBucket.Put(nodePub, []byte(node.Alias.UnwrapOr("")))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4466,11 +4464,11 @@ func putLightningNode(nodeBucket, aliasBucket, updateIndex kvdb.RwBucket,
|
||||
}
|
||||
|
||||
func fetchLightningNode(nodeBucket kvdb.RBucket,
|
||||
nodePub []byte) (models.Node, error) {
|
||||
nodePub []byte) (*models.Node, error) {
|
||||
|
||||
nodeBytes := nodeBucket.Get(nodePub)
|
||||
if nodeBytes == nil {
|
||||
return models.Node{}, ErrGraphNodeNotFound
|
||||
return nil, ErrGraphNodeNotFound
|
||||
}
|
||||
|
||||
nodeReader := bytes.NewReader(nodeBytes)
|
||||
@@ -4533,30 +4531,29 @@ func deserializeLightningNodeCacheable(r io.Reader) (route.Vertex,
|
||||
return pubKey, features, nil
|
||||
}
|
||||
|
||||
func deserializeLightningNode(r io.Reader) (models.Node, error) {
|
||||
func deserializeLightningNode(r io.Reader) (*models.Node, error) {
|
||||
var (
|
||||
node models.Node
|
||||
scratch [8]byte
|
||||
err error
|
||||
pubKey [33]byte
|
||||
)
|
||||
|
||||
// Always populate a feature vector, even if we don't have a node
|
||||
// announcement and short circuit below.
|
||||
node.Features = lnwire.EmptyFeatureVector()
|
||||
|
||||
if _, err := r.Read(scratch[:]); err != nil {
|
||||
return models.Node{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unix := int64(byteOrder.Uint64(scratch[:]))
|
||||
node.LastUpdate = time.Unix(unix, 0)
|
||||
lastUpdate := time.Unix(unix, 0)
|
||||
|
||||
if _, err := io.ReadFull(r, node.PubKeyBytes[:]); err != nil {
|
||||
return models.Node{}, err
|
||||
if _, err := io.ReadFull(r, pubKey[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node := models.NewV1ShellNode(pubKey)
|
||||
node.LastUpdate = lastUpdate
|
||||
|
||||
if _, err := r.Read(scratch[:2]); err != nil {
|
||||
return models.Node{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasNodeAnn := byteOrder.Uint16(scratch[:2])
|
||||
@@ -4568,28 +4565,31 @@ func deserializeLightningNode(r io.Reader) (models.Node, error) {
|
||||
|
||||
// We did get a node announcement for this node, so we'll have the rest
|
||||
// of the data available.
|
||||
if err := binary.Read(r, byteOrder, &node.Color.R); err != nil {
|
||||
return models.Node{}, err
|
||||
var nodeColor color.RGBA
|
||||
if err := binary.Read(r, byteOrder, &nodeColor.R); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := binary.Read(r, byteOrder, &node.Color.G); err != nil {
|
||||
return models.Node{}, err
|
||||
if err := binary.Read(r, byteOrder, &nodeColor.G); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := binary.Read(r, byteOrder, &node.Color.B); err != nil {
|
||||
return models.Node{}, err
|
||||
if err := binary.Read(r, byteOrder, &nodeColor.B); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node.Color = fn.Some(nodeColor)
|
||||
|
||||
node.Alias, err = wire.ReadVarString(r, 0)
|
||||
alias, err := wire.ReadVarString(r, 0)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
return nil, err
|
||||
}
|
||||
node.Alias = fn.Some(alias)
|
||||
|
||||
err = node.Features.Decode(r)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := r.Read(scratch[:2]); err != nil {
|
||||
return models.Node{}, err
|
||||
return nil, err
|
||||
}
|
||||
numAddresses := int(byteOrder.Uint16(scratch[:2]))
|
||||
|
||||
@@ -4597,7 +4597,7 @@ func deserializeLightningNode(r io.Reader) (models.Node, error) {
|
||||
for i := 0; i < numAddresses; i++ {
|
||||
address, err := DeserializeAddr(r)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
return nil, err
|
||||
}
|
||||
addresses = append(addresses, address)
|
||||
}
|
||||
@@ -4605,7 +4605,7 @@ func deserializeLightningNode(r io.Reader) (models.Node, error) {
|
||||
|
||||
node.AuthSigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig")
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We'll try and see if there are any opaque bytes left, if not, then
|
||||
@@ -4617,7 +4617,7 @@ func deserializeLightningNode(r io.Reader) (models.Node, error) {
|
||||
case errors.Is(err, io.ErrUnexpectedEOF):
|
||||
case errors.Is(err, io.EOF):
|
||||
case err != nil:
|
||||
return models.Node{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(extraBytes) > 0 {
|
||||
|
||||
+87
-15
@@ -7,7 +7,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
)
|
||||
|
||||
// Node represents an individual vertex/node within the channel graph.
|
||||
@@ -15,6 +17,9 @@ import (
|
||||
// from it. As the graph is directed, a node will also have an incoming edge
|
||||
// attached to it for each outgoing edge.
|
||||
type Node struct {
|
||||
// Version is the gossip version that this node was advertised on.
|
||||
Version lnwire.GossipVersion
|
||||
|
||||
// PubKeyBytes is the raw bytes of the public key of the target node.
|
||||
PubKeyBytes [33]byte
|
||||
pubKey *btcec.PublicKey
|
||||
@@ -27,11 +32,11 @@ type Node struct {
|
||||
Addresses []net.Addr
|
||||
|
||||
// Color is the selected color for the node.
|
||||
Color color.RGBA
|
||||
Color fn.Option[color.RGBA]
|
||||
|
||||
// Alias is a nick-name for the node. The alias can be used to confirm
|
||||
// a node's identity or to serve as a short ID for an address book.
|
||||
Alias string
|
||||
Alias fn.Option[string]
|
||||
|
||||
// AuthSigBytes is the raw signature under the advertised public key
|
||||
// which serves to authenticate the attributes announced by this node.
|
||||
@@ -49,6 +54,72 @@ type Node struct {
|
||||
ExtraOpaqueData []byte
|
||||
}
|
||||
|
||||
// NodeV1Fields houses the fields that are specific to a version 1 node
|
||||
// announcement.
|
||||
type NodeV1Fields struct {
|
||||
// Address is the TCP address this node is reachable over.
|
||||
Addresses []net.Addr
|
||||
|
||||
// AuthSigBytes is the raw signature under the advertised public key
|
||||
// which serves to authenticate the attributes announced by this node.
|
||||
AuthSigBytes []byte
|
||||
|
||||
// Features is the list of protocol features supported by this node.
|
||||
Features *lnwire.RawFeatureVector
|
||||
|
||||
// Color is the selected color for the node.
|
||||
Color color.RGBA
|
||||
|
||||
// Alias is a nick-name for the node. The alias can be used to confirm
|
||||
// a node's identity or to serve as a short ID for an address book.
|
||||
Alias string
|
||||
|
||||
// LastUpdate is the last time the vertex information for this node has
|
||||
// been updated.
|
||||
LastUpdate time.Time
|
||||
|
||||
// ExtraOpaqueData is the set of data that was appended to this
|
||||
// message, some of which we may not actually know how to iterate or
|
||||
// parse. By holding onto this data, we ensure that we're able to
|
||||
// properly validate the set of signatures that cover these new fields,
|
||||
// and ensure we're able to make upgrades to the network in a forwards
|
||||
// compatible manner.
|
||||
ExtraOpaqueData []byte
|
||||
}
|
||||
|
||||
// NewV1Node creates a new version 1 node from the passed fields.
|
||||
func NewV1Node(pub route.Vertex, n *NodeV1Fields) *Node {
|
||||
return &Node{
|
||||
Version: lnwire.GossipVersion1,
|
||||
PubKeyBytes: pub,
|
||||
Addresses: n.Addresses,
|
||||
AuthSigBytes: n.AuthSigBytes,
|
||||
Features: lnwire.NewFeatureVector(
|
||||
n.Features, lnwire.Features,
|
||||
),
|
||||
Color: fn.Some(n.Color),
|
||||
Alias: fn.Some(n.Alias),
|
||||
LastUpdate: n.LastUpdate,
|
||||
ExtraOpaqueData: n.ExtraOpaqueData,
|
||||
}
|
||||
}
|
||||
|
||||
// NewV1ShellNode creates a new shell version 1 node.
|
||||
func NewV1ShellNode(pubKey route.Vertex) *Node {
|
||||
return NewShellNode(lnwire.GossipVersion1, pubKey)
|
||||
}
|
||||
|
||||
// NewShellNode creates a new shell node with the given gossip version and
|
||||
// public key.
|
||||
func NewShellNode(v lnwire.GossipVersion, pubKey route.Vertex) *Node {
|
||||
return &Node{
|
||||
Version: v,
|
||||
PubKeyBytes: pubKey,
|
||||
Features: lnwire.EmptyFeatureVector(),
|
||||
LastUpdate: time.Unix(0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// HaveAnnouncement returns true if we have received a node announcement for
|
||||
// this node. We determine this by checking if we have a signature for the
|
||||
// announcement.
|
||||
@@ -85,7 +156,7 @@ func (n *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1,
|
||||
return nil, fmt.Errorf("node does not have node announcement")
|
||||
}
|
||||
|
||||
alias, err := lnwire.NewNodeAlias(n.Alias)
|
||||
alias, err := lnwire.NewNodeAlias(n.Alias.UnwrapOr(""))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -93,7 +164,7 @@ func (n *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1,
|
||||
nodeAnn := &lnwire.NodeAnnouncement1{
|
||||
Features: n.Features.RawFeatureVector,
|
||||
NodeID: n.PubKeyBytes,
|
||||
RGBColor: n.Color,
|
||||
RGBColor: n.Color.UnwrapOr(color.RGBA{}),
|
||||
Alias: alias,
|
||||
Addresses: n.Addresses,
|
||||
Timestamp: uint32(n.LastUpdate.Unix()),
|
||||
@@ -118,16 +189,17 @@ func (n *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1,
|
||||
// lnwire.NodeAnnouncement1 message.
|
||||
func NodeFromWireAnnouncement(msg *lnwire.NodeAnnouncement1) *Node {
|
||||
timestamp := time.Unix(int64(msg.Timestamp), 0)
|
||||
features := lnwire.NewFeatureVector(msg.Features, lnwire.Features)
|
||||
|
||||
return &Node{
|
||||
LastUpdate: timestamp,
|
||||
Addresses: msg.Addresses,
|
||||
PubKeyBytes: msg.NodeID,
|
||||
Alias: msg.Alias.String(),
|
||||
AuthSigBytes: msg.Signature.ToSignatureBytes(),
|
||||
Features: features,
|
||||
Color: msg.RGBColor,
|
||||
ExtraOpaqueData: msg.ExtraOpaqueData,
|
||||
}
|
||||
return NewV1Node(
|
||||
msg.NodeID,
|
||||
&NodeV1Fields{
|
||||
LastUpdate: timestamp,
|
||||
Addresses: msg.Addresses,
|
||||
Alias: msg.Alias.String(),
|
||||
AuthSigBytes: msg.Signature.ToSignatureBytes(),
|
||||
Features: msg.Features,
|
||||
Color: msg.RGBColor,
|
||||
ExtraOpaqueData: msg.ExtraOpaqueData,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -391,9 +391,11 @@ func (c *ChannelGraph) addToTopologyChange(update *TopologyChange,
|
||||
nodeUpdate := &NetworkNodeUpdate{
|
||||
Addresses: m.Addresses,
|
||||
IdentityKey: pubKey,
|
||||
Alias: m.Alias,
|
||||
Color: EncodeHexColor(m.Color),
|
||||
Features: m.Features.Clone(),
|
||||
Alias: m.Alias.UnwrapOr(""),
|
||||
Color: EncodeHexColor(
|
||||
m.Color.UnwrapOr(color.RGBA{}),
|
||||
),
|
||||
Features: m.Features.Clone(),
|
||||
}
|
||||
|
||||
update.NodeUpdates = append(update.NodeUpdates, nodeUpdate)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"net"
|
||||
"slices"
|
||||
"time"
|
||||
@@ -1451,8 +1452,10 @@ func insertNodeSQLMig(ctx context.Context, db SQLQueries,
|
||||
|
||||
if node.HaveAnnouncement() {
|
||||
params.LastUpdate = sqldb.SQLInt64(node.LastUpdate.Unix())
|
||||
params.Color = sqldb.SQLStrValid(EncodeHexColor(node.Color))
|
||||
params.Alias = sqldb.SQLStrValid(node.Alias)
|
||||
params.Color = sqldb.SQLStrValid(
|
||||
EncodeHexColor(node.Color.UnwrapOr(color.RGBA{})),
|
||||
)
|
||||
params.Alias = sqldb.SQLStrValid(node.Alias.UnwrapOr(""))
|
||||
params.Signature = node.AuthSigBytes
|
||||
}
|
||||
|
||||
|
||||
@@ -384,9 +384,7 @@ func TestMigrateGraphToSQL(t *testing.T) {
|
||||
// The PruneGraph call requires that the source
|
||||
// node be set. So that is the first object
|
||||
// we will write.
|
||||
&models.Node{
|
||||
PubKeyBytes: testPub,
|
||||
},
|
||||
models.NewV1ShellNode(testPub),
|
||||
// Now we add some block heights to prune
|
||||
// the graph at.
|
||||
uint32(1), uint32(2), uint32(20), uint32(3),
|
||||
@@ -746,16 +744,15 @@ type testNodeOpt func(*models.Node)
|
||||
// makeTestNode can be used to create a test models.Node. The
|
||||
// functional options can be used to modify the node's attributes.
|
||||
func makeTestNode(t *testing.T, opts ...testNodeOpt) *models.Node {
|
||||
n := &models.Node{
|
||||
n := models.NewV1Node(genPubKey(t), &models.NodeV1Fields{
|
||||
AuthSigBytes: testSigBytes,
|
||||
LastUpdate: testTime,
|
||||
Color: testColor,
|
||||
Alias: "kek",
|
||||
Features: testFeatures,
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
Addresses: testAddrs,
|
||||
ExtraOpaqueData: testExtraData,
|
||||
PubKeyBytes: genPubKey(t),
|
||||
}
|
||||
})
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(n)
|
||||
@@ -774,11 +771,7 @@ func makeTestNode(t *testing.T, opts ...testNodeOpt) *models.Node {
|
||||
func makeTestShellNode(t *testing.T,
|
||||
opts ...testNodeOpt) *models.Node {
|
||||
|
||||
n := &models.Node{
|
||||
PubKeyBytes: genPubKey(t),
|
||||
Features: testEmptyFeatures,
|
||||
LastUpdate: time.Unix(0, 0),
|
||||
}
|
||||
n := models.NewV1ShellNode(genPubKey(t))
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(n)
|
||||
@@ -1813,18 +1806,15 @@ func genRandomNode(t *rapid.T) *models.Node {
|
||||
extraOpaqueData = nil
|
||||
}
|
||||
|
||||
node := &models.Node{
|
||||
AuthSigBytes: sigBytes,
|
||||
LastUpdate: randTime,
|
||||
Color: randColor,
|
||||
Alias: alias.String(),
|
||||
Features: lnwire.NewFeatureVector(
|
||||
features, lnwire.Features,
|
||||
),
|
||||
node := models.NewV1Node(pubKeyBytes, &models.NodeV1Fields{
|
||||
AuthSigBytes: sigBytes,
|
||||
LastUpdate: randTime,
|
||||
Color: randColor,
|
||||
Alias: alias.String(),
|
||||
Features: features,
|
||||
Addresses: addrs,
|
||||
ExtraOpaqueData: extraOpaqueData,
|
||||
PubKeyBytes: pubKeyBytes,
|
||||
}
|
||||
})
|
||||
|
||||
// We call this method so that the internal pubkey field is populated
|
||||
// which then lets us to proper struct comparison later on.
|
||||
|
||||
+38
-17
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
color "image/color"
|
||||
"iter"
|
||||
"maps"
|
||||
"math"
|
||||
@@ -555,14 +556,14 @@ func (s *SQLStore) SetSourceNode(ctx context.Context,
|
||||
//
|
||||
// NOTE: This is part of the V1Store interface.
|
||||
func (s *SQLStore) NodeUpdatesInHorizon(startTime, endTime time.Time,
|
||||
opts ...IteratorOption) iter.Seq2[models.Node, error] {
|
||||
opts ...IteratorOption) iter.Seq2[*models.Node, error] {
|
||||
|
||||
cfg := defaultIteratorConfig()
|
||||
for _, opt := range opts {
|
||||
opt(cfg)
|
||||
}
|
||||
|
||||
return func(yield func(models.Node, error) bool) {
|
||||
return func(yield func(*models.Node, error) bool) {
|
||||
var (
|
||||
ctx = context.TODO()
|
||||
lastUpdateTime sql.NullInt64
|
||||
@@ -573,7 +574,7 @@ func (s *SQLStore) NodeUpdatesInHorizon(startTime, endTime time.Time,
|
||||
// Each iteration, we'll read a batch amount of nodes, yield
|
||||
// them, then decide is we have more or not.
|
||||
for hasMore {
|
||||
var batch []models.Node
|
||||
var batch []*models.Node
|
||||
|
||||
//nolint:ll
|
||||
err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
|
||||
@@ -607,7 +608,7 @@ func (s *SQLStore) NodeUpdatesInHorizon(startTime, endTime time.Time,
|
||||
err = forEachNodeInBatch(
|
||||
ctx, s.cfg.QueryCfg, db, rows,
|
||||
func(_ int64, node *models.Node) error {
|
||||
batch = append(batch, *node)
|
||||
batch = append(batch, node)
|
||||
|
||||
// Update pagination cursors
|
||||
// based on the last processed
|
||||
@@ -629,14 +630,14 @@ func (s *SQLStore) NodeUpdatesInHorizon(startTime, endTime time.Time,
|
||||
|
||||
return nil
|
||||
}, func() {
|
||||
batch = []models.Node{}
|
||||
batch = []*models.Node{}
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("NodeUpdatesInHorizon batch "+
|
||||
"error: %v", err)
|
||||
|
||||
yield(models.Node{}, err)
|
||||
yield(&models.Node{}, err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -3485,27 +3486,30 @@ func buildNodeWithBatchData(dbNode sqlc.GraphNode,
|
||||
var pub [33]byte
|
||||
copy(pub[:], dbNode.PubKey)
|
||||
|
||||
node := &models.Node{
|
||||
PubKeyBytes: pub,
|
||||
Features: lnwire.EmptyFeatureVector(),
|
||||
LastUpdate: time.Unix(0, 0),
|
||||
}
|
||||
node := models.NewV1ShellNode(pub)
|
||||
|
||||
if len(dbNode.Signature) == 0 {
|
||||
return node, nil
|
||||
}
|
||||
|
||||
node.AuthSigBytes = dbNode.Signature
|
||||
node.Alias = dbNode.Alias.String
|
||||
node.LastUpdate = time.Unix(dbNode.LastUpdate.Int64, 0)
|
||||
|
||||
if dbNode.Alias.Valid {
|
||||
node.Alias = fn.Some(dbNode.Alias.String)
|
||||
}
|
||||
if dbNode.LastUpdate.Valid {
|
||||
node.LastUpdate = time.Unix(dbNode.LastUpdate.Int64, 0)
|
||||
}
|
||||
|
||||
var err error
|
||||
if dbNode.Color.Valid {
|
||||
node.Color, err = DecodeHexColor(dbNode.Color.String)
|
||||
nodeColor, err := DecodeHexColor(dbNode.Color.String)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode color: %w",
|
||||
err)
|
||||
}
|
||||
|
||||
node.Color = fn.Some(nodeColor)
|
||||
}
|
||||
|
||||
// Use preloaded features.
|
||||
@@ -3608,9 +3612,26 @@ func upsertNode(ctx context.Context, db SQLQueries,
|
||||
}
|
||||
|
||||
if node.HaveAnnouncement() {
|
||||
params.LastUpdate = sqldb.SQLInt64(node.LastUpdate.Unix())
|
||||
params.Color = sqldb.SQLStrValid(EncodeHexColor(node.Color))
|
||||
params.Alias = sqldb.SQLStrValid(node.Alias)
|
||||
switch node.Version {
|
||||
case lnwire.GossipVersion1:
|
||||
params.LastUpdate = sqldb.SQLInt64(
|
||||
node.LastUpdate.Unix(),
|
||||
)
|
||||
|
||||
case lnwire.GossipVersion2:
|
||||
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown gossip version: %d",
|
||||
node.Version)
|
||||
}
|
||||
|
||||
node.Color.WhenSome(func(rgba color.RGBA) {
|
||||
params.Color = sqldb.SQLStrValid(EncodeHexColor(rgba))
|
||||
})
|
||||
node.Alias.WhenSome(func(s string) {
|
||||
params.Alias = sqldb.SQLStrValid(s)
|
||||
})
|
||||
|
||||
params.Signature = node.AuthSigBytes
|
||||
}
|
||||
|
||||
|
||||
+16
-18
@@ -83,15 +83,16 @@ func createTestNode(t *testing.T) *models.Node {
|
||||
require.NoError(t, err)
|
||||
|
||||
pub := priv.PubKey().SerializeCompressed()
|
||||
n := &models.Node{
|
||||
LastUpdate: time.Unix(updateTime, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek" + hex.EncodeToString(pub),
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures,
|
||||
}
|
||||
copy(n.PubKeyBytes[:], pub)
|
||||
n := models.NewV1Node(
|
||||
route.NewVertex(priv.PubKey()), &models.NodeV1Fields{
|
||||
LastUpdate: time.Unix(updateTime, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek" + hex.EncodeToString(pub),
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
},
|
||||
)
|
||||
|
||||
return n
|
||||
}
|
||||
@@ -699,15 +700,12 @@ func TestNodeUpdateNotification(t *testing.T) {
|
||||
t, testFeaturesBuf.Bytes(), featuresBuf.Bytes(),
|
||||
)
|
||||
|
||||
if nodeUpdate.Alias != ann.Alias {
|
||||
t.Fatalf("node alias doesn't match: expected %v, got %v",
|
||||
ann.Alias, nodeUpdate.Alias)
|
||||
}
|
||||
if nodeUpdate.Color != graphdb.EncodeHexColor(ann.Color) {
|
||||
t.Fatalf("node color doesn't match: expected %v, "+
|
||||
"got %v", graphdb.EncodeHexColor(ann.Color),
|
||||
nodeUpdate.Color)
|
||||
}
|
||||
require.Equal(t, nodeUpdate.Alias, ann.Alias.UnwrapOr(""))
|
||||
require.Equal(
|
||||
t, nodeUpdate.Color, graphdb.EncodeHexColor(
|
||||
ann.Color.UnwrapOr(color.RGBA{}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Create lookup map for notifications we are intending to receive. Entries
|
||||
|
||||
+15
-16
@@ -226,18 +226,7 @@ func (s *Server) ImportGraph(ctx context.Context,
|
||||
|
||||
var err error
|
||||
for _, rpcNode := range graph.Nodes {
|
||||
node := &models.Node{
|
||||
LastUpdate: time.Unix(
|
||||
int64(rpcNode.LastUpdate), 0,
|
||||
),
|
||||
Alias: rpcNode.Alias,
|
||||
// NOTE: this is a workaround to ensure that
|
||||
// HaveAnnouncement() returns true so that the other
|
||||
// fields are properly persisted. However,
|
||||
AuthSigBytes: []byte{0},
|
||||
}
|
||||
|
||||
node.PubKeyBytes, err = parsePubKey(rpcNode.PubKey)
|
||||
pubKeyBytes, err := parsePubKey(rpcNode.PubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -254,15 +243,25 @@ func (s *Server) ImportGraph(ctx context.Context,
|
||||
}
|
||||
|
||||
featureVector := lnwire.NewRawFeatureVector(featureBits...)
|
||||
node.Features = lnwire.NewFeatureVector(
|
||||
featureVector, featureNames,
|
||||
)
|
||||
|
||||
node.Color, err = lncfg.ParseHexColor(rpcNode.Color)
|
||||
nodeColor, err := lncfg.ParseHexColor(rpcNode.Color)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node := models.NewV1Node(pubKeyBytes, &models.NodeV1Fields{
|
||||
LastUpdate: time.Unix(
|
||||
int64(rpcNode.LastUpdate), 0,
|
||||
),
|
||||
Alias: rpcNode.Alias,
|
||||
Features: featureVector,
|
||||
Color: nodeColor,
|
||||
// NOTE: this is a workaround to ensure that
|
||||
// HaveAnnouncement() returns true so that the other
|
||||
// fields are properly persisted. However,
|
||||
AuthSigBytes: []byte{0},
|
||||
})
|
||||
|
||||
if err := graphDB.AddNode(ctx, node); err != nil {
|
||||
return nil, fmt.Errorf("unable to add node %v: %w",
|
||||
rpcNode.PubKey, err)
|
||||
|
||||
+21
-17
@@ -228,14 +228,16 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dbNode := &models.Node{
|
||||
pubKey, err := route.NewVertexFromBytes(pubBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
dbNode := models.NewV1Node(pubKey, &models.NodeV1Fields{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: testTime,
|
||||
Addresses: testAddrs,
|
||||
Alias: node.Alias,
|
||||
Features: testFeatures,
|
||||
}
|
||||
copy(dbNode.PubKeyBytes[:], pubBytes)
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
})
|
||||
|
||||
// We require all aliases within the graph to be unique for our
|
||||
// tests.
|
||||
@@ -564,15 +566,15 @@ func createTestGraphFromChannels(t *testing.T, useCache bool,
|
||||
features = lnwire.EmptyFeatureVector()
|
||||
}
|
||||
|
||||
dbNode := &models.Node{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: testTime,
|
||||
Addresses: testAddrs,
|
||||
Alias: alias,
|
||||
Features: features,
|
||||
}
|
||||
|
||||
copy(dbNode.PubKeyBytes[:], pubKey.SerializeCompressed())
|
||||
dbNode := models.NewV1Node(
|
||||
route.NewVertex(pubKey), &models.NodeV1Fields{
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
LastUpdate: testTime,
|
||||
Addresses: testAddrs,
|
||||
Alias: alias,
|
||||
Features: features.RawFeatureVector,
|
||||
},
|
||||
)
|
||||
|
||||
privKeyMap[alias] = privKey
|
||||
|
||||
@@ -1249,10 +1251,12 @@ func runPathFindingWithAdditionalEdges(t *testing.T, useCache bool) {
|
||||
dogePubKeyBytes, err := hex.DecodeString(dogePubKeyHex)
|
||||
require.NoError(t, err, "unable to decode public key")
|
||||
|
||||
doge := &models.Node{}
|
||||
copy(doge.PubKeyBytes[:], dogePubKeyBytes[:])
|
||||
doge.Alias = "doge"
|
||||
copy(doge.PubKeyBytes[:], dogePubKeyBytes)
|
||||
pubKey, err := route.NewVertexFromBytes(dogePubKeyBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
doge := models.NewV1Node(pubKey, &models.NodeV1Fields{
|
||||
Alias: "doge",
|
||||
})
|
||||
graph.aliasMap["doge"] = doge.PubKeyBytes
|
||||
|
||||
// Create the channel edge going from songoku to doge and include it in
|
||||
|
||||
@@ -89,8 +89,9 @@ func TestUpdateAdditionalEdge(t *testing.T) {
|
||||
|
||||
// Create a minimal test node using the private key priv1.
|
||||
pub := priv1.PubKey().SerializeCompressed()
|
||||
testNode := &models.Node{}
|
||||
copy(testNode.PubKeyBytes[:], pub)
|
||||
var pubKey [33]byte
|
||||
copy(pubKey[:], pub)
|
||||
testNode := models.NewV1ShellNode(pubKey)
|
||||
|
||||
nodeID, err := testNode.PubKey()
|
||||
require.NoError(t, err, "failed to get node id")
|
||||
|
||||
+30
-27
@@ -192,15 +192,16 @@ func createTestNode() (*models.Node, error) {
|
||||
}
|
||||
|
||||
pub := priv.PubKey().SerializeCompressed()
|
||||
n := &models.Node{
|
||||
LastUpdate: time.Unix(updateTime, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek" + string(pub),
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures,
|
||||
}
|
||||
copy(n.PubKeyBytes[:], pub)
|
||||
n := models.NewV1Node(
|
||||
route.NewVertex(priv.PubKey()), &models.NodeV1Fields{
|
||||
LastUpdate: time.Unix(updateTime, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "kek" + string(pub),
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
},
|
||||
)
|
||||
|
||||
return n, nil
|
||||
}
|
||||
@@ -2870,27 +2871,29 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
|
||||
|
||||
// Now check that we can update the node info for the partial node
|
||||
// without messing up the channel graph.
|
||||
n1 := &models.Node{
|
||||
LastUpdate: time.Unix(123, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "node11",
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures,
|
||||
}
|
||||
copy(n1.PubKeyBytes[:], priv1.PubKey().SerializeCompressed())
|
||||
n1 := models.NewV1Node(
|
||||
route.NewVertex(priv1.PubKey()), &models.NodeV1Fields{
|
||||
LastUpdate: time.Unix(123, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "node11",
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
},
|
||||
)
|
||||
|
||||
require.NoError(t, ctx.graph.AddNode(ctxb, n1))
|
||||
|
||||
n2 := &models.Node{
|
||||
LastUpdate: time.Unix(123, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "node22",
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures,
|
||||
}
|
||||
copy(n2.PubKeyBytes[:], priv2.PubKey().SerializeCompressed())
|
||||
n2 := models.NewV1Node(
|
||||
route.NewVertex(priv2.PubKey()), &models.NodeV1Fields{
|
||||
LastUpdate: time.Unix(123, 0),
|
||||
Addresses: testAddrs,
|
||||
Color: color.RGBA{1, 2, 3, 0},
|
||||
Alias: "node22",
|
||||
AuthSigBytes: testSig.Serialize(),
|
||||
Features: testFeatures.RawFeatureVector,
|
||||
},
|
||||
)
|
||||
|
||||
require.NoError(t, ctx.graph.AddNode(ctxb, n2))
|
||||
|
||||
|
||||
+10
-7
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"io"
|
||||
"maps"
|
||||
"math"
|
||||
@@ -7187,11 +7188,13 @@ func marshalNode(node *models.Node) *lnrpc.LightningNode {
|
||||
customRecords := marshalExtraOpaqueData(node.ExtraOpaqueData)
|
||||
|
||||
return &lnrpc.LightningNode{
|
||||
LastUpdate: uint32(node.LastUpdate.Unix()),
|
||||
PubKey: hex.EncodeToString(node.PubKeyBytes[:]),
|
||||
Addresses: nodeAddrs,
|
||||
Alias: node.Alias,
|
||||
Color: graphdb.EncodeHexColor(node.Color),
|
||||
LastUpdate: uint32(node.LastUpdate.Unix()),
|
||||
PubKey: hex.EncodeToString(node.PubKeyBytes[:]),
|
||||
Addresses: nodeAddrs,
|
||||
Alias: node.Alias.UnwrapOr(""),
|
||||
Color: graphdb.EncodeHexColor(
|
||||
node.Color.UnwrapOr(color.RGBA{}),
|
||||
),
|
||||
Features: features,
|
||||
CustomRecords: customRecords,
|
||||
}
|
||||
@@ -8258,9 +8261,9 @@ func (r *rpcServer) ForwardingHistory(ctx context.Context,
|
||||
}
|
||||
|
||||
// Cache the peer alias.
|
||||
chanToPeerAlias[chanID] = peer.Alias
|
||||
chanToPeerAlias[chanID] = peer.Alias.UnwrapOr("")
|
||||
|
||||
return peer.Alias, nil
|
||||
return peer.Alias.UnwrapOr(""), nil
|
||||
}
|
||||
|
||||
// TODO(roasbeef): add settlement latency?
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"math/big"
|
||||
prand "math/rand"
|
||||
"net"
|
||||
@@ -3299,17 +3300,17 @@ func (s *server) createNewHiddenService(ctx context.Context) error {
|
||||
|
||||
// Finally, we'll update the on-disk version of our announcement so it
|
||||
// will eventually propagate to nodes in the network.
|
||||
selfNode := &models.Node{
|
||||
LastUpdate: time.Unix(int64(newNodeAnn.Timestamp), 0),
|
||||
Addresses: newNodeAnn.Addresses,
|
||||
Alias: newNodeAnn.Alias.String(),
|
||||
Features: lnwire.NewFeatureVector(
|
||||
newNodeAnn.Features, lnwire.Features,
|
||||
),
|
||||
Color: newNodeAnn.RGBColor,
|
||||
AuthSigBytes: newNodeAnn.Signature.ToSignatureBytes(),
|
||||
}
|
||||
copy(selfNode.PubKeyBytes[:], s.identityECDH.PubKey().SerializeCompressed())
|
||||
selfNode := models.NewV1Node(
|
||||
route.NewVertex(s.identityECDH.PubKey()), &models.NodeV1Fields{
|
||||
Addresses: newNodeAnn.Addresses,
|
||||
Features: newNodeAnn.Features,
|
||||
AuthSigBytes: newNodeAnn.Signature.ToSignatureBytes(),
|
||||
Color: newNodeAnn.RGBColor,
|
||||
Alias: newNodeAnn.Alias.String(),
|
||||
LastUpdate: time.Unix(int64(newNodeAnn.Timestamp), 0),
|
||||
},
|
||||
)
|
||||
|
||||
if err := s.graphDB.SetSourceNode(ctx, selfNode); err != nil {
|
||||
return fmt.Errorf("can't set self node: %w", err)
|
||||
}
|
||||
@@ -3425,9 +3426,9 @@ func (s *server) updateAndBroadcastSelfNode(ctx context.Context,
|
||||
|
||||
selfNode.LastUpdate = time.Unix(int64(newNodeAnn.Timestamp), 0)
|
||||
selfNode.Addresses = newNodeAnn.Addresses
|
||||
selfNode.Alias = newNodeAnn.Alias.String()
|
||||
selfNode.Alias = fn.Some(newNodeAnn.Alias.String())
|
||||
selfNode.Features = s.featureMgr.Get(feature.SetNodeAnn)
|
||||
selfNode.Color = newNodeAnn.RGBColor
|
||||
selfNode.Color = fn.Some(newNodeAnn.RGBColor)
|
||||
selfNode.AuthSigBytes = newNodeAnn.Signature.ToSignatureBytes()
|
||||
|
||||
copy(selfNode.PubKeyBytes[:], s.identityECDH.PubKey().SerializeCompressed())
|
||||
@@ -5583,7 +5584,7 @@ func (s *server) setSelfNode(ctx context.Context, nodePub route.Vertex,
|
||||
// Parse the color from config. We will update this later if the config
|
||||
// color is not changed from default (#3399FF) and we have a value in
|
||||
// the source node.
|
||||
color, err := lncfg.ParseHexColor(s.cfg.Color)
|
||||
nodeColor, err := lncfg.ParseHexColor(s.cfg.Color)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to parse color: %w", err)
|
||||
}
|
||||
@@ -5607,13 +5608,17 @@ func (s *server) setSelfNode(ctx context.Context, nodePub route.Vertex,
|
||||
// didn't specify a different color in the config. We'll use the
|
||||
// source node's color.
|
||||
if s.cfg.Color == defaultColor {
|
||||
color = srcNode.Color
|
||||
srcNode.Color.WhenSome(func(rgba color.RGBA) {
|
||||
nodeColor = rgba
|
||||
})
|
||||
}
|
||||
|
||||
// If an alias is not specified in the config, we'll use the
|
||||
// source node's alias.
|
||||
if alias == "" {
|
||||
alias = srcNode.Alias
|
||||
srcNode.Alias.WhenSome(func(s string) {
|
||||
alias = s
|
||||
})
|
||||
}
|
||||
|
||||
// If the `externalip` is not specified in the config, it means
|
||||
@@ -5643,15 +5648,15 @@ func (s *server) setSelfNode(ctx context.Context, nodePub route.Vertex,
|
||||
|
||||
// TODO(abdulkbk): potentially find a way to use the source node's
|
||||
// features in the self node.
|
||||
selfNode := &models.Node{
|
||||
LastUpdate: nodeLastUpdate,
|
||||
Addresses: addrs,
|
||||
Alias: nodeAlias.String(),
|
||||
Color: color,
|
||||
Features: s.featureMgr.Get(feature.SetNodeAnn),
|
||||
}
|
||||
|
||||
copy(selfNode.PubKeyBytes[:], nodePub[:])
|
||||
selfNode := models.NewV1Node(
|
||||
nodePub, &models.NodeV1Fields{
|
||||
Alias: nodeAlias.String(),
|
||||
Color: nodeColor,
|
||||
LastUpdate: nodeLastUpdate,
|
||||
Addresses: addrs,
|
||||
Features: s.featureMgr.GetRaw(feature.SetNodeAnn),
|
||||
},
|
||||
)
|
||||
|
||||
// Based on the disk representation of the node announcement generated
|
||||
// above, we'll generate a node announcement that can go out on the
|
||||
|
||||
Reference in new issue
Block a user