swarm/network: Comment NewPeerPotMap (and small bug fix)

This commit is contained in:
lash 2018-11-14 17:28:53 +01:00
parent d115a77707
commit 153beac174
3 changed files with 66 additions and 8 deletions

View file

@ -450,20 +450,39 @@ func (k *Kademlia) neighbourhoodDepth() (depth int) {
if k.conns.Size() <= k.MinProxBinSize { if k.conns.Size() <= k.MinProxBinSize {
return 0 return 0
} }
// total number of peers in iteration
var size int var size int
// true if iteration has all prox peers
var b bool var b bool
// last po recorded in iteration
var lastPo int var lastPo int
f := func(v pot.Val, i int) bool { f := func(v pot.Val, i int) bool {
size++ size++
// the actual depth of the farthest nn // this means we have all nn-peers.
// depth is by default set to the bin of the farthest nn-peer
if size == k.MinProxBinSize { if size == k.MinProxBinSize {
b = true b = true
depth = i depth = i
return true return true
} }
// if there are empty bins between farthest nn and current node, the depth should be the farthest of those empty bins // if there are empty bins between farthest nn and current node,
// the depth should recalculated to be
// the farthest of those empty bins
//
// 0 abac ccde
// 1 2a2a
// 2 589f <--- nearest non-nn
// 3 <--- don't count as empty bins
// 4 <--- don't count as empty bins
// ============ DEPTH 5 ===========
// 5 cbcb cdcd <---- furthest nn
// 6 a1a2 b3c4
if b && i < depth { if b && i < depth {
depth = i + 1 depth = i + 1
lastPo = i lastPo = i
@ -474,10 +493,12 @@ func (k *Kademlia) neighbourhoodDepth() (depth int) {
} }
k.conns.EachNeighbour(k.base, pof, f) k.conns.EachNeighbour(k.base, pof, f)
// cover edge case where more than one farthest nn and only proxpeers // cover edge case where more than one farthest nn
// AND we only have nn-peers
if lastPo == depth { if lastPo == depth {
depth = 0 depth = 0
} }
return depth return depth
} }
@ -607,6 +628,7 @@ type PeerPot struct {
// as hexadecimal representations of the address. // as hexadecimal representations of the address.
// used for testing only // used for testing only
func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot { func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot {
// create a table of all nodes for health check // create a table of all nodes for health check
np := pot.NewPot(nil, 0) np := pot.NewPot(nil, 0)
for _, addr := range addrs { for _, addr := range addrs {
@ -615,38 +637,65 @@ func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot {
ppmap := make(map[string]*PeerPot) ppmap := make(map[string]*PeerPot)
for i, a := range addrs { for i, a := range addrs {
// set to proxbin depth when all nn-peers are found
pl := 256 pl := 256
// next po in turn in iteration
prev := 256 prev := 256
// all bins outside proxbin depth with no peers
var emptyBins []int var emptyBins []int
// all nn-peers
var nns [][]byte var nns [][]byte
depthTraversed := false // any empty bins between furthest nn and nearest non-nn should not be counted as emptybins
// used to skip empty bins immediately after nn-peers
depthTraversed := false
np.EachNeighbour(addrs[i], pof, func(val pot.Val, po int) bool { np.EachNeighbour(addrs[i], pof, func(val pot.Val, po int) bool {
a := val.([]byte) a := val.([]byte)
// 256 is self. We don't care about ourselves
if po == 256 { if po == 256 {
return true return true
} }
// if first nn-peer or peer in same bin as last
if pl == 256 || pl == po { if pl == 256 || pl == po {
nns = append(nns, a) nns = append(nns, a)
} }
// all bins are filled
// start counting pl and set prev to
if pl == 256 && len(nns) >= kadMinProxSize { if pl == 256 && len(nns) >= kadMinProxSize {
pl = po pl = po
prev = po prev = po
} }
// only true starting from first peer after nn-peers
if prev < pl { if prev < pl {
if !depthTraversed { if depthTraversed {
depthTraversed = true
} else {
for j := prev; j > po; j-- { for j := prev; j > po; j-- {
emptyBins = append(emptyBins, j) emptyBins = append(emptyBins, j)
} }
} }
// after first peer after nn-peers, start counting emptybins
depthTraversed = true
} }
// expected po in next iteration if there are no empty bins inbetween
prev = po - 1 prev = po - 1
return true return true
}) })
// add any remaining bins between po 0 and the last po in iteration
// to the list of empty bins
for j := prev; j >= 0; j-- { for j := prev; j >= 0; j-- {
emptyBins = append(emptyBins, j) emptyBins = append(emptyBins, j)
} }
log.Trace(fmt.Sprintf("%x NNS: %s", addrs[i][:4], LogAddrs(nns))) log.Trace(fmt.Sprintf("%x NNS: %s", addrs[i][:4], LogAddrs(nns)))
ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins} ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins}
} }

View file

@ -76,6 +76,13 @@ func Register(k *Kademlia, regs ...string) {
} }
} }
// tests the validity of neighborhood depth calculations
//
// in particular, it tests that if there are one or more consequtive
// empty bins above the farthest "nearest neighbor-peer" then
// the depth should be set at the farthest of those empty bins
//
// TODO: Make test adapt to change in MinProxBinSize
func TestNeighbourhoodDepth(t *testing.T) { func TestNeighbourhoodDepth(t *testing.T) {
baseAddressBytes := RandomAddr().OAddr baseAddressBytes := RandomAddr().OAddr
kad := NewKademlia(baseAddressBytes, NewKadParams()) kad := NewKademlia(baseAddressBytes, NewKadParams())

View file

@ -34,7 +34,9 @@ import (
// all nodes have the their Kadmlias healthy. // all nodes have the their Kadmlias healthy.
func ExampleSimulation_WaitTillHealthy() { func ExampleSimulation_WaitTillHealthy() {
t.Skip("temporarily disabled as simuations.WaitTillHealthy cannot be trusted") log.Error("temporarily disabled as simuations.WaitTillHealthy cannot be trusted")
return
sim := simulation.New(map[string]simulation.ServiceFunc{ sim := simulation.New(map[string]simulation.ServiceFunc{
"bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
addr := network.NewAddr(ctx.Config.Node()) addr := network.NewAddr(ctx.Config.Node())