lnd.xprv/routing/rt/graph/graph.go
BitfuryLightning 327768f4ad routing: Move tools inside lnd. Refactor and delete unneeded stuff
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
2016-11-23 20:37:43 -06:00

358 lines
9.0 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 graph
import (
"errors"
"fmt"
"math"
"bytes"
"github.com/roasbeef/btcd/wire"
)
var (
// CyclicDataError represents internal error. When trying to
// obtain explicit path after BFS. Following parents resulted
// in a loop.
CyclicDataError = errors.New("Cyclic data")
// PathNotFoundError represents not existing path
// after search
PathNotFoundError = errors.New("Path not found")
// NodeNotFoundError represents that required vertex
// does not exist in the graph
NodeNotFoundError = errors.New("Node not found")
// EdgeNotFoundError represents that requested edge
// does not exist in the graph
EdgeNotFoundError = errors.New("Edge not found")
)
// Vertex represent graph vertex(node) in a
// lightning network
type Vertex struct {
PubKey [33]byte
}
// NilVertex represents not existing vertex.
// This value should be used similar to nil
var NilVertex = Vertex{PubKey: [33]byte{}}
// NewVertex creates a new vertex from a compressed public key.
func NewVertex(v []byte) Vertex {
x := Vertex{}
copy(x.PubKey[:], v)
return x
}
// String creates a string representation of a Vertex.
// Note: it does not hex encode.
func (s Vertex) String() string {
return string(s.PubKey[:])
}
// ToByte33 returns [33]byte
// 33 - is usual byte length of a compressed
// public key
func (s Vertex) ToByte33() [33]byte {
var rez [33]byte
copy(rez[:], s.PubKey[:])
return rez
}
// ToByte() returns byte representation of
// the vertex
func (s Vertex) ToByte() []byte {
return s.PubKey[:]
}
// IsNil compares vertex to nil vertex
func (s Vertex) IsNil() bool {
var z [33]byte
return bytes.Equal(s.PubKey[:], z[:])
}
// EdgeID represent edge unique identifier.
type EdgeID wire.OutPoint
// NilEdgeID represent not existing EdgeID
var NilEdgeID = EdgeID{wire.ShaHash{}, 0}
// NewEdgeID returns new EdgeID
func NewEdgeID(v wire.OutPoint) EdgeID {
return EdgeID(v)
}
// String returns string representation of EdgeID
func (e EdgeID) String() string {
return wire.OutPoint(e).String()
}
// ChannelInfo contains information about edge(channel)
// like capacity or weight
type ChannelInfo struct {
// Capacity in satoshi of the channel
Cpt int64
// Weight of the channel
Wgt float64
}
// Copy() creates a copy of a ChannelInfo struct.
// If c==nil than it returns nil.
// This method is used to safely create copy of a structure
// given by a pointer which may be nil.
func (c *ChannelInfo) Copy() *ChannelInfo {
if c == nil {
return nil
} else {
c1 := *c
return &c1
}
}
// Edge represents edge in a graph
type Edge struct {
// Source and Target
Src, Tgt Vertex
// Edge identifier
Id EdgeID
// Additional information about edge
Info *ChannelInfo
}
// NilEdge represents nil (not-existing) edge
var NilEdge = Edge{NilVertex, NilVertex, NilEdgeID, nil}
// String returns string of an Edge
func (e Edge) String() string {
return fmt.Sprintf("edge[%v %v %v %v]", e.Src, e.Tgt, e.Id, e.Info)
}
// NewEdge create a new edge
func NewEdge(src, tgt Vertex, id EdgeID, info *ChannelInfo) Edge {
return Edge{
Src: src,
Tgt: tgt,
Id: id,
Info: info,
}
}
// Graph is multigraph implementation.
type Graph struct {
adjacencyList map[Vertex]map[Vertex]map[EdgeID]*ChannelInfo
}
// NewGraph creates a new empty graph.
func NewGraph() *Graph {
g := new(Graph)
g.adjacencyList = make(map[Vertex]map[Vertex]map[EdgeID]*ChannelInfo)
return g
}
// GetVertexCount returns number of vertexes in a graph.
func (g *Graph) GetVertexCount() int {
return len(g.adjacencyList)
}
// GetVertexes returns all vertexes in a graph.
func (g *Graph) GetVertexes() []Vertex {
IDs := make([]Vertex, 0, g.GetVertexCount())
for ID := range g.adjacencyList {
IDs = append(IDs, ID)
}
return IDs
}
// GetEdges return all edges in a graph.
// For undirected graph it returns each edge twice (for each direction)
// To get all edges in undirected graph use GetUndirectedEdges
func (g *Graph) GetEdges() []Edge {
edges := make([]Edge, 0)
for v1 := range g.adjacencyList {
for v2, multiedges := range g.adjacencyList[v1] {
for id, edge := range multiedges {
edges = append(edges, NewEdge(v1, v2, id, edge))
}
}
}
return edges
}
// GetUndirectedEdges returns all edges in an undirected graph.
func (g *Graph) GetUndirectedEdges() []Edge {
edges := make([]Edge, 0)
for v1 := range g.adjacencyList {
for v2, multiedges := range g.adjacencyList[v1] {
if v1.String() <= v2.String() {
for id, edge := range multiedges {
edges = append(edges, NewEdge(v1, v2, id, edge))
}
}
}
}
return edges
}
// HasVertex check if graph contain the given vertex.
func (g *Graph) HasVertex(v Vertex) bool {
_, ok := g.adjacencyList[v]
return ok
}
// HasEdge check if there is edge with a given EdgeID
// between two given vertexes.
func (g *Graph) HasEdge(v1, v2 Vertex, edgeID EdgeID) bool {
if _, ok := g.adjacencyList[v1]; ok {
if multiedges, ok := g.adjacencyList[v1][v2]; ok {
if _, ok := multiedges[edgeID]; ok {
return true
}
}
}
return false
}
// AddVertex adds vertex to a graph.
// If graph already contains this vertex it does nothing.
// Returns true if vertex previously doesnt't exist.
func (g *Graph) AddVertex(v Vertex) bool {
if g.HasVertex(v) {
return false
}
g.adjacencyList[v] = make(map[Vertex]map[EdgeID]*ChannelInfo)
return true
}
// RemoveVertex removes vertex from a graph
// If a graph already does not contain this vertex it does nothing
// Returns true if previously existed vertex got deleted
// BUG(mkl): does it correctly deletes edges with this vertex
func (g *Graph) RemoveVertex(v Vertex) bool {
if !g.HasVertex(v) {
return false
}
delete(g.adjacencyList, v)
return true
}
// AddEdge adds directed edge to the graph
// v1, v2 must exist. If they do not exist this function do nothing
// and return false. If edge with given vertexes and id already exists it
// gets overwritten
func (g *Graph) AddEdge(v1, v2 Vertex, edgeID EdgeID, info *ChannelInfo) bool {
if !g.HasVertex(v1) || !g.HasVertex(v2) {
return false
}
tmap := g.adjacencyList[v1]
if tmap[v2] == nil {
tmap[v2] = make(map[EdgeID]*ChannelInfo)
}
tmap[v2][edgeID] = info
return true
}
// AddUndirectedEdge adds an undirected edge to the graph.
// Vertexes should exists.
func (g *Graph) AddUndirectedEdge(v1, v2 Vertex, edgeID EdgeID, info *ChannelInfo) bool {
ok1 := g.AddEdge(v1, v2, edgeID, info)
ok2 := g.AddEdge(v2, v1, edgeID, info)
return ok1 && ok2
}
// ReplaceEdge replaces directed edge in the graph
func (g *Graph) ReplaceEdge(v1, v2 Vertex, edgeID EdgeID, info *ChannelInfo) bool {
if tmap, ok := g.adjacencyList[v1]; ok {
if _, ok := tmap[v2]; ok {
if _, ok := tmap[v2][edgeID]; ok {
tmap[v2][edgeID] = info
return true
}
}
}
return false
}
// ReplaceUndirectedEdge replaces undirected edge in the graph.
func (g *Graph) ReplaceUndirectedEdge(v1, v2 Vertex, edgeID EdgeID, info *ChannelInfo) bool {
ok1 := g.ReplaceEdge(v1, v2, edgeID, info)
ok2 := g.ReplaceEdge(v2, v1, edgeID, info)
return ok1 && ok2
}
// RemoveEdge removes directed edge in a graph.
func (g *Graph) RemoveEdge(v1, v2 Vertex, edgeID EdgeID) bool {
if _, ok := g.adjacencyList[v1]; ok {
if _, ok := g.adjacencyList[v1][v2]; ok {
tmap := g.adjacencyList[v1][v2]
if _, ok := tmap[edgeID]; ok {
delete(tmap, edgeID)
if len(tmap) == 0 {
delete(g.adjacencyList[v1], v2)
}
return true
}
}
}
return false
}
// RemoveUndirectedEdge removes undirected edge in a graph.
func (g *Graph) RemoveUndirectedEdge(v1, v2 Vertex, edgeID EdgeID) bool {
ok1 := g.RemoveEdge(v1, v2, edgeID)
ok2 := g.RemoveEdge(v2, v1, edgeID)
return ok1 && ok2
}
// GetInfo returns info about edge in a graph.
func (g *Graph) GetInfo(v1, v2 Vertex, edgeID EdgeID) (*ChannelInfo, error) {
if tmap, ok := g.adjacencyList[v1]; ok {
if _, ok := tmap[v2]; ok {
if _, ok := tmap[v2][edgeID]; ok {
return tmap[v2][edgeID], nil
}
}
}
return nil, EdgeNotFoundError
}
// GetNeighbors returns neighbors of a given vertex in a graph.
// Note: output should not be modified because it will change
// original graph
func (g *Graph) GetNeighbors(v Vertex) (map[Vertex]map[EdgeID]*ChannelInfo, error) {
if !g.HasVertex(v) {
return nil, NodeNotFoundError
}
return g.adjacencyList[v], nil
}
// MinCostChannel return channel with minimal weight between two vertexes
func (g *Graph) MinCostChannel(v1, v2 Vertex) (*ChannelInfo, error) {
if !g.HasVertex(v1) || !g.HasVertex(v2) {
return nil, NodeNotFoundError
}
if _, ok := g.adjacencyList[v1][v2]; !ok {
return nil, EdgeNotFoundError
}
wgt := math.MaxFloat64
var easiest *ChannelInfo
for _, edge := range g.adjacencyList[v1][v2] {
if edge.Wgt < wgt {
wgt, easiest = edge.Wgt, edge
}
}
return easiest, nil
}
// Bfs do breadth-first search starting from a given vertex
func (g *Graph) Bfs(source Vertex) (map[Vertex]int, map[Vertex]Vertex, error) {
return bfs(g, source, NilVertex)
}