mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
swarm/network: WIP Create Healthy assertion tests
This commit is contained in:
parent
2990503d89
commit
cbf6d77a7f
4 changed files with 102 additions and 22 deletions
|
|
@ -17,6 +17,7 @@
|
||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -248,17 +249,27 @@ func (h *Hive) savePeers() error {
|
||||||
// It evaluates the healthiness based on the addresses passed as argument
|
// 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
|
// in relation to the base address of the hive instance the method is called on
|
||||||
func (h *Hive) Healthy(addrs [][]byte) *Health {
|
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 {
|
for _, a := range addrs {
|
||||||
p := &Peer{
|
if bytes.Equal(a, h.BaseAddr()) {
|
||||||
BzzPeer: &BzzPeer{
|
continue
|
||||||
BzzAddr: &BzzAddr{
|
|
||||||
OAddr: a,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
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()
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
// 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
|
// if base is nil, kademlia base address is used
|
||||||
// It returns peers in order deepest to shallowest
|
// It returns peers in order deepest to shallowest
|
||||||
func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) {
|
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
|
// if there is altogether less than MinProxBinSize peers it returns 0
|
||||||
// caller must hold the lock
|
// caller must hold the lock
|
||||||
func depthForPot(p *pot.Pot, minProxBinSize int, pivotAddr []byte) (depth int) {
|
func depthForPot(p *pot.Pot, minProxBinSize int, pivotAddr []byte) (depth int) {
|
||||||
|
log.Trace("pivot", "a", pivotAddr)
|
||||||
if p.Size() <= minProxBinSize {
|
if p.Size() <= minProxBinSize {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
@ -470,7 +471,8 @@ func depthForPot(p *pot.Pot, minProxBinSize int, pivotAddr []byte) (depth int) {
|
||||||
}
|
}
|
||||||
p.EachNeighbour(pivotAddr, Pof, f)
|
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 po == depth {
|
||||||
if maxDepth == depth {
|
if maxDepth == depth {
|
||||||
return false
|
return false
|
||||||
|
|
@ -629,8 +631,8 @@ func NewPeerPotMap(kads []*Kademlia) map[string]*PeerPot {
|
||||||
a := k.base
|
a := k.base
|
||||||
|
|
||||||
// actual kademlia depth
|
// 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
|
// all nn-peers
|
||||||
var nns [][]byte
|
var nns [][]byte
|
||||||
|
|
||||||
|
|
@ -652,7 +654,7 @@ func NewPeerPotMap(kads []*Kademlia) map[string]*PeerPot {
|
||||||
return false
|
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{
|
ppmap[common.Bytes2Hex(a)] = &PeerPot{
|
||||||
Kademlia: k,
|
Kademlia: k,
|
||||||
NNSet: nns,
|
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)
|
// all bins (except self) are included (0 <= bin <= 255)
|
||||||
depth := depthForPot(o.addrs, o.MinProxBinSize, o.base)
|
depth := depthForPot(o.addrs, o.MinProxBinSize, o.base)
|
||||||
o.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool {
|
o.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool {
|
||||||
|
log.Info("eachaddr", "depth", depth, "po", po)
|
||||||
if po < depth {
|
if po < depth {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -711,7 +714,7 @@ func (o *PeerPot) knowNeighbours() (got bool, n int, missing [][]byte) {
|
||||||
if pm[pk] {
|
if pm[pk] {
|
||||||
gots++
|
gots++
|
||||||
} else {
|
} 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)
|
culprits = append(culprits, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,17 @@ func testKadPeerAddr(s string) *BzzAddr {
|
||||||
return &BzzAddr{OAddr: a, UAddr: a}
|
return &BzzAddr{OAddr: a, UAddr: a}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestKademlia(b string) *Kademlia {
|
func newTestKademliaParams() *KadParams {
|
||||||
params := NewKadParams()
|
params := NewKadParams()
|
||||||
|
// TODO why is this 1?
|
||||||
params.MinBinSize = 1
|
params.MinBinSize = 1
|
||||||
params.MinProxBinSize = 2
|
params.MinProxBinSize = 2
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestKademlia(b string) *Kademlia {
|
||||||
base := pot.NewAddressFromString(b)
|
base := pot.NewAddressFromString(b)
|
||||||
return NewKademlia(base, params)
|
return NewKademlia(base, newTestKademliaParams())
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestKadPeer(k *Kademlia, s string, lightNode bool) *Peer {
|
func newTestKadPeer(k *Kademlia, s string, lightNode bool) *Peer {
|
||||||
|
|
@ -157,6 +162,58 @@ func TestNeighbourhoodDepth(t *testing.T) {
|
||||||
testNum++
|
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 {
|
func testSuggestPeer(k *Kademlia, expAddr string, expPo int, expWant bool) error {
|
||||||
addr, o, want := k.SuggestPeer()
|
addr, o, want := k.SuggestPeer()
|
||||||
log.Trace("suggestpeer return", "a", addr, "o", o, "want", want)
|
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]
|
return pot.ToBin(a.Address())[:8]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO explain why this bug occurred and how it should have been mitigated
|
||||||
func TestSuggestPeerBug(t *testing.T) {
|
func TestSuggestPeerBug(t *testing.T) {
|
||||||
// 2 row gap, unsaturated proxbin, no callables -> want PO 0
|
// 2 row gap, unsaturated proxbin, no callables -> want PO 0
|
||||||
k := newTestKademlia("00000000")
|
k := newTestKademlia("00000000")
|
||||||
|
|
@ -557,7 +615,7 @@ func testKademliaCase(t *testing.T, pivotAddr string, addrs ...string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
h := pp.Healthy()
|
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())
|
t.Fatalf("not healthy: %#v\n%v", h, k.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"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 {
|
if err := client.Call(&healthy, "hive_healthy", addrs); err != nil {
|
||||||
return false, fmt.Errorf("error getting node health: %s", err)
|
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
|
return healthy.KnowNN && healthy.GotNN, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -399,13 +400,20 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt
|
||||||
}
|
}
|
||||||
healthy := &network.Health{}
|
healthy := &network.Health{}
|
||||||
addr := id.String()
|
addr := id.String()
|
||||||
log.Error("before hive healthy call")
|
|
||||||
if err := client.Call(&healthy, "hive_healthy", addrs); err != nil {
|
if err := client.Call(&healthy, "hive_healthy", addrs); err != nil {
|
||||||
return fmt.Errorf("error getting node health: %s", err)
|
return fmt.Errorf("error getting node health: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.GotNN && healthy.KnowNN))
|
log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.GotNN && healthy.KnowNN && healthy.CountKnowNN > 0))
|
||||||
if !healthy.GotNN {
|
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
|
isHealthy = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue