Skip to content
This repository has been archived by the owner on Aug 2, 2021. It is now read-only.

Commit

Permalink
swarm/pss: negihbourhood addressing simulation tests (#19278)
Browse files Browse the repository at this point in the history
* swarm/pss: fixed bug in pss.process, test added

* swarm/pss: test case updated

* swarm/pss: WaitTillSnapshotRecreated() func added

* swarm/pss: snapshot test updated

* swarm/pss: WaitTillSnapshotLoaded() fixed

* swarm/pss: gofmt applied

* swarm/pss: refactoring, file renamed

* swarm/pss: input data fixed

* swarm/pss: race condition fixed

* swarm/pss: test timeout increased

* swarm/pss: eliminated the global variables

* swarm/pss: tests added

* swarm/pss: comments added

* swarm/pss: comment fixed

* swarm/pss: refactored according to review

* swarm/pss: style fix

* swarm/pss: increased timeout
  • Loading branch information
gluk256 authored and nonsense committed May 8, 2019
1 parent f4476d4 commit eb1aaf3
Show file tree
Hide file tree
Showing 4 changed files with 738 additions and 9 deletions.
105 changes: 105 additions & 0 deletions swarm/network/simulation/kademlia.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ package simulation

import (
"context"
"encoding/binary"
"encoding/hex"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/simulations"
"github.com/ethereum/go-ethereum/swarm/network"
)

Expand Down Expand Up @@ -95,3 +97,106 @@ func (s *Simulation) kademlias() (ks map[enode.ID]*network.Kademlia) {
}
return ks
}

// WaitTillSnapshotRecreated is blocking until all the connections specified
// in the snapshot are registered in the kademlia.
// It differs from WaitTillHealthy, which waits only until all the kademlias are
// healthy (it might happen even before all the connections are established).
func (s *Simulation) WaitTillSnapshotRecreated(ctx context.Context, snap simulations.Snapshot) error {
expected := getSnapshotConnections(snap.Conns)
ticker := time.NewTicker(150 * time.Millisecond)
defer ticker.Stop()

for {
select {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
actual := s.getActualConnections()
if isAllDeployed(expected, actual) {
return nil
}
}
}
}

func (s *Simulation) getActualConnections() (res []uint64) {
kademlias := s.kademlias()
for base, k := range kademlias {
k.EachConn(base[:], 256, func(p *network.Peer, _ int) bool {
res = append(res, getConnectionHash(base, p.ID()))
return true
})
}

// only list those connections that appear twice (both peers should recognize connection as active)
res = removeDuplicatesAndSingletons(res)
return res
}

func getSnapshotConnections(conns []simulations.Conn) (res []uint64) {
for _, c := range conns {
res = append(res, getConnectionHash(c.One, c.Other))
}
return res
}

// returns an integer connection identifier (similar to 8-byte hash)
func getConnectionHash(a, b enode.ID) uint64 {
var h [8]byte
for i := 0; i < 8; i++ {
h[i] = a[i] ^ b[i]
}
res := binary.LittleEndian.Uint64(h[:])
return res
}

// returns true if all connections in expected are listed in actual
func isAllDeployed(expected []uint64, actual []uint64) bool {
if len(expected) == 0 {
return true
}

exp := make([]uint64, len(expected))
copy(exp, expected)
for _, c := range actual {
// remove value c from exp
for i := 0; i < len(exp); i++ {
if exp[i] == c {
exp = removeListElement(exp, i)
if len(exp) == 0 {
return true
}
}
}
}
return len(exp) == 0
}

func removeListElement(arr []uint64, i int) []uint64 {
last := len(arr) - 1
arr[i] = arr[last]
arr = arr[:last]
return arr
}

func removeDuplicatesAndSingletons(arr []uint64) []uint64 {
for i := 0; i < len(arr); {
found := false
for j := i + 1; j < len(arr); j++ {
if arr[i] == arr[j] {
arr = removeListElement(arr, j) // remove duplicate
found = true
break
}
}

if found {
i++
} else {
arr = removeListElement(arr, i) // remove singleton
}
}

return arr
}
163 changes: 163 additions & 0 deletions swarm/network/simulation/kademlia_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,166 @@ func TestWaitTillHealthy(t *testing.T) {
}
}
}

// TestWaitTillSnapshotRecreated tests that we indeed have a network
// configuration specified in the snapshot file, after we wait for it.
//
// First we create a first simulation
// Run it as nodes connected in a ring
// Wait until the network is healthy
// Then we create a snapshot
// With this snapshot we create a new simulation
// Call WaitTillSnapshotRecreated() function and wait until it returns
// Iterate the nodes and check if all the connections are successfully recreated
func TestWaitTillSnapshotRecreated(t *testing.T) {
var err error
sim := New(createSimServiceMap(true))
_, err = sim.AddNodesAndConnectRing(16)
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
_, err = sim.WaitTillHealthy(ctx)
if err != nil {
t.Fatal(err)
}

originalConnections := sim.getActualConnections()
snap, err := sim.Net.Snapshot()
sim.Close()
if err != nil {
t.Fatal(err)
}

controlSim := New(createSimServiceMap(false))
defer controlSim.Close()
err = controlSim.Net.Load(snap)
if err != nil {
t.Fatal(err)
}
err = controlSim.WaitTillSnapshotRecreated(ctx, *snap)
if err != nil {
t.Fatal(err)
}
controlConnections := controlSim.getActualConnections()

for _, c := range originalConnections {
if !exist(controlConnections, c) {
t.Fatal("connection was not recreated")
}
}
}

// exist returns true if val is found in arr
func exist(arr []uint64, val uint64) bool {
for _, c := range arr {
if c == val {
return true
}
}
return false
}

func TestRemoveDuplicatesAndSingletons(t *testing.T) {
singletons := []uint64{
0x3c127c6f6cb026b0,
0x0f45190d72e71fc5,
0xb0184c02449e0bb6,
0xa85c7b84239c54d3,
0xe3b0c44298fc1c14,
0x9afbf4c8996fb924,
0x27ae41e4649b934c,
0xa495991b7852b855,
}

doubles := []uint64{
0x1b879f878de7fc7a,
0xc6791470521bdab4,
0xdd34b0ee39bbccc6,
0x4d904fbf0f31da10,
0x6403c2560432c8f8,
0x18954e33cf3ad847,
0x90db00e98dc7a8a6,
0x92886b0dfcc1809b,
}

var arr []uint64
arr = append(arr, doubles...)
arr = append(arr, singletons...)
arr = append(arr, doubles...)
arr = removeDuplicatesAndSingletons(arr)

for _, i := range singletons {
if exist(arr, i) {
t.Fatalf("singleton not removed: %d", i)
}
}

for _, i := range doubles {
if !exist(arr, i) {
t.Fatalf("wrong value removed: %d", i)
}
}

for j := 0; j < len(doubles); j++ {
v := doubles[j] + singletons[j]
if exist(arr, v) {
t.Fatalf("non-existing value found, index: %d", j)
}
}
}

func TestIsAllDeployed(t *testing.T) {
a := []uint64{
0x3c127c6f6cb026b0,
0x0f45190d72e71fc5,
0xb0184c02449e0bb6,
0xa85c7b84239c54d3,
0xe3b0c44298fc1c14,
0x9afbf4c8996fb924,
0x27ae41e4649b934c,
0xa495991b7852b855,
}

b := []uint64{
0x1b879f878de7fc7a,
0xc6791470521bdab4,
0xdd34b0ee39bbccc6,
0x4d904fbf0f31da10,
0x6403c2560432c8f8,
0x18954e33cf3ad847,
0x90db00e98dc7a8a6,
0x92886b0dfcc1809b,
}

var c []uint64
c = append(c, a...)
c = append(c, b...)

if !isAllDeployed(a, c) {
t.Fatal("isAllDeployed failed")
}

if !isAllDeployed(b, c) {
t.Fatal("isAllDeployed failed")
}

if isAllDeployed(c, a) {
t.Fatal("isAllDeployed failed: false positive")
}

if isAllDeployed(c, b) {
t.Fatal("isAllDeployed failed: false positive")
}

c = c[2:]

if isAllDeployed(a, c) {
t.Fatal("isAllDeployed failed: false positive")
}

if !isAllDeployed(b, c) {
t.Fatal("isAllDeployed failed")
}
}
Loading

0 comments on commit eb1aaf3

Please sign in to comment.