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
258 lines
7.1 KiB
Go
258 lines
7.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 rt
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/lightningnetwork/lnd/routing/rt/graph"
|
|
)
|
|
|
|
type OperationType byte
|
|
const (
|
|
AddChannelOP OperationType = iota
|
|
RemoveChannelOp
|
|
)
|
|
|
|
// String returns string representation
|
|
func (t OperationType) String()string {
|
|
switch t {
|
|
case AddChannelOP:
|
|
return "<ADD_CHANNEL>"
|
|
case RemoveChannelOp:
|
|
return "<REMOVE_CHANNEL>"
|
|
default:
|
|
return "<UNKNOWN_TYPE>"
|
|
}
|
|
}
|
|
|
|
// ChannelOperation represent operation on a graph
|
|
// Such as add edge or remove edge
|
|
type ChannelOperation struct {
|
|
graph.Edge
|
|
Operation OperationType // One of ADD_CHANNEL, REMOVE_CHANNEL
|
|
}
|
|
|
|
// NewChannelOperation returns new ChannelOperation
|
|
func NewChannelOperation(src, tgt graph.Vertex, id graph.EdgeID, info *graph.ChannelInfo, opType OperationType) ChannelOperation{
|
|
return ChannelOperation{
|
|
Edge: graph.Edge{
|
|
Src: src,
|
|
Tgt: tgt,
|
|
Id: id,
|
|
Info: info.Copy(),
|
|
},
|
|
Operation: opType,
|
|
}
|
|
}
|
|
|
|
// String return string representation
|
|
func (c ChannelOperation) String () string {
|
|
return fmt.Sprintf(
|
|
"ChannelOperation[%v %v %v %v %v]",
|
|
c.Src,
|
|
c.Tgt,
|
|
c.Id,
|
|
c.Info,
|
|
c.Operation,
|
|
)
|
|
}
|
|
|
|
// Copy returns copy of ChannelOperation
|
|
func (op *ChannelOperation) Copy() ChannelOperation {
|
|
return ChannelOperation{
|
|
Edge: graph.Edge{
|
|
Src: op.Src,
|
|
Tgt: op.Tgt,
|
|
Id: op.Id,
|
|
Info: op.Info.Copy(),
|
|
},
|
|
Operation: op.Operation,
|
|
}
|
|
}
|
|
|
|
// DifferenceBuffer represent multiple changes in a graph
|
|
// such as adding or deleting edges
|
|
type DifferenceBuffer []ChannelOperation
|
|
|
|
// String returns string representation
|
|
func (d DifferenceBuffer) String() string {
|
|
s := ""
|
|
for i:=0; i<len(d); i++ {
|
|
s += fmt.Sprintf(" %v\n", d[i])
|
|
}
|
|
s1 := ""
|
|
if len(d) > 0 {
|
|
s1 = "\n"
|
|
}
|
|
return fmt.Sprintf("DifferenceBuffer[%v%v]", s1, s)
|
|
}
|
|
|
|
// NewDifferenceBuffer create new empty DifferenceBuffer
|
|
func NewDifferenceBuffer() *DifferenceBuffer {
|
|
d := make(DifferenceBuffer, 0)
|
|
return &d
|
|
}
|
|
|
|
// IsEmpty checks if buffer is empty(contains no operations in it)
|
|
func (diffBuff *DifferenceBuffer) IsEmpty() bool {
|
|
return len(*diffBuff) == 0
|
|
}
|
|
|
|
// Clear deletes all operations from DifferenceBuffer making it empty
|
|
func (diffBuff *DifferenceBuffer) Clear() {
|
|
*diffBuff = make([]ChannelOperation, 0)
|
|
}
|
|
|
|
// Copy create copy of a DifferenceBuffer
|
|
func (diffBuff *DifferenceBuffer) Copy() *DifferenceBuffer {
|
|
d := make([]ChannelOperation, 0, len(*diffBuff))
|
|
for _, op := range *diffBuff {
|
|
d = append(d, op.Copy())
|
|
}
|
|
return (*DifferenceBuffer)(&d)
|
|
}
|
|
|
|
// RoutingTable represent information about graph and neighbors
|
|
// TODO(mkl): better doc
|
|
// Methods of this struct is not thread safe
|
|
type RoutingTable struct {
|
|
// Contains node's view of lightning network
|
|
G *graph.Graph
|
|
// Contains changes to send to a different neighbors
|
|
// Changing RT modifies DifferenceBuffer
|
|
diff []*DifferenceBuffer
|
|
}
|
|
|
|
// ShortestPath find shortest path between two node in routing table
|
|
func (rt *RoutingTable) ShortestPath(src, dst graph.Vertex) ([]graph.Vertex, error) {
|
|
return graph.ShortestPath(rt.G, src, dst)
|
|
}
|
|
|
|
// NewRoutingTable creates new empty routing table
|
|
func NewRoutingTable() *RoutingTable {
|
|
return &RoutingTable{
|
|
G: graph.NewGraph(),
|
|
diff: make([]*DifferenceBuffer, 0),
|
|
}
|
|
}
|
|
|
|
// AddNodes add multiple nodes to the routing table
|
|
func (rt *RoutingTable) AddNodes(IDs ...graph.Vertex) {
|
|
for _, ID := range IDs {
|
|
rt.G.AddVertex(ID)
|
|
}
|
|
}
|
|
|
|
// AddChannel adds channel to the routing table.
|
|
// It will add nodes if they are not present in RT.
|
|
// It will update all difference buffers
|
|
func (rt *RoutingTable) AddChannel(Node1, Node2 graph.Vertex, edgeID graph.EdgeID, info *graph.ChannelInfo) {
|
|
rt.AddNodes(Node1, Node2)
|
|
if !rt.HasChannel(Node1, Node2, edgeID) {
|
|
rt.G.AddUndirectedEdge(Node1, Node2, edgeID, info)
|
|
for _, diffBuff := range rt.diff {
|
|
*diffBuff = append(*diffBuff, NewChannelOperation(Node1, Node2, edgeID, info, AddChannelOP))
|
|
}
|
|
}
|
|
}
|
|
|
|
// HasChannel check if channel between two nodes exist in routing table
|
|
func (rt *RoutingTable) HasChannel(node1, node2 graph.Vertex, edgeID graph.EdgeID) bool {
|
|
return rt.G.HasEdge(node1, node2, edgeID)
|
|
}
|
|
|
|
// RemoveChannel removes channel from the routing table.
|
|
// It will do nothing if channel does not exist in RT.
|
|
// It will update all difference buffers
|
|
func (rt *RoutingTable) RemoveChannel(Node1, Node2 graph.Vertex, edgeID graph.EdgeID) {
|
|
if rt.HasChannel(Node1, Node2, edgeID) {
|
|
rt.G.RemoveUndirectedEdge(Node1, Node2, edgeID)
|
|
for _, diffBuff := range rt.diff {
|
|
*diffBuff = append(*diffBuff, NewChannelOperation(Node1, Node2, edgeID, nil, RemoveChannelOp))
|
|
}
|
|
}
|
|
}
|
|
|
|
// NewDiffBuff create a new difference buffer in a routing table
|
|
func (rt *RoutingTable) NewDiffBuff() *DifferenceBuffer {
|
|
buff := NewDifferenceBuffer()
|
|
rt.diff = append(rt.diff, buff)
|
|
return buff
|
|
}
|
|
|
|
// ApplyDiffBuff applies difference buffer to the routing table.
|
|
// It will modify RoutingTable's difference buffers.
|
|
func (rt *RoutingTable) ApplyDiffBuff(diffBuff *DifferenceBuffer) {
|
|
for _, op := range *diffBuff {
|
|
if op.Operation == AddChannelOP {
|
|
rt.AddChannel(op.Src, op.Tgt, op.Id, op.Info)
|
|
} else if op.Operation == RemoveChannelOp {
|
|
rt.RemoveChannel(op.Src, op.Tgt, op.Id)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Nodes return all nodes from routing table
|
|
func (rt *RoutingTable) Nodes() []graph.Vertex {
|
|
return rt.G.GetVertexes()
|
|
}
|
|
|
|
// NumberOfNodes returns number of nodes in routing table
|
|
func (rt *RoutingTable) NumberOfNodes() int {
|
|
return rt.G.GetVertexCount()
|
|
}
|
|
|
|
// AllChannels returns all channels from routing table
|
|
func (rt *RoutingTable) AllChannels() []graph.Edge {
|
|
edges := rt.G.GetUndirectedEdges()
|
|
return edges
|
|
}
|
|
|
|
// AddTable adds other RoutingTable.
|
|
// Resulting table contains channels, nodes from both tables.
|
|
func (rt *RoutingTable) AddTable(rt1 *RoutingTable) {
|
|
newChannels := rt1.AllChannels()
|
|
for _, channel := range newChannels {
|
|
rt.AddChannel(channel.Src, channel.Tgt, channel.Id, channel.Info.Copy())
|
|
}
|
|
}
|
|
|
|
// Copy - creates a copy of RoutingTable
|
|
// It makes deep copy of routing table.
|
|
// Note: difference buffers are not copied!
|
|
func (rt *RoutingTable) Copy() *RoutingTable {
|
|
// TODO: add tests
|
|
channels := rt.AllChannels()
|
|
newRT := NewRoutingTable()
|
|
newRT.AddNodes(rt.Nodes()...)
|
|
for _, channel := range channels {
|
|
newRT.AddChannel(channel.Src, channel.Tgt, channel.Id, channel.Info.Copy())
|
|
}
|
|
return newRT
|
|
}
|
|
|
|
// String returns string representation of routing table
|
|
func (rt *RoutingTable) String() string {
|
|
rez := ""
|
|
edges := rt.G.GetUndirectedEdges()
|
|
for _, edge := range edges {
|
|
rez += fmt.Sprintf("%v %v %v", edge.Src, edge.Tgt, edge.Info)
|
|
}
|
|
return rez
|
|
}
|
|
|
|
// Find k-shortest path between source and destination
|
|
func (rt *RoutingTable) KShortestPaths(src, dst graph.Vertex, k int) ([][]graph.Vertex, error) {
|
|
return graph.KShortestPaths(rt.G, src, dst, k)
|
|
}
|
|
|
|
// Returns copy of channel info for channel in routing table
|
|
func (rt *RoutingTable) GetChannelInfo(id1, id2 graph.Vertex, edgeId graph.EdgeID) (*graph.ChannelInfo, error) {
|
|
info, err := rt.G.GetInfo(id1, id2, edgeId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return info.Copy(), nil
|
|
} |