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)
|
||
|
}
|