graph/db: introduce ForEachSourceNodeChannel
In preparation for creating a clean interface for the graph store, we want to hide anything that is DB specific from the exposed methods on the interface. Currently the `ForEachNodeChannel` and the `FetchOtherNode` methods of the `KVStore` expose a `kvdb.RTx` parameter which is bbolt specific. There is only one call-site of `ForEachNodeChannel` actually makes use of the passed `kvdb.RTx` parameter, and that is in the `establishPersistentConnections` method of the `server` which then passes the tx parameter to `FetchOtherNode`. So to clean-up the interface such that the `kvdb.RTx` is no longer exposed: we instead create one new method called `ForEachSourceNodeChannel` which can be used to replace the above mentioned call-site. So as of this commit, all the remaining call-site of `ForEachNodeChannel` pass in a nil param for `kvdb.RTx` - meaning we can remove the parameter in a future commit.
This commit is contained in:
3 files changed
+136
-26
No files matched your search
+92
-1
@@ -618,7 +618,7 @@ func createChannelEdge(node1, node2 *models.LightningNode) (
|
|||||||
chanID := uint64(prand.Int63())
|
chanID := uint64(prand.Int63())
|
||||||
outpoint := wire.OutPoint{
|
outpoint := wire.OutPoint{
|
||||||
Hash: rev,
|
Hash: rev,
|
||||||
Index: 9,
|
Index: prand.Uint32(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the new edge to the database, this should proceed without any
|
// Add the new edge to the database, this should proceed without any
|
||||||
@@ -991,6 +991,97 @@ func newEdgePolicy(chanID uint64, updateTime int64) *models.ChannelEdgePolicy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestForEachSourceNodeChannel tests that the ForEachSourceNodeChannel
|
||||||
|
// correctly iterates through the channels of the set source node.
|
||||||
|
func TestForEachSourceNodeChannel(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
graph, err := MakeTestGraph(t)
|
||||||
|
require.NoError(t, err, "unable to make test database")
|
||||||
|
|
||||||
|
// Create a source node (A) and set it as such in the DB.
|
||||||
|
nodeA := createTestVertex(t)
|
||||||
|
require.NoError(t, graph.SetSourceNode(nodeA))
|
||||||
|
|
||||||
|
// Now, create a few more nodes (B, C, D) along with some channels
|
||||||
|
// between them. We'll create the following graph:
|
||||||
|
//
|
||||||
|
// A -- B -- D
|
||||||
|
// |
|
||||||
|
// C
|
||||||
|
//
|
||||||
|
// The graph includes a channel (B-D) that does not belong to the source
|
||||||
|
// node along with 2 channels (A-B and A-C) that do belong to the source
|
||||||
|
// node. For the A-B channel, we will let the source node set an
|
||||||
|
// outgoing policy but for the A-C channel, we will set only an incoming
|
||||||
|
// policy.
|
||||||
|
|
||||||
|
nodeB := createTestVertex(t)
|
||||||
|
nodeC := createTestVertex(t)
|
||||||
|
nodeD := createTestVertex(t)
|
||||||
|
|
||||||
|
abEdge, abPolicy1, abPolicy2 := createChannelEdge(nodeA, nodeB)
|
||||||
|
require.NoError(t, graph.AddChannelEdge(abEdge))
|
||||||
|
acEdge, acPolicy1, acPolicy2 := createChannelEdge(nodeA, nodeC)
|
||||||
|
require.NoError(t, graph.AddChannelEdge(acEdge))
|
||||||
|
bdEdge, _, _ := createChannelEdge(nodeB, nodeD)
|
||||||
|
require.NoError(t, graph.AddChannelEdge(bdEdge))
|
||||||
|
|
||||||
|
// Figure out which of the policies returned above are node A's so that
|
||||||
|
// we know which to persist.
|
||||||
|
//
|
||||||
|
// First, set the outgoing policy for the A-B channel.
|
||||||
|
abPolicyAOutgoing := abPolicy1
|
||||||
|
if !bytes.Equal(abPolicy1.ToNode[:], nodeB.PubKeyBytes[:]) {
|
||||||
|
abPolicyAOutgoing = abPolicy2
|
||||||
|
}
|
||||||
|
require.NoError(t, graph.UpdateEdgePolicy(abPolicyAOutgoing))
|
||||||
|
|
||||||
|
// Now, set the incoming policy for the A-C channel.
|
||||||
|
acPolicyAIncoming := acPolicy1
|
||||||
|
if !bytes.Equal(acPolicy1.ToNode[:], nodeA.PubKeyBytes[:]) {
|
||||||
|
acPolicyAIncoming = acPolicy2
|
||||||
|
}
|
||||||
|
require.NoError(t, graph.UpdateEdgePolicy(acPolicyAIncoming))
|
||||||
|
|
||||||
|
type sourceNodeChan struct {
|
||||||
|
otherNode route.Vertex
|
||||||
|
havePolicy bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put together our expected source node channels.
|
||||||
|
expectedSrcChans := map[wire.OutPoint]*sourceNodeChan{
|
||||||
|
abEdge.ChannelPoint: {
|
||||||
|
otherNode: nodeB.PubKeyBytes,
|
||||||
|
havePolicy: true,
|
||||||
|
},
|
||||||
|
acEdge.ChannelPoint: {
|
||||||
|
otherNode: nodeC.PubKeyBytes,
|
||||||
|
havePolicy: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, we'll use the ForEachSourceNodeChannel and assert that it
|
||||||
|
// returns the expected data in the call-back.
|
||||||
|
err = graph.ForEachSourceNodeChannel(func(chanPoint wire.OutPoint,
|
||||||
|
havePolicy bool, otherNode *models.LightningNode) error {
|
||||||
|
|
||||||
|
require.Contains(t, expectedSrcChans, chanPoint)
|
||||||
|
expected := expectedSrcChans[chanPoint]
|
||||||
|
|
||||||
|
require.Equal(
|
||||||
|
t, expected.otherNode[:], otherNode.PubKeyBytes[:],
|
||||||
|
)
|
||||||
|
require.Equal(t, expected.havePolicy, havePolicy)
|
||||||
|
|
||||||
|
delete(expectedSrcChans, chanPoint)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Empty(t, expectedSrcChans)
|
||||||
|
}
|
||||||
|
|
||||||
func TestGraphTraversal(t *testing.T) {
|
func TestGraphTraversal(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -3109,6 +3109,44 @@ func (c *KVStore) ForEachNodeChannel(nodePub route.Vertex,
|
|||||||
return nodeTraversal(nil, nodePub[:], c.db, cb)
|
return nodeTraversal(nil, nodePub[:], c.db, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForEachSourceNodeChannel iterates through all channels of the source node,
|
||||||
|
// executing the passed callback on each. The callback is provided with the
|
||||||
|
// channel's outpoint, whether we have a policy for the channel and the channel
|
||||||
|
// peer's node information.
|
||||||
|
func (c *KVStore) ForEachSourceNodeChannel(cb func(chanPoint wire.OutPoint,
|
||||||
|
havePolicy bool, otherNode *models.LightningNode) error) error {
|
||||||
|
|
||||||
|
return kvdb.View(c.db, func(tx kvdb.RTx) error {
|
||||||
|
nodes := tx.ReadBucket(nodeBucket)
|
||||||
|
if nodes == nil {
|
||||||
|
return ErrGraphNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := c.sourceNode(nodes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeTraversal(
|
||||||
|
tx, node.PubKeyBytes[:], c.db, func(tx kvdb.RTx,
|
||||||
|
info *models.ChannelEdgeInfo,
|
||||||
|
policy, _ *models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
|
peer, err := c.FetchOtherNode(
|
||||||
|
tx, info, node.PubKeyBytes[:],
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb(
|
||||||
|
info.ChannelPoint, policy != nil, peer,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}, func() {})
|
||||||
|
}
|
||||||
|
|
||||||
// ForEachNodeChannelTx iterates through all channels of the given node,
|
// ForEachNodeChannelTx iterates through all channels of the given node,
|
||||||
// executing the passed callback with an edge info structure and the policies
|
// executing the passed callback with an edge info structure and the policies
|
||||||
// of each end of the channel. The first edge policy is the outgoing edge *to*
|
// of each end of the channel. The first edge policy is the outgoing edge *to*
|
||||||
|
|||||||
@@ -3553,36 +3553,17 @@ func (s *server) establishPersistentConnections() error {
|
|||||||
// After checking our previous connections for addresses to connect to,
|
// After checking our previous connections for addresses to connect to,
|
||||||
// iterate through the nodes in our channel graph to find addresses
|
// iterate through the nodes in our channel graph to find addresses
|
||||||
// that have been added via NodeAnnouncement messages.
|
// that have been added via NodeAnnouncement messages.
|
||||||
sourceNode, err := s.graphDB.SourceNode()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to fetch source node: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(roasbeef): instead iterate over link nodes and query graph for
|
// TODO(roasbeef): instead iterate over link nodes and query graph for
|
||||||
// each of the nodes.
|
// each of the nodes.
|
||||||
selfPub := s.identityECDH.PubKey().SerializeCompressed()
|
err = s.graphDB.ForEachSourceNodeChannel(func(chanPoint wire.OutPoint,
|
||||||
err = s.graphDB.ForEachNodeChannel(sourceNode.PubKeyBytes, func(
|
havePolicy bool, channelPeer *models.LightningNode) error {
|
||||||
tx kvdb.RTx,
|
|
||||||
chanInfo *models.ChannelEdgeInfo,
|
|
||||||
policy, _ *models.ChannelEdgePolicy) error {
|
|
||||||
|
|
||||||
// If the remote party has announced the channel to us, but we
|
// If the remote party has announced the channel to us, but we
|
||||||
// haven't yet, then we won't have a policy. However, we don't
|
// haven't yet, then we won't have a policy. However, we don't
|
||||||
// need this to connect to the peer, so we'll log it and move on.
|
// need this to connect to the peer, so we'll log it and move on.
|
||||||
if policy == nil {
|
if !havePolicy {
|
||||||
srvrLog.Warnf("No channel policy found for "+
|
srvrLog.Warnf("No channel policy found for "+
|
||||||
"ChannelPoint(%v): ", chanInfo.ChannelPoint)
|
"ChannelPoint(%v): ", chanPoint)
|
||||||
}
|
|
||||||
|
|
||||||
// We'll now fetch the peer opposite from us within this
|
|
||||||
// channel so we can queue up a direct connection to them.
|
|
||||||
channelPeer, err := s.graphDB.FetchOtherNode(
|
|
||||||
tx, chanInfo, selfPub,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to fetch channel peer for "+
|
|
||||||
"ChannelPoint(%v): %v", chanInfo.ChannelPoint,
|
|
||||||
err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pubStr := string(channelPeer.PubKeyBytes[:])
|
pubStr := string(channelPeer.PubKeyBytes[:])
|
||||||
@@ -3642,8 +3623,8 @@ func (s *server) establishPersistentConnections() error {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
srvrLog.Errorf("Failed to iterate channels for node %x",
|
srvrLog.Errorf("Failed to iterate over source node channels: "+
|
||||||
sourceNode.PubKeyBytes)
|
"%v", err)
|
||||||
|
|
||||||
if !errors.Is(err, graphdb.ErrGraphNoEdgesFound) &&
|
if !errors.Is(err, graphdb.ErrGraphNoEdgesFound) &&
|
||||||
!errors.Is(err, graphdb.ErrEdgeNotFound) {
|
!errors.Is(err, graphdb.ErrEdgeNotFound) {
|
||||||
|
|||||||
Reference in new issue
Block a user