2018-07-30 20:25:18 +01:00
|
|
|
// Copyright (C) 2018 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package kademlia
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-08-09 20:20:39 +01:00
|
|
|
"encoding/binary"
|
2018-11-02 16:46:59 +00:00
|
|
|
"sort"
|
2018-08-13 09:39:45 +01:00
|
|
|
"time"
|
|
|
|
|
2018-11-20 18:29:07 +00:00
|
|
|
"github.com/gogo/protobuf/proto"
|
2018-07-30 20:25:18 +01:00
|
|
|
|
2018-11-30 13:40:13 +00:00
|
|
|
"storj.io/storj/pkg/pb"
|
2018-11-29 18:39:27 +00:00
|
|
|
"storj.io/storj/pkg/storj"
|
|
|
|
"storj.io/storj/pkg/utils"
|
2018-07-30 20:25:18 +01:00
|
|
|
"storj.io/storj/storage"
|
|
|
|
)
|
|
|
|
|
|
|
|
// addNode attempts to add a new contact to the routing table
|
|
|
|
// Requires node not already in table
|
2018-08-17 20:11:46 +01:00
|
|
|
// Returns true if node was added successfully
|
2018-09-18 05:39:06 +01:00
|
|
|
func (rt *RoutingTable) addNode(node *pb.Node) (bool, error) {
|
2018-07-30 20:25:18 +01:00
|
|
|
rt.mutex.Lock()
|
|
|
|
defer rt.mutex.Unlock()
|
2018-11-29 18:39:27 +00:00
|
|
|
nodeIDBytes := node.Id.Bytes()
|
|
|
|
|
|
|
|
if bytes.Equal(nodeIDBytes, rt.self.Id.Bytes()) {
|
2018-07-30 20:25:18 +01:00
|
|
|
err := rt.createOrUpdateKBucket(rt.createFirstBucketID(), time.Now())
|
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not create initial K bucket: %s", err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
err = rt.putNode(node)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not add initial node to nodeBucketDB: %s", err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
2018-08-17 20:11:46 +01:00
|
|
|
return true, nil
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
kadBucketID, err := rt.getKBucketID(node.Id)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not getKBucketID: %s", err)
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
2018-07-30 20:25:18 +01:00
|
|
|
hasRoom, err := rt.kadBucketHasRoom(kadBucketID)
|
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, err
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
containsLocal, err := rt.kadBucketContainsLocalNode(kadBucketID)
|
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, err
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
withinK, err := rt.nodeIsWithinNearestK(node.Id)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not determine if node is within k: %s", err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
for !hasRoom {
|
|
|
|
if containsLocal || withinK {
|
|
|
|
depth, err := rt.determineLeafDepth(kadBucketID)
|
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not determine leaf depth: %s", err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
kadBucketID = rt.splitBucket(kadBucketID, depth)
|
|
|
|
err = rt.createOrUpdateKBucket(kadBucketID, time.Now())
|
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not split and create K bucket: %s", err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
kadBucketID, err = rt.getKBucketID(node.Id)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not get k bucket Id within add node split bucket checks: %s", err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
hasRoom, err = rt.kadBucketHasRoom(kadBucketID)
|
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, err
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
containsLocal, err = rt.kadBucketContainsLocalNode(kadBucketID)
|
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, err
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2018-08-17 20:11:46 +01:00
|
|
|
rt.addToReplacementCache(kadBucketID, node)
|
|
|
|
return false, nil
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
err = rt.putNode(node)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not add node to nodeBucketDB: %s", err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
err = rt.createOrUpdateKBucket(kadBucketID, time.Now())
|
|
|
|
if err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return false, RoutingErr.New("could not create or update K bucket: %s", err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
2018-08-17 20:11:46 +01:00
|
|
|
return true, nil
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// updateNode will update the node information given that
|
|
|
|
// the node is already in the routing table.
|
2018-09-18 05:39:06 +01:00
|
|
|
func (rt *RoutingTable) updateNode(node *pb.Node) error {
|
2018-11-29 18:39:27 +00:00
|
|
|
if err := rt.putNode(node); err != nil {
|
2018-08-17 20:11:46 +01:00
|
|
|
return RoutingErr.New("could not update node: %v", err)
|
|
|
|
}
|
2018-07-30 20:25:18 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-08-17 20:11:46 +01:00
|
|
|
// removeNode will remove churned nodes and replace those entries with nodes from the replacement cache.
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) removeNode(nodeID storj.NodeID) error {
|
|
|
|
kadBucketID, err := rt.getKBucketID(nodeID)
|
|
|
|
if err != nil {
|
|
|
|
return RoutingErr.New("could not get k bucket %s", err)
|
|
|
|
}
|
|
|
|
_, err = rt.nodeBucketDB.Get(nodeID.Bytes())
|
2018-08-21 19:44:42 +01:00
|
|
|
if storage.ErrKeyNotFound.Has(err) {
|
|
|
|
return nil
|
|
|
|
} else if err != nil {
|
|
|
|
return RoutingErr.New("could not get node %s", err)
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
err = rt.nodeBucketDB.Delete(nodeID.Bytes())
|
2018-08-17 20:11:46 +01:00
|
|
|
if err != nil {
|
|
|
|
return RoutingErr.New("could not delete node %s", err)
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
nodes := rt.replacementCache[kadBucketID]
|
2018-08-17 20:11:46 +01:00
|
|
|
if len(nodes) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
err = rt.putNode(nodes[len(nodes)-1])
|
2018-08-17 20:11:46 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
rt.replacementCache[kadBucketID] = nodes[:len(nodes)-1]
|
2018-07-30 20:25:18 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
// putNode: helper, adds or updates Node and ID to nodeBucketDB
|
|
|
|
func (rt *RoutingTable) putNode(node *pb.Node) error {
|
|
|
|
v, err := proto.Marshal(node)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
2018-11-29 18:39:27 +00:00
|
|
|
return RoutingErr.Wrap(err)
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
err = rt.nodeBucketDB.Put(node.Id.Bytes(), v)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return RoutingErr.New("could not add key value pair to nodeBucketDB: %s", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// createOrUpdateKBucket: helper, adds or updates given kbucket
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) createOrUpdateKBucket(bID bucketID, now time.Time) error {
|
2018-08-09 20:20:39 +01:00
|
|
|
dateTime := make([]byte, binary.MaxVarintLen64)
|
|
|
|
binary.PutVarint(dateTime, now.UnixNano())
|
2018-11-29 18:39:27 +00:00
|
|
|
err := rt.kadBucketDB.Put(bID[:], dateTime)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return RoutingErr.New("could not add or update k bucket: %s", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-08-09 20:20:39 +01:00
|
|
|
// getKBucketID: helper, returns the id of the corresponding k bucket given a node id.
|
|
|
|
// The node doesn't have to be in the routing table at time of search
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) getKBucketID(nodeID storj.NodeID) (bucketID, error) {
|
2018-07-30 20:25:18 +01:00
|
|
|
kadBucketIDs, err := rt.kadBucketDB.List(nil, 0)
|
|
|
|
if err != nil {
|
2018-11-29 18:39:27 +00:00
|
|
|
return bucketID{}, RoutingErr.New("could not list all k bucket ids: %s", err)
|
|
|
|
}
|
|
|
|
var keys []bucketID
|
|
|
|
keys = append(keys, bucketID{})
|
|
|
|
for _, k := range kadBucketIDs {
|
|
|
|
keys = append(keys, keyToBucketID(k))
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < len(keys)-1; i++ {
|
2018-11-29 18:39:27 +00:00
|
|
|
if bytes.Compare(nodeID.Bytes(), keys[i][:]) > 0 && bytes.Compare(nodeID.Bytes(), keys[i+1][:]) <= 0 {
|
2018-07-30 20:25:18 +01:00
|
|
|
return keys[i+1], nil
|
|
|
|
}
|
|
|
|
}
|
2018-11-20 16:54:52 +00:00
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
// shouldn't happen BUT return error if no matching kbucket...
|
|
|
|
return bucketID{}, RoutingErr.New("could not find k bucket")
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
2018-11-02 16:46:59 +00:00
|
|
|
// compareByXor compares left, right xorred by reference
|
|
|
|
func compareByXor(left, right, reference storage.Key) int {
|
|
|
|
n := len(reference)
|
|
|
|
if n > len(left) {
|
|
|
|
n = len(left)
|
|
|
|
}
|
|
|
|
if n > len(right) {
|
|
|
|
n = len(right)
|
|
|
|
}
|
|
|
|
left = left[:n]
|
|
|
|
right = right[:n]
|
|
|
|
reference = reference[:n]
|
|
|
|
|
|
|
|
for i, r := range reference {
|
|
|
|
a, b := left[i]^r, right[i]^r
|
|
|
|
if a != b {
|
|
|
|
if a < b {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return 1
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
}
|
2018-11-02 16:46:59 +00:00
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func sortByXOR(nodeIDs storage.Keys, ref storage.Key) {
|
|
|
|
sort.Slice(nodeIDs, func(i, k int) bool {
|
|
|
|
return compareByXor(nodeIDs[i], nodeIDs[k], ref) < 0
|
|
|
|
})
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
func nodeIDsToKeys(ids storj.NodeIDList) (nodeIDKeys storage.Keys) {
|
|
|
|
for _, n := range ids {
|
|
|
|
nodeIDKeys = append(nodeIDKeys, n.Bytes())
|
|
|
|
}
|
|
|
|
return nodeIDKeys
|
|
|
|
}
|
|
|
|
|
|
|
|
func keysToNodeIDs(keys storage.Keys) (ids storj.NodeIDList, err error) {
|
|
|
|
var idErrs []error
|
|
|
|
for _, k := range keys {
|
|
|
|
id, err := storj.NodeIDFromBytes(k[:])
|
|
|
|
if err != nil {
|
|
|
|
idErrs = append(idErrs, err)
|
|
|
|
}
|
|
|
|
ids = append(ids, id)
|
|
|
|
}
|
|
|
|
if err := utils.CombineErrors(idErrs...); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ids, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func keyToBucketID(key storage.Key) (bID bucketID) {
|
|
|
|
copy(bID[:], key)
|
|
|
|
return bID
|
|
|
|
}
|
|
|
|
|
2018-07-30 20:25:18 +01:00
|
|
|
// determineFurthestIDWithinK: helper, determines the furthest node within the k closest to local node
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) determineFurthestIDWithinK(nodeIDs storj.NodeIDList) (storj.NodeID, error) {
|
|
|
|
nodeIDKeys := nodeIDsToKeys(nodeIDs)
|
|
|
|
sortByXOR(nodeIDKeys, rt.self.Id.Bytes())
|
2018-11-02 16:46:59 +00:00
|
|
|
if len(nodeIDs) < rt.bucketSize+1 { //adding 1 since we're not including local node in closest k
|
2018-11-29 18:39:27 +00:00
|
|
|
return storj.NodeIDFromBytes(nodeIDKeys[len(nodeIDKeys)-1])
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
return storj.NodeIDFromBytes(nodeIDKeys[rt.bucketSize])
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// xorTwoIds: helper, finds the xor distance between two byte slices
|
2018-11-29 18:39:27 +00:00
|
|
|
func xorTwoIds(id, comparisonID []byte) []byte {
|
2018-07-30 20:25:18 +01:00
|
|
|
var xorArr []byte
|
2018-10-08 16:09:37 +01:00
|
|
|
s := len(id)
|
|
|
|
if s > len(comparisonID) {
|
|
|
|
s = len(comparisonID)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < s; i++ {
|
2018-07-30 20:25:18 +01:00
|
|
|
xor := id[i] ^ comparisonID[i]
|
|
|
|
xorArr = append(xorArr, xor)
|
|
|
|
}
|
|
|
|
return xorArr
|
|
|
|
}
|
|
|
|
|
|
|
|
// nodeIsWithinNearestK: helper, returns true if the node in question is within the nearest k from local node
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) nodeIsWithinNearestK(nodeID storj.NodeID) (bool, error) {
|
|
|
|
nodeKeys, err := rt.nodeBucketDB.List(nil, 0)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return false, RoutingErr.New("could not get nodes: %s", err)
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
nodeCount := len(nodeKeys)
|
2018-07-30 20:25:18 +01:00
|
|
|
if nodeCount < rt.bucketSize+1 { //adding 1 since we're not including local node in closest k
|
|
|
|
return true, nil
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
nodeIDs, err := keysToNodeIDs(nodeKeys)
|
|
|
|
if err != nil {
|
|
|
|
return false, RoutingErr.Wrap(err)
|
|
|
|
}
|
|
|
|
furthestIDWithinK, err := rt.determineFurthestIDWithinK(nodeIDs)
|
2018-08-09 20:20:39 +01:00
|
|
|
if err != nil {
|
|
|
|
return false, RoutingErr.New("could not determine furthest id within k: %s", err)
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
existingXor := xorTwoIds(furthestIDWithinK.Bytes(), rt.self.Id.Bytes())
|
|
|
|
newXor := xorTwoIds(nodeID.Bytes(), rt.self.Id.Bytes())
|
2018-07-30 20:25:18 +01:00
|
|
|
if bytes.Compare(newXor, existingXor) < 0 {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// kadBucketContainsLocalNode returns true if the kbucket in question contains the local node
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) kadBucketContainsLocalNode(queryID bucketID) (bool, error) {
|
|
|
|
bID, err := rt.getKBucketID(rt.self.Id)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
return bytes.Equal(queryID[:], bID[:]), nil
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// kadBucketHasRoom: helper, returns true if it has fewer than k nodes
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) kadBucketHasRoom(bID bucketID) (bool, error) {
|
|
|
|
nodes, err := rt.getNodeIDsWithinKBucket(bID)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
if len(nodes) < rt.bucketSize {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// getNodeIDsWithinKBucket: helper, returns a collection of all the node ids contained within the kbucket
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) getNodeIDsWithinKBucket(bID bucketID) (storj.NodeIDList, error) {
|
|
|
|
endpoints, err := rt.getKBucketRange(bID)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
left := endpoints[0]
|
|
|
|
right := endpoints[1]
|
2018-11-29 18:39:27 +00:00
|
|
|
var nodeIDsBytes [][]byte
|
|
|
|
allNodeIDsBytes, err := rt.nodeBucketDB.List(nil, 0)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, RoutingErr.New("could not list nodes %s", err)
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
for _, v := range allNodeIDsBytes {
|
|
|
|
if (bytes.Compare(v, left[:]) > 0) && (bytes.Compare(v, right[:]) <= 0) {
|
|
|
|
nodeIDsBytes = append(nodeIDsBytes, v)
|
|
|
|
if len(nodeIDsBytes) == rt.bucketSize {
|
2018-07-30 20:25:18 +01:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
nodeIDs, err := storj.NodeIDsFromBytes(nodeIDsBytes)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(nodeIDsBytes) > 0 {
|
2018-07-30 20:25:18 +01:00
|
|
|
return nodeIDs, nil
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
// getNodesFromIDsBytes: helper, returns array of encoded nodes from node ids
|
|
|
|
func (rt *RoutingTable) getNodesFromIDsBytes(nodeIDs storj.NodeIDList) ([]*pb.Node, error) {
|
|
|
|
var marshaledNodes []storage.Value
|
2018-08-09 20:20:39 +01:00
|
|
|
for _, v := range nodeIDs {
|
2018-11-29 18:39:27 +00:00
|
|
|
n, err := rt.nodeBucketDB.Get(v.Bytes())
|
2018-08-09 20:20:39 +01:00
|
|
|
if err != nil {
|
2018-11-29 18:39:27 +00:00
|
|
|
return nil, RoutingErr.New("could not get node id %v, %s", v, err)
|
2018-08-09 20:20:39 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
marshaledNodes = append(marshaledNodes, n)
|
2018-08-09 20:20:39 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
return unmarshalNodes(marshaledNodes)
|
2018-08-09 20:20:39 +01:00
|
|
|
}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
// unmarshalNodes: helper, returns slice of reconstructed node pointers given a map of nodeIDs:serialized nodes
|
2018-11-29 18:39:27 +00:00
|
|
|
func unmarshalNodes(nodes []storage.Value) ([]*pb.Node, error) {
|
2018-09-18 05:39:06 +01:00
|
|
|
var unmarshaled []*pb.Node
|
2018-11-29 18:39:27 +00:00
|
|
|
for _, n := range nodes {
|
2018-09-18 05:39:06 +01:00
|
|
|
node := &pb.Node{}
|
|
|
|
err := proto.Unmarshal(n, node)
|
2018-08-09 20:20:39 +01:00
|
|
|
if err != nil {
|
|
|
|
return unmarshaled, RoutingErr.New("could not unmarshal node %s", err)
|
|
|
|
}
|
|
|
|
unmarshaled = append(unmarshaled, node)
|
|
|
|
}
|
|
|
|
return unmarshaled, nil
|
|
|
|
}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
// getUnmarshaledNodesFromBucket: helper, gets nodes within kbucket
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) getUnmarshaledNodesFromBucket(bID bucketID) ([]*pb.Node, error) {
|
|
|
|
nodeIDsBytes, err := rt.getNodeIDsWithinKBucket(bID)
|
2018-08-09 20:20:39 +01:00
|
|
|
if err != nil {
|
2018-09-18 05:39:06 +01:00
|
|
|
return []*pb.Node{}, RoutingErr.New("could not get nodeIds within kbucket %s", err)
|
2018-08-09 20:20:39 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
nodes, err := rt.getNodesFromIDsBytes(nodeIDsBytes)
|
2018-08-09 20:20:39 +01:00
|
|
|
if err != nil {
|
2018-09-18 05:39:06 +01:00
|
|
|
return []*pb.Node{}, RoutingErr.New("could not get node values %s", err)
|
2018-08-09 20:20:39 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
return nodes, nil
|
2018-08-09 20:20:39 +01:00
|
|
|
}
|
|
|
|
|
2018-07-30 20:25:18 +01:00
|
|
|
// getKBucketRange: helper, returns the left and right endpoints of the range of node ids contained within the bucket
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) getKBucketRange(bID bucketID) ([]bucketID, error) {
|
|
|
|
kadIDs, err := rt.kadBucketDB.ReverseList(bID[:], 2)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, RoutingErr.New("could not reverse list k bucket ids %s", err)
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
coords := make([]bucketID, 2)
|
2018-07-30 20:25:18 +01:00
|
|
|
if len(kadIDs) < 2 {
|
2018-11-29 18:39:27 +00:00
|
|
|
coords[0] = bucketID{}
|
2018-07-30 20:25:18 +01:00
|
|
|
} else {
|
2018-11-29 18:39:27 +00:00
|
|
|
copy(coords[0][:], kadIDs[1])
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
copy(coords[1][:], kadIDs[0])
|
2018-07-30 20:25:18 +01:00
|
|
|
return coords, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// createFirstBucketID creates byte slice representing 11..11
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) createFirstBucketID() bucketID {
|
|
|
|
var id bucketID
|
2018-07-30 20:25:18 +01:00
|
|
|
x := byte(255)
|
2018-11-29 18:39:27 +00:00
|
|
|
for i := 0; i < len(id); i++ {
|
|
|
|
id[i] = x
|
2018-07-30 20:25:18 +01:00
|
|
|
}
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
|
|
|
// determineLeafDepth determines the level of the bucket id in question.
|
|
|
|
// Eg level 0 means there is only 1 bucket, level 1 means the bucket has been split once, and so on
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) determineLeafDepth(bID bucketID) (int, error) {
|
|
|
|
bucketRange, err := rt.getKBucketRange(bID)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return -1, RoutingErr.New("could not get k bucket range %s", err)
|
|
|
|
}
|
|
|
|
smaller := bucketRange[0]
|
2018-11-29 18:39:27 +00:00
|
|
|
diffBit, err := rt.determineDifferingBitIndex(bID, smaller)
|
2018-07-30 20:25:18 +01:00
|
|
|
if err != nil {
|
|
|
|
return diffBit + 1, RoutingErr.New("could not determine differing bit %s", err)
|
|
|
|
}
|
|
|
|
return diffBit + 1, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// determineDifferingBitIndex: helper, returns the last bit differs starting from prefix to suffix
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) determineDifferingBitIndex(bID, comparisonID bucketID) (int, error) {
|
|
|
|
if bytes.Equal(bID[:], comparisonID[:]) {
|
2018-07-30 20:25:18 +01:00
|
|
|
return -2, RoutingErr.New("compared two equivalent k bucket ids")
|
|
|
|
}
|
2018-11-29 18:39:27 +00:00
|
|
|
emptyBID := bucketID{}
|
|
|
|
if bytes.Equal(comparisonID[:], emptyBID[:]) {
|
2018-07-30 20:25:18 +01:00
|
|
|
comparisonID = rt.createFirstBucketID()
|
|
|
|
}
|
|
|
|
|
|
|
|
var differingByteIndex int
|
|
|
|
var differingByteXor byte
|
2018-11-29 18:39:27 +00:00
|
|
|
xorArr := xorTwoIds(bID[:], comparisonID[:])
|
2018-07-30 20:25:18 +01:00
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
firstBID := rt.createFirstBucketID()
|
|
|
|
if bytes.Equal(xorArr, firstBID[:]) {
|
2018-07-30 20:25:18 +01:00
|
|
|
return -1, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for j, v := range xorArr {
|
|
|
|
if v != byte(0) {
|
|
|
|
differingByteIndex = j
|
|
|
|
differingByteXor = v
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
h := 0
|
|
|
|
for ; h < 8; h++ {
|
|
|
|
toggle := byte(1 << uint(h))
|
|
|
|
tempXor := differingByteXor
|
|
|
|
tempXor ^= toggle
|
|
|
|
if tempXor < differingByteXor {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
bitInByteIndex := 7 - h
|
|
|
|
byteIndex := differingByteIndex
|
|
|
|
bitIndex := byteIndex*8 + bitInByteIndex
|
|
|
|
|
|
|
|
return bitIndex, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// splitBucket: helper, returns the smaller of the two new bucket ids
|
|
|
|
// the original bucket id becomes the greater of the 2 new
|
2018-11-29 18:39:27 +00:00
|
|
|
func (rt *RoutingTable) splitBucket(bID bucketID, depth int) bucketID {
|
|
|
|
var newID bucketID
|
|
|
|
copy(newID[:], bID[:])
|
|
|
|
byteIndex := depth / 8
|
|
|
|
bitInByteIndex := 7 - (depth % 8)
|
2018-07-30 20:25:18 +01:00
|
|
|
toggle := byte(1 << uint(bitInByteIndex))
|
|
|
|
newID[byteIndex] ^= toggle
|
|
|
|
return newID
|
|
|
|
}
|