swarm/network: WIP Create Healthy assertion tests

This commit is contained in:
lash 2018-12-17 20:45:05 +01:00
parent 2990503d89
commit cbf6d77a7f
4 changed files with 102 additions and 22 deletions

View file

@ -17,6 +17,7 @@
package network
import (
"bytes"
"fmt"
"sync"
"time"
@ -248,17 +249,27 @@ func (h *Hive) savePeers() error {
// It evaluates the healthiness based on the addresses passed as argument
// in relation to the base address of the hive instance the method is called on
func (h *Hive) Healthy(addrs [][]byte) *Health {
k := NewKademlia(h.BaseAddr(), NewKadParams())
//k := NewKademlia(h.BaseAddr(), NewKadParams())
pivotK := *h.Kademlia
kads := []*Kademlia{&pivotK}
for _, a := range addrs {
p := &Peer{
BzzPeer: &BzzPeer{
BzzAddr: &BzzAddr{
OAddr: a,
},
},
if bytes.Equal(a, h.BaseAddr()) {
continue
}
k.On(p)
kads = append(kads, NewKademlia(a, kadParamsFromInstance(h.Kademlia)))
}
pp := NewPeerPotMap([]*Kademlia{k})
pp := NewPeerPotMap(kads)
return pp[common.Bytes2Hex(h.BaseAddr())].Healthy()
}
func kadParamsFromInstance(k *Kademlia) *KadParams {
return &KadParams{
MaxProxDisplay: k.MaxProxDisplay,
MinProxBinSize: k.MinProxBinSize,
MinBinSize: k.MinBinSize,
MaxBinSize: k.MaxBinSize,
RetryInterval: k.RetryInterval,
RetryExponent: k.RetryExponent,
MaxRetries: k.MaxRetries,
}
}

View file

@ -411,7 +411,7 @@ func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int, bool) bool) {
}
// EachAddr called with (base, po, f) is an iterator applying f to each known peer
// that has proximity order po or less as measured from the base
// that has proximity order o or less as measured from the base
// if base is nil, kademlia base address is used
// It returns peers in order deepest to shallowest
func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) {
@ -444,6 +444,7 @@ func (k *Kademlia) NeighbourhoodDepth() (depth int) {
// if there is altogether less than MinProxBinSize peers it returns 0
// caller must hold the lock
func depthForPot(p *pot.Pot, minProxBinSize int, pivotAddr []byte) (depth int) {
log.Trace("pivot", "a", pivotAddr)
if p.Size() <= minProxBinSize {
return 0
}
@ -470,7 +471,8 @@ func depthForPot(p *pot.Pot, minProxBinSize int, pivotAddr []byte) (depth int) {
}
p.EachNeighbour(pivotAddr, Pof, f)
p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, _ func(func(pot.Val, int) bool) bool) bool {
p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val, int) bool) bool) bool {
log.Trace("eachbin", "addr", pivotAddr, "po", po)
if po == depth {
if maxDepth == depth {
return false
@ -629,8 +631,8 @@ func NewPeerPotMap(kads []*Kademlia) map[string]*PeerPot {
a := k.base
// actual kademlia depth
depth := depthForPot(np, k.MinProxBinSize, a)
depth := depthForPot(k.addrs, k.MinProxBinSize, a)
log.Trace("potmap", "k", k.BaseAddr(), "depth", depth)
// all nn-peers
var nns [][]byte
@ -652,7 +654,7 @@ func NewPeerPotMap(kads []*Kademlia) map[string]*PeerPot {
return false
})
log.Trace(fmt.Sprintf("%x NNS: %s", kads[i].base[:4], LogAddrs(nns)))
log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s", kads[i].base[:4], LogAddrs(nns)))
ppmap[common.Bytes2Hex(a)] = &PeerPot{
Kademlia: k,
NNSet: nns,
@ -692,6 +694,7 @@ func (o *PeerPot) knowNeighbours() (got bool, n int, missing [][]byte) {
// all bins (except self) are included (0 <= bin <= 255)
depth := depthForPot(o.addrs, o.MinProxBinSize, o.base)
o.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool {
log.Info("eachaddr", "depth", depth, "po", po)
if po < depth {
return false
}
@ -711,7 +714,7 @@ func (o *PeerPot) knowNeighbours() (got bool, n int, missing [][]byte) {
if pm[pk] {
gots++
} else {
log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", o.base, pk)) //(o.BaseAddr()[:4], pk[:8]))
log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", o.base, pk))
culprits = append(culprits, p)
}
}

View file

@ -41,12 +41,17 @@ func testKadPeerAddr(s string) *BzzAddr {
return &BzzAddr{OAddr: a, UAddr: a}
}
func newTestKademlia(b string) *Kademlia {
func newTestKademliaParams() *KadParams {
params := NewKadParams()
// TODO why is this 1?
params.MinBinSize = 1
params.MinProxBinSize = 2
return params
}
func newTestKademlia(b string) *Kademlia {
base := pot.NewAddressFromString(b)
return NewKademlia(base, params)
return NewKademlia(base, newTestKademliaParams())
}
func newTestKadPeer(k *Kademlia, s string, lightNode bool) *Peer {
@ -157,6 +162,58 @@ func TestNeighbourhoodDepth(t *testing.T) {
testNum++
}
func TestHealth(t *testing.T) {
k := newTestKademlia("00000000")
assertHealth(t, k, false)
Register(k, "00001000")
log.Trace(k.String())
assertHealth(t, k, false)
On(k, "00001000")
assertHealth(t, k, true)
Register(k, "00000100")
log.Trace(k.String())
assertHealth(t, k, false)
On(k, "00000100")
assertHealth(t, k, true)
Register(k, "10000000")
log.Trace(k.String())
assertHealth(t, k, false)
On(k, "10000000")
assertHealth(t, k, true)
Register(k, "00100000")
log.Trace(k.String())
assertHealth(t, k, false)
On(k, "00100000")
assertHealth(t, k, true)
Register(k, "01000000")
log.Trace(k.String())
assertHealth(t, k, false)
On(k, "01000000")
assertHealth(t, k, true)
}
func assertHealth(t *testing.T, k *Kademlia, expectHealthy bool) {
kid := common.Bytes2Hex(k.BaseAddr())
kads := []*Kademlia{k}
k.EachAddr(nil, 255, func(addr *BzzAddr, po int, _ bool) bool {
kads = append(kads, NewKademlia(addr.Address(), newTestKademliaParams()))
return true
})
pp := NewPeerPotMap(kads)
log.Trace("set", "pp", pp[kid].NNSet)
healthParams := pp[kid].Healthy()
// definition of health, all conditions but be true:
// - we at least know one peer
// - we know all neighbors
// - we are connected to all known neighbors
health := healthParams.KnowNN && healthParams.GotNN && healthParams.CountKnowNN > 0
if expectHealthy != health {
t.Fatalf("expected kademlia health %v, is %v\n%v", expectHealthy, health, k.String())
}
}
func testSuggestPeer(k *Kademlia, expAddr string, expPo int, expWant bool) error {
addr, o, want := k.SuggestPeer()
log.Trace("suggestpeer return", "a", addr, "o", o, "want", want)
@ -179,6 +236,7 @@ func binStr(a *BzzAddr) string {
return pot.ToBin(a.Address())[:8]
}
// TODO explain why this bug occurred and how it should have been mitigated
func TestSuggestPeerBug(t *testing.T) {
// 2 row gap, unsaturated proxbin, no callables -> want PO 0
k := newTestKademlia("00000000")
@ -557,7 +615,7 @@ func testKademliaCase(t *testing.T, pivotAddr string, addrs ...string) {
}
h := pp.Healthy()
if !(h.GotNN && h.KnowNN) {
if !(h.GotNN && h.KnowNN && h.CountKnowNN > 0) {
t.Fatalf("not healthy: %#v\n%v", h, k.String())
}
}

View file

@ -31,6 +31,7 @@ import (
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
@ -285,7 +286,7 @@ func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simul
if err := client.Call(&healthy, "hive_healthy", addrs); err != nil {
return false, fmt.Errorf("error getting node health: %s", err)
}
log.Debug(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v,\n\n%v", id, healthy.GotNN, healthy.KnowNN, healthy.Hive))
log.Info(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v,\n\n%v", id, healthy.GotNN, healthy.KnowNN, healthy.Hive))
return healthy.KnowNN && healthy.GotNN, nil
}
@ -399,13 +400,20 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt
}
healthy := &network.Health{}
addr := id.String()
log.Error("before hive healthy call")
if err := client.Call(&healthy, "hive_healthy", addrs); err != nil {
return fmt.Errorf("error getting node health: %s", err)
}
log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.GotNN && healthy.KnowNN))
if !healthy.GotNN {
log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.GotNN && healthy.KnowNN && healthy.CountKnowNN > 0))
var nodeStr string
if err := client.Call(&nodeStr, "hive_string"); err != nil {
return fmt.Errorf("error getting node string %s", err)
}
log.Info(nodeStr)
for _, a := range addrs {
log.Info(common.Bytes2Hex(a))
}
if !healthy.GotNN || healthy.CountKnowNN == 0 {
isHealthy = false
break
}