327768f4ad
Use [33]byte for graph vertex representation. Delete unneeded stuff: 1. DeepEqual for graph comparison 2. EdgePath 3. 2-thread BFS 4. Table transfer messages and neighborhood radius 5. Beacons Refactor: 1. Change ID to Vertex 2. Test use table driven approach 3. Add comments 4. Make graph internal representation private 5. Use wire.OutPoint as EdgeId 6. Decouple routing messages from routing implementation 7. Delete Async methods 8. Delete unneeded channels and priority buffer from manager 9. Delete unneeded interfaces in internal graph realisation 10. Renamed ID to Vertex
240 lines
6.1 KiB
Go
240 lines
6.1 KiB
Go
// Copyright (c) 2016 Bitfury Group Limited
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file LICENSE or http://www.opensource.org/licenses/mit-license.php
|
|
|
|
package routing
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/lightningnetwork/lnd/routing/rt/graph"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func abs(x int) int {
|
|
if x < 0 {
|
|
return -x
|
|
}
|
|
return x
|
|
}
|
|
|
|
func vertexFromInt(x int) graph.Vertex {
|
|
s := fmt.Sprintf("%v", x)
|
|
return graph.NewVertex([]byte(s))
|
|
}
|
|
|
|
func edgeIdFromString(s string) graph.EdgeID {
|
|
e := graph.EdgeID{}
|
|
copy(e.Hash[:], []byte(s))
|
|
return e
|
|
}
|
|
|
|
var sampleEdgeId graph.EdgeID = edgeIdFromString("EdgeId")
|
|
|
|
func createLinearNetwork(n int) (*MockNetwork, []*RoutingManager) {
|
|
// Creates linear graph 0->1->2->..->n-1
|
|
nodes := make([]*RoutingManager, 0)
|
|
net := NewMockNetwork(false)
|
|
net.Start()
|
|
for i := 0; i < n; i++ {
|
|
node := NewRoutingManager(vertexFromInt(i), nil)
|
|
nodes = append(nodes, node)
|
|
node.Start()
|
|
net.Add(node)
|
|
}
|
|
|
|
for i := 0; i < n-1; i++ {
|
|
nodes[i].OpenChannel(nodes[i+1].Id, sampleEdgeId, nil)
|
|
nodes[i+1].OpenChannel(nodes[i].Id, sampleEdgeId, nil)
|
|
}
|
|
|
|
return net, nodes
|
|
}
|
|
|
|
func createCompleteNetwork(n int) (*MockNetwork, []*RoutingManager) {
|
|
nodes := make([]*RoutingManager, 0)
|
|
net := NewMockNetwork(false)
|
|
net.Start()
|
|
for i := 0; i < n; i++ {
|
|
node := NewRoutingManager(vertexFromInt(i), nil)
|
|
nodes = append(nodes, node)
|
|
node.Start()
|
|
net.Add(node)
|
|
}
|
|
|
|
for i := 0; i < n-1; i++ {
|
|
for j := i + 1; j < n; j++ {
|
|
nodes[i].OpenChannel(nodes[j].Id, sampleEdgeId, nil)
|
|
nodes[j].OpenChannel(nodes[i].Id, sampleEdgeId, nil)
|
|
}
|
|
}
|
|
|
|
return net, nodes
|
|
}
|
|
|
|
func createNetwork(desc [][2]int, idFunc func(int) graph.Vertex) (*MockNetwork, map[int]*RoutingManager, []graph.Edge) {
|
|
// Creates network of nodes from graph description
|
|
net := NewMockNetwork(false)
|
|
net.Start()
|
|
// create unique nodes
|
|
nodes := make(map[int]*RoutingManager)
|
|
for i := 0; i < len(desc); i++ {
|
|
for j := 0; j < 2; j++ {
|
|
nodeId := desc[i][j]
|
|
if _, ok := nodes[nodeId]; !ok {
|
|
var id graph.Vertex
|
|
if idFunc != nil {
|
|
id = idFunc(nodeId)
|
|
} else {
|
|
id = vertexFromInt(nodeId)
|
|
}
|
|
node := NewRoutingManager(id, nil)
|
|
nodes[nodeId] = node
|
|
node.Start()
|
|
net.Add(node)
|
|
}
|
|
}
|
|
}
|
|
edges := make([]graph.Edge, 0, len(desc))
|
|
for i := 0; i < len(desc); i++ {
|
|
edgeID := edgeIdFromString(fmt.Sprintf("edge-%v", i))
|
|
nodes[desc[i][0]].OpenChannel(nodes[desc[i][1]].Id, edgeID, &graph.ChannelInfo{1, 1})
|
|
nodes[desc[i][1]].OpenChannel(nodes[desc[i][0]].Id, edgeID, &graph.ChannelInfo{1, 1})
|
|
edges = append(edges, graph.NewEdge(
|
|
nodes[desc[i][0]].Id,
|
|
nodes[desc[i][1]].Id,
|
|
edgeID,
|
|
&graph.ChannelInfo{1, 1},
|
|
))
|
|
}
|
|
return net, nodes, edges
|
|
}
|
|
|
|
func TestNeighborsScanLinearGraph(t *testing.T) {
|
|
n := 4
|
|
net, nodes := createLinearNetwork(n)
|
|
time.Sleep(10 * time.Millisecond)
|
|
// Each node should know about all channels
|
|
for i := 0; i < n; i++ {
|
|
for j := 0; j < n; j++ {
|
|
for k := 0; k < n; k++ {
|
|
ans := nodes[i].HasChannel(nodes[j].Id, nodes[k].Id, sampleEdgeId)
|
|
correctAns := abs(j-k) == 1
|
|
if ans != correctAns {
|
|
t.Errorf("nodes[%v].HasChannel(%v, %v)==%v, want %v", i, j, k, ans, correctAns)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
net.Stop()
|
|
|
|
}
|
|
|
|
func TestNeighborsScanCompleteGraph(t *testing.T) {
|
|
n := 4
|
|
net, nodes := createCompleteNetwork(n)
|
|
time.Sleep(10 * time.Millisecond)
|
|
// Each node should know about all channels
|
|
for i := 0; i < n; i++ {
|
|
for j := 0; j < n; j++ {
|
|
for k := 0; k < n; k++ {
|
|
ans := nodes[i].HasChannel(nodes[j].Id, nodes[k].Id, sampleEdgeId)
|
|
correctAns := j != k
|
|
if ans != correctAns {
|
|
t.Errorf("nodes[%v].HasChannel(%v, %v)==%v, want %v", i, j, k, ans, correctAns)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
net.Stop()
|
|
}
|
|
|
|
func TestNeighborsRemoveChannel(t *testing.T) {
|
|
// Create complete graph, than delete channels to make it linear
|
|
n := 4
|
|
net, nodes := createCompleteNetwork(n)
|
|
time.Sleep(10 * time.Millisecond)
|
|
for i := 0; i < n; i++ {
|
|
for j := 0; j < n; j++ {
|
|
if abs(i-j) != 1 {
|
|
nodes[i].RemoveChannel(nodes[i].Id, nodes[j].Id, sampleEdgeId)
|
|
}
|
|
}
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
// Each node should know about all channels
|
|
for i := 0; i < n; i++ {
|
|
for j := 0; j < n; j++ {
|
|
for k := 0; k < n; k++ {
|
|
ans := nodes[i].HasChannel(nodes[j].Id, nodes[k].Id, sampleEdgeId)
|
|
correctAns := abs(j-k) == 1
|
|
if ans != correctAns {
|
|
t.Errorf("nodes[%v].HasChannel(%v, %v)==%v, want %v", i, j, k, ans, correctAns)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
net.Stop()
|
|
}
|
|
|
|
func TestFindPath(t *testing.T) {
|
|
// Create linear graph
|
|
n := 6
|
|
net, nodes := createLinearNetwork(n)
|
|
time.Sleep(10 * time.Millisecond) // Each node should know about all channels
|
|
|
|
path, err := nodes[0].FindPath(nodes[5].Id)
|
|
if err != nil {
|
|
t.Errorf("err = %v, want %v", err)
|
|
}
|
|
correctPath := []graph.Vertex{}
|
|
for i := 0; i < n; i++ {
|
|
correctPath = append(correctPath, nodes[i].Id)
|
|
}
|
|
if !reflect.DeepEqual(path, correctPath) {
|
|
t.Errorf("path = %v, want %v", path, correctPath)
|
|
}
|
|
// Case when path do not exist
|
|
path, err = nodes[0].FindPath(vertexFromInt(7))
|
|
if path != nil {
|
|
t.Errorf("path = %v, want %v", path, nil)
|
|
}
|
|
if err != graph.PathNotFoundError {
|
|
t.Errorf("err = %v, want %v", err, graph.PathNotFoundError)
|
|
}
|
|
net.Stop()
|
|
}
|
|
|
|
func TestKShortestPaths(t *testing.T) {
|
|
net, nodes, _ := createNetwork([][2]int{
|
|
[2]int{0, 1},
|
|
[2]int{1, 2},
|
|
[2]int{2, 3},
|
|
[2]int{1, 3},
|
|
[2]int{4, 5},
|
|
}, nil)
|
|
time.Sleep(10 * time.Millisecond) // Each node should know about all channels
|
|
// There was bug in lnd when second search of the same path leads to lncli/lnd freeze
|
|
for iter := 1; iter <= 3; iter++ {
|
|
paths, err := nodes[0].FindKShortestPaths(nodes[3].Id, 2)
|
|
if err != nil {
|
|
t.Errorf("err = %v, want %v", err, nil)
|
|
}
|
|
correctPaths := [][]graph.Vertex{
|
|
[]graph.Vertex{vertexFromInt(0), vertexFromInt(1), vertexFromInt(3)},
|
|
[]graph.Vertex{vertexFromInt(0), vertexFromInt(1), vertexFromInt(2), vertexFromInt(3)},
|
|
}
|
|
if !reflect.DeepEqual(paths, correctPaths) {
|
|
t.Errorf("on iteration: %v paths = %v, want %v", iter, paths, correctPaths)
|
|
}
|
|
}
|
|
// Case when path do not exist
|
|
paths, _ := nodes[0].FindKShortestPaths(vertexFromInt(7), 3)
|
|
if len(paths) != 0 {
|
|
t.Errorf("path = %v, want %v", paths, []graph.Vertex{})
|
|
}
|
|
net.Stop()
|
|
}
|