lnd.xprv/autopilot/top_centrality_test.go
Andras Banki-Horvath 8373b2ad20
autopilot: add greedy "TopK" centrality heuristic
This commit creates a new autopilot heuristic which simply returns
normalized betweenness centrality values for the current graph. This
new heuristic will make it possible to prefer nodes with large
centrality when we're trying to open channels. The heuristic is also
somewhat dumb as it doesn't try to figure out the best nodes, as that'd
require adding ghost edges to the graph recalculating the centrality as
many times as many nodes there are (minus the one we already have
channels with).
2020-07-17 16:12:54 +02:00

110 lines
2.7 KiB
Go

package autopilot
import (
"testing"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcutil"
"github.com/stretchr/testify/require"
)
// testTopCentrality is subtest helper to which given the passed graph and
// channels creates the expected centrality score set and checks that the
// calculated score set matches it.
func testTopCentrality(t *testing.T, graph testGraph,
graphNodes map[int]*btcec.PublicKey, channelsWith []int) {
topCentrality := NewTopCentrality()
var channels []Channel
for _, ch := range channelsWith {
channels = append(channels, Channel{
Node: NewNodeID(graphNodes[ch]),
})
}
// Start iteration from -1 to also test the case where the node set
// is empty.
for i := -1; i < len(graphNodes); i++ {
nodes := make(map[NodeID]struct{})
expected := make(map[NodeID]*NodeScore)
for j := 0; j <= i; j++ {
// Add node to the interest set.
nodeID := NewNodeID(graphNodes[j])
nodes[nodeID] = struct{}{}
// Add to the expected set unless it's a node we have
// a channel with.
haveChannel := false
for _, ch := range channels {
if nodeID == ch.Node {
haveChannel = true
break
}
}
if !haveChannel {
score := normalizedTestGraphCentrality[j]
expected[nodeID] = &NodeScore{
NodeID: nodeID,
Score: score,
}
}
}
const chanSize = btcutil.SatoshiPerBitcoin
// Attempt to get centrality scores and expect
// that the result equals with the expected set.
scores, err := topCentrality.NodeScores(
graph, channels, chanSize, nodes,
)
require.NoError(t, err)
require.Equal(t, expected, scores)
}
}
// TestTopCentrality tests that we return the correct normalized centralitiy
// values given a non empty graph, and given our node has an increasing amount
// of channels from 0 to N-1 simulating the whole range from non-connected to
// fully connected.
func TestTopCentrality(t *testing.T) {
// Generate channels: {}, {0}, {0, 1}, ... {0, 1, ..., N-1}
channelsWith := [][]int{nil}
for i := 0; i < centralityTestGraph.nodes; i++ {
channels := make([]int, i+1)
for j := 0; j <= i; j++ {
channels[j] = j
}
channelsWith = append(channelsWith, channels)
}
for _, chanGraph := range chanGraphs {
chanGraph := chanGraph
success := t.Run(chanGraph.name, func(t *testing.T) {
t.Parallel()
graph, cleanup, err := chanGraph.genFunc()
require.NoError(t, err, "unable to create graph")
if cleanup != nil {
defer cleanup()
}
// Build the test graph.
graphNodes := buildTestGraph(
t, graph, centralityTestGraph,
)
for _, chans := range channelsWith {
testTopCentrality(t, graph, graphNodes, chans)
}
})
require.True(t, success)
}
}