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
358 lines
9.0 KiB
Go
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)
|
|
}
|