lnd.xprv/routing/rt/rt.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

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
}