aboutsummaryrefslogtreecommitdiffstats
path: root/swarm/network/simulation
diff options
context:
space:
mode:
Diffstat (limited to 'swarm/network/simulation')
-rw-r--r--swarm/network/simulation/bucket.go79
-rw-r--r--swarm/network/simulation/bucket_test.go155
-rw-r--r--swarm/network/simulation/events.go217
-rw-r--r--swarm/network/simulation/events_test.go107
-rw-r--r--swarm/network/simulation/example_test.go141
-rw-r--r--swarm/network/simulation/http.go68
-rw-r--r--swarm/network/simulation/http_test.go110
-rw-r--r--swarm/network/simulation/kademlia.go203
-rw-r--r--swarm/network/simulation/kademlia_test.go310
-rw-r--r--swarm/network/simulation/node.go341
-rw-r--r--swarm/network/simulation/node_test.go446
-rw-r--r--swarm/network/simulation/service.go65
-rw-r--r--swarm/network/simulation/service_test.go46
-rw-r--r--swarm/network/simulation/simulation.go218
-rw-r--r--swarm/network/simulation/simulation_test.go203
15 files changed, 0 insertions, 2709 deletions
diff --git a/swarm/network/simulation/bucket.go b/swarm/network/simulation/bucket.go
deleted file mode 100644
index 49a1f4309..000000000
--- a/swarm/network/simulation/bucket.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import "github.com/ethereum/go-ethereum/p2p/enode"
-
-// BucketKey is the type that should be used for keys in simulation buckets.
-type BucketKey string
-
-// NodeItem returns an item set in ServiceFunc function for a particular node.
-func (s *Simulation) NodeItem(id enode.ID, key interface{}) (value interface{}, ok bool) {
- s.mu.Lock()
- defer s.mu.Unlock()
-
- if _, ok := s.buckets[id]; !ok {
- return nil, false
- }
- return s.buckets[id].Load(key)
-}
-
-// SetNodeItem sets a new item associated with the node with provided NodeID.
-// Buckets should be used to avoid managing separate simulation global state.
-func (s *Simulation) SetNodeItem(id enode.ID, key interface{}, value interface{}) {
- s.mu.Lock()
- defer s.mu.Unlock()
-
- s.buckets[id].Store(key, value)
-}
-
-// NodesItems returns a map of items from all nodes that are all set under the
-// same BucketKey.
-func (s *Simulation) NodesItems(key interface{}) (values map[enode.ID]interface{}) {
- s.mu.RLock()
- defer s.mu.RUnlock()
-
- ids := s.NodeIDs()
- values = make(map[enode.ID]interface{}, len(ids))
- for _, id := range ids {
- if _, ok := s.buckets[id]; !ok {
- continue
- }
- if v, ok := s.buckets[id].Load(key); ok {
- values[id] = v
- }
- }
- return values
-}
-
-// UpNodesItems returns a map of items with the same BucketKey from all nodes that are up.
-func (s *Simulation) UpNodesItems(key interface{}) (values map[enode.ID]interface{}) {
- s.mu.RLock()
- defer s.mu.RUnlock()
-
- ids := s.UpNodeIDs()
- values = make(map[enode.ID]interface{})
- for _, id := range ids {
- if _, ok := s.buckets[id]; !ok {
- continue
- }
- if v, ok := s.buckets[id].Load(key); ok {
- values[id] = v
- }
- }
- return values
-}
diff --git a/swarm/network/simulation/bucket_test.go b/swarm/network/simulation/bucket_test.go
deleted file mode 100644
index 2273d35a2..000000000
--- a/swarm/network/simulation/bucket_test.go
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "sync"
- "testing"
-
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
-)
-
-// TestServiceBucket tests all bucket functionality using subtests.
-// It constructs a simulation of two nodes by adding items to their buckets
-// in ServiceFunc constructor, then by SetNodeItem. Testing UpNodesItems
-// is done by stopping one node and validating availability of its items.
-func TestServiceBucket(t *testing.T) {
- testKey := "Key"
- testValue := "Value"
-
- sim := New(map[string]ServiceFunc{
- "noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
- b.Store(testKey, testValue+ctx.Config.ID.String())
- return newNoopService(), nil, nil
- },
- })
- defer sim.Close()
-
- id1, err := sim.AddNode()
- if err != nil {
- t.Fatal(err)
- }
-
- id2, err := sim.AddNode()
- if err != nil {
- t.Fatal(err)
- }
-
- t.Run("ServiceFunc bucket Store", func(t *testing.T) {
- v, ok := sim.NodeItem(id1, testKey)
- if !ok {
- t.Fatal("bucket item not found")
- }
- s, ok := v.(string)
- if !ok {
- t.Fatal("bucket item value is not string")
- }
- if s != testValue+id1.String() {
- t.Fatalf("expected %q, got %q", testValue+id1.String(), s)
- }
-
- v, ok = sim.NodeItem(id2, testKey)
- if !ok {
- t.Fatal("bucket item not found")
- }
- s, ok = v.(string)
- if !ok {
- t.Fatal("bucket item value is not string")
- }
- if s != testValue+id2.String() {
- t.Fatalf("expected %q, got %q", testValue+id2.String(), s)
- }
- })
-
- customKey := "anotherKey"
- customValue := "anotherValue"
-
- t.Run("SetNodeItem", func(t *testing.T) {
- sim.SetNodeItem(id1, customKey, customValue)
-
- v, ok := sim.NodeItem(id1, customKey)
- if !ok {
- t.Fatal("bucket item not found")
- }
- s, ok := v.(string)
- if !ok {
- t.Fatal("bucket item value is not string")
- }
- if s != customValue {
- t.Fatalf("expected %q, got %q", customValue, s)
- }
-
- _, ok = sim.NodeItem(id2, customKey)
- if ok {
- t.Fatal("bucket item should not be found")
- }
- })
-
- if err := sim.StopNode(id2); err != nil {
- t.Fatal(err)
- }
-
- t.Run("UpNodesItems", func(t *testing.T) {
- items := sim.UpNodesItems(testKey)
-
- v, ok := items[id1]
- if !ok {
- t.Errorf("node 1 item not found")
- }
- s, ok := v.(string)
- if !ok {
- t.Fatal("node 1 item value is not string")
- }
- if s != testValue+id1.String() {
- t.Fatalf("expected %q, got %q", testValue+id1.String(), s)
- }
-
- _, ok = items[id2]
- if ok {
- t.Errorf("node 2 item should not be found")
- }
- })
-
- t.Run("NodeItems", func(t *testing.T) {
- items := sim.NodesItems(testKey)
-
- v, ok := items[id1]
- if !ok {
- t.Errorf("node 1 item not found")
- }
- s, ok := v.(string)
- if !ok {
- t.Fatal("node 1 item value is not string")
- }
- if s != testValue+id1.String() {
- t.Fatalf("expected %q, got %q", testValue+id1.String(), s)
- }
-
- v, ok = items[id2]
- if !ok {
- t.Errorf("node 2 item not found")
- }
- s, ok = v.(string)
- if !ok {
- t.Fatal("node 1 item value is not string")
- }
- if s != testValue+id2.String() {
- t.Fatalf("expected %q, got %q", testValue+id2.String(), s)
- }
- })
-}
diff --git a/swarm/network/simulation/events.go b/swarm/network/simulation/events.go
deleted file mode 100644
index d73c3af4e..000000000
--- a/swarm/network/simulation/events.go
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "context"
- "sync"
-
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations"
-)
-
-// PeerEvent is the type of the channel returned by Simulation.PeerEvents.
-type PeerEvent struct {
- // NodeID is the ID of node that the event is caught on.
- NodeID enode.ID
- // PeerID is the ID of the peer node that the event is caught on.
- PeerID enode.ID
- // Event is the event that is caught.
- Event *simulations.Event
- // Error is the error that may have happened during event watching.
- Error error
-}
-
-// PeerEventsFilter defines a filter on PeerEvents to exclude messages with
-// defined properties. Use PeerEventsFilter methods to set required options.
-type PeerEventsFilter struct {
- eventType simulations.EventType
-
- connUp *bool
-
- msgReceive *bool
- protocol *string
- msgCode *uint64
-}
-
-// NewPeerEventsFilter returns a new PeerEventsFilter instance.
-func NewPeerEventsFilter() *PeerEventsFilter {
- return &PeerEventsFilter{}
-}
-
-// Connect sets the filter to events when two nodes connect.
-func (f *PeerEventsFilter) Connect() *PeerEventsFilter {
- f.eventType = simulations.EventTypeConn
- b := true
- f.connUp = &b
- return f
-}
-
-// Drop sets the filter to events when two nodes disconnect.
-func (f *PeerEventsFilter) Drop() *PeerEventsFilter {
- f.eventType = simulations.EventTypeConn
- b := false
- f.connUp = &b
- return f
-}
-
-// ReceivedMessages sets the filter to only messages that are received.
-func (f *PeerEventsFilter) ReceivedMessages() *PeerEventsFilter {
- f.eventType = simulations.EventTypeMsg
- b := true
- f.msgReceive = &b
- return f
-}
-
-// SentMessages sets the filter to only messages that are sent.
-func (f *PeerEventsFilter) SentMessages() *PeerEventsFilter {
- f.eventType = simulations.EventTypeMsg
- b := false
- f.msgReceive = &b
- return f
-}
-
-// Protocol sets the filter to only one message protocol.
-func (f *PeerEventsFilter) Protocol(p string) *PeerEventsFilter {
- f.eventType = simulations.EventTypeMsg
- f.protocol = &p
- return f
-}
-
-// MsgCode sets the filter to only one msg code.
-func (f *PeerEventsFilter) MsgCode(c uint64) *PeerEventsFilter {
- f.eventType = simulations.EventTypeMsg
- f.msgCode = &c
- return f
-}
-
-// PeerEvents returns a channel of events that are captured by admin peerEvents
-// subscription nodes with provided NodeIDs. Additional filters can be set to ignore
-// events that are not relevant.
-func (s *Simulation) PeerEvents(ctx context.Context, ids []enode.ID, filters ...*PeerEventsFilter) <-chan PeerEvent {
- eventC := make(chan PeerEvent)
-
- // wait group to make sure all subscriptions to admin peerEvents are established
- // before this function returns.
- var subsWG sync.WaitGroup
- for _, id := range ids {
- s.shutdownWG.Add(1)
- subsWG.Add(1)
- go func(id enode.ID) {
- defer s.shutdownWG.Done()
-
- events := make(chan *simulations.Event)
- sub := s.Net.Events().Subscribe(events)
- defer sub.Unsubscribe()
-
- subsWG.Done()
-
- for {
- select {
- case <-ctx.Done():
- if err := ctx.Err(); err != nil {
- select {
- case eventC <- PeerEvent{NodeID: id, Error: err}:
- case <-s.Done():
- }
- }
- return
- case <-s.Done():
- return
- case e := <-events:
- // ignore control events
- if e.Control {
- continue
- }
- match := len(filters) == 0 // if there are no filters match all events
- for _, f := range filters {
- if f.eventType == simulations.EventTypeConn && e.Conn != nil {
- if *f.connUp != e.Conn.Up {
- continue
- }
- // all connection filter parameters matched, break the loop
- match = true
- break
- }
- if f.eventType == simulations.EventTypeMsg && e.Msg != nil {
- if f.msgReceive != nil && *f.msgReceive != e.Msg.Received {
- continue
- }
- if f.protocol != nil && *f.protocol != e.Msg.Protocol {
- continue
- }
- if f.msgCode != nil && *f.msgCode != e.Msg.Code {
- continue
- }
- // all message filter parameters matched, break the loop
- match = true
- break
- }
- }
- var peerID enode.ID
- switch e.Type {
- case simulations.EventTypeConn:
- peerID = e.Conn.One
- if peerID == id {
- peerID = e.Conn.Other
- }
- case simulations.EventTypeMsg:
- peerID = e.Msg.One
- if peerID == id {
- peerID = e.Msg.Other
- }
- }
- if match {
- select {
- case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Event: e}:
- case <-ctx.Done():
- if err := ctx.Err(); err != nil {
- select {
- case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Error: err}:
- case <-s.Done():
- }
- }
- return
- case <-s.Done():
- return
- }
- }
- case err := <-sub.Err():
- if err != nil {
- select {
- case eventC <- PeerEvent{NodeID: id, Error: err}:
- case <-ctx.Done():
- if err := ctx.Err(); err != nil {
- select {
- case eventC <- PeerEvent{NodeID: id, Error: err}:
- case <-s.Done():
- }
- }
- return
- case <-s.Done():
- return
- }
- }
- }
- }
- }(id)
- }
-
- // wait all subscriptions
- subsWG.Wait()
- return eventC
-}
diff --git a/swarm/network/simulation/events_test.go b/swarm/network/simulation/events_test.go
deleted file mode 100644
index 529844816..000000000
--- a/swarm/network/simulation/events_test.go
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "context"
- "sync"
- "testing"
- "time"
-)
-
-// TestPeerEvents creates simulation, adds two nodes,
-// register for peer events, connects nodes in a chain
-// and waits for the number of connection events to
-// be received.
-func TestPeerEvents(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- _, err := sim.AddNodes(2)
- if err != nil {
- t.Fatal(err)
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
- events := sim.PeerEvents(ctx, sim.NodeIDs())
-
- // two nodes -> two connection events
- expectedEventCount := 2
-
- var wg sync.WaitGroup
- wg.Add(expectedEventCount)
-
- go func() {
- for e := range events {
- if e.Error != nil {
- if e.Error == context.Canceled {
- return
- }
- t.Error(e.Error)
- continue
- }
- wg.Done()
- }
- }()
-
- err = sim.Net.ConnectNodesChain(sim.NodeIDs())
- if err != nil {
- t.Fatal(err)
- }
-
- wg.Wait()
-}
-
-func TestPeerEventsTimeout(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- _, err := sim.AddNodes(2)
- if err != nil {
- t.Fatal(err)
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
- defer cancel()
- events := sim.PeerEvents(ctx, sim.NodeIDs())
-
- done := make(chan struct{})
- errC := make(chan error)
- go func() {
- for e := range events {
- if e.Error == context.Canceled {
- return
- }
- if e.Error == context.DeadlineExceeded {
- close(done)
- return
- } else {
- errC <- e.Error
- }
- }
- }()
-
- select {
- case <-time.After(time.Second):
- t.Fatal("no context deadline received")
- case err := <-errC:
- t.Fatal(err)
- case <-done:
- // all good, context deadline detected
- }
-}
diff --git a/swarm/network/simulation/example_test.go b/swarm/network/simulation/example_test.go
deleted file mode 100644
index 9d1492979..000000000
--- a/swarm/network/simulation/example_test.go
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation_test
-
-import (
- "context"
- "fmt"
- "sync"
- "time"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/swarm/network"
- "github.com/ethereum/go-ethereum/swarm/network/simulation"
-)
-
-// Every node can have a Kademlia associated using the node bucket under
-// BucketKeyKademlia key. This allows to use WaitTillHealthy to block until
-// all nodes have the their Kademlias healthy.
-func ExampleSimulation_WaitTillHealthy() {
-
- sim := simulation.New(map[string]simulation.ServiceFunc{
- "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
- addr := network.NewAddr(ctx.Config.Node())
- hp := network.NewHiveParams()
- hp.Discovery = false
- config := &network.BzzConfig{
- OverlayAddr: addr.Over(),
- UnderlayAddr: addr.Under(),
- HiveParams: hp,
- }
- kad := network.NewKademlia(addr.Over(), network.NewKadParams())
- // store kademlia in node's bucket under BucketKeyKademlia
- // so that it can be found by WaitTillHealthy method.
- b.Store(simulation.BucketKeyKademlia, kad)
- return network.NewBzz(config, kad, nil, nil, nil), nil, nil
- },
- })
- defer sim.Close()
-
- _, err := sim.AddNodesAndConnectRing(10)
- if err != nil {
- // handle error properly...
- panic(err)
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
- defer cancel()
- ill, err := sim.WaitTillHealthy(ctx)
- if err != nil {
- // inspect the latest detected not healthy kademlias
- for id, kad := range ill {
- fmt.Println("Node", id)
- fmt.Println(kad.String())
- }
- // handle error...
- }
-
- // continue with the test
-
-}
-
-// Watch all peer events in the simulation network, buy receiving from a channel.
-func ExampleSimulation_PeerEvents() {
- sim := simulation.New(nil)
- defer sim.Close()
-
- events := sim.PeerEvents(context.Background(), sim.NodeIDs())
-
- go func() {
- for e := range events {
- if e.Error != nil {
- log.Error("peer event", "err", e.Error)
- continue
- }
- log.Info("peer event", "node", e.NodeID, "peer", e.PeerID, "type", e.Event.Type)
- }
- }()
-}
-
-// Detect when a nodes drop a peer.
-func ExampleSimulation_PeerEvents_disconnections() {
- sim := simulation.New(nil)
- defer sim.Close()
-
- disconnections := sim.PeerEvents(
- context.Background(),
- sim.NodeIDs(),
- simulation.NewPeerEventsFilter().Drop(),
- )
-
- go func() {
- for d := range disconnections {
- if d.Error != nil {
- log.Error("peer drop", "err", d.Error)
- continue
- }
- log.Warn("peer drop", "node", d.NodeID, "peer", d.PeerID)
- }
- }()
-}
-
-// Watch multiple types of events or messages. In this case, they differ only
-// by MsgCode, but filters can be set for different types or protocols, too.
-func ExampleSimulation_PeerEvents_multipleFilters() {
- sim := simulation.New(nil)
- defer sim.Close()
-
- msgs := sim.PeerEvents(
- context.Background(),
- sim.NodeIDs(),
- // Watch when bzz messages 1 and 4 are received.
- simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("bzz").MsgCode(1),
- simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("bzz").MsgCode(4),
- )
-
- go func() {
- for m := range msgs {
- if m.Error != nil {
- log.Error("bzz message", "err", m.Error)
- continue
- }
- log.Info("bzz message", "node", m.NodeID, "peer", m.PeerID)
- }
- }()
-}
diff --git a/swarm/network/simulation/http.go b/swarm/network/simulation/http.go
deleted file mode 100644
index 69ae3baec..000000000
--- a/swarm/network/simulation/http.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "fmt"
- "net/http"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/p2p/simulations"
-)
-
-// Package defaults.
-var (
- DefaultHTTPSimAddr = ":8888"
-)
-
-//WithServer implements the builder pattern constructor for Simulation to
-//start with a HTTP server
-func (s *Simulation) WithServer(addr string) *Simulation {
- //assign default addr if nothing provided
- if addr == "" {
- addr = DefaultHTTPSimAddr
- }
- log.Info(fmt.Sprintf("Initializing simulation server on %s...", addr))
- //initialize the HTTP server
- s.handler = simulations.NewServer(s.Net)
- s.runC = make(chan struct{})
- //add swarm specific routes to the HTTP server
- s.addSimulationRoutes()
- s.httpSrv = &http.Server{
- Addr: addr,
- Handler: s.handler,
- }
- go func() {
- err := s.httpSrv.ListenAndServe()
- if err != nil {
- log.Error("Error starting the HTTP server", "error", err)
- }
- }()
- return s
-}
-
-//register additional HTTP routes
-func (s *Simulation) addSimulationRoutes() {
- s.handler.POST("/runsim", s.RunSimulation)
-}
-
-// RunSimulation is the actual POST endpoint runner
-func (s *Simulation) RunSimulation(w http.ResponseWriter, req *http.Request) {
- log.Debug("RunSimulation endpoint running")
- s.runC <- struct{}{}
- w.WriteHeader(http.StatusOK)
-}
diff --git a/swarm/network/simulation/http_test.go b/swarm/network/simulation/http_test.go
deleted file mode 100644
index dffd03a03..000000000
--- a/swarm/network/simulation/http_test.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "context"
- "fmt"
- "net/http"
- "sync"
- "testing"
- "time"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
-)
-
-func TestSimulationWithHTTPServer(t *testing.T) {
- log.Debug("Init simulation")
-
- ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
- defer cancel()
-
- sim := New(
- map[string]ServiceFunc{
- "noop": func(_ *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
- return newNoopService(), nil, nil
- },
- }).WithServer(DefaultHTTPSimAddr)
- defer sim.Close()
- log.Debug("Done.")
-
- _, err := sim.AddNode()
- if err != nil {
- t.Fatal(err)
- }
-
- log.Debug("Starting sim round and let it time out...")
- //first test that running without sending to the channel will actually
- //block the simulation, so let it time out
- result := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error {
- log.Debug("Just start the sim without any action and wait for the timeout")
- //ensure with a Sleep that simulation doesn't terminate before the timeout
- time.Sleep(2 * time.Second)
- return nil
- })
-
- if result.Error != nil {
- if result.Error.Error() == "context deadline exceeded" {
- log.Debug("Expected timeout error received")
- } else {
- t.Fatal(result.Error)
- }
- }
-
- //now run it again and send the expected signal on the waiting channel,
- //then close the simulation
- log.Debug("Starting sim round and wait for frontend signal...")
- //this time the timeout should be long enough so that it doesn't kick in too early
- ctx, cancel2 := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel2()
- errC := make(chan error, 1)
- go triggerSimulationRun(t, errC)
- result = sim.Run(ctx, func(ctx context.Context, sim *Simulation) error {
- log.Debug("This run waits for the run signal from `frontend`...")
- //ensure with a Sleep that simulation doesn't terminate before the signal is received
- time.Sleep(2 * time.Second)
- return nil
- })
- if result.Error != nil {
- t.Fatal(result.Error)
- }
- if err := <-errC; err != nil {
- t.Fatal(err)
- }
- log.Debug("Test terminated successfully")
-}
-
-func triggerSimulationRun(t *testing.T, errC chan error) {
- //We need to first wait for the sim HTTP server to start running...
- time.Sleep(2 * time.Second)
- //then we can send the signal
-
- log.Debug("Sending run signal to simulation: POST /runsim...")
- resp, err := http.Post(fmt.Sprintf("http://localhost%s/runsim", DefaultHTTPSimAddr), "application/json", nil)
- if err != nil {
- errC <- fmt.Errorf("Request failed: %v", err)
- return
- }
- log.Debug("Signal sent")
- if resp.StatusCode != http.StatusOK {
- errC <- fmt.Errorf("err %s", resp.Status)
- return
- }
- errC <- resp.Body.Close()
-}
diff --git a/swarm/network/simulation/kademlia.go b/swarm/network/simulation/kademlia.go
deleted file mode 100644
index 00e870a07..000000000
--- a/swarm/network/simulation/kademlia.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-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"
-)
-
-// BucketKeyKademlia is the key to be used for storing the kademlia
-// instance for particular node, usually inside the ServiceFunc function.
-var BucketKeyKademlia BucketKey = "kademlia"
-
-// WaitTillHealthy is blocking until the health of all kademlias is true.
-// If error is not nil, a map of kademlia that was found not healthy is returned.
-// TODO: Check correctness since change in kademlia depth calculation logic
-func (s *Simulation) WaitTillHealthy(ctx context.Context) (ill map[enode.ID]*network.Kademlia, err error) {
- // Prepare PeerPot map for checking Kademlia health
- var ppmap map[string]*network.PeerPot
- kademlias := s.kademlias()
- addrs := make([][]byte, 0, len(kademlias))
- // TODO verify that all kademlias have same params
- for _, k := range kademlias {
- addrs = append(addrs, k.BaseAddr())
- }
- ppmap = network.NewPeerPotMap(s.neighbourhoodSize, addrs)
-
- // Wait for healthy Kademlia on every node before checking files
- ticker := time.NewTicker(200 * time.Millisecond)
- defer ticker.Stop()
-
- ill = make(map[enode.ID]*network.Kademlia)
- for {
- select {
- case <-ctx.Done():
- return ill, ctx.Err()
- case <-ticker.C:
- for k := range ill {
- delete(ill, k)
- }
- log.Debug("kademlia health check", "addr count", len(addrs), "kad len", len(kademlias))
- for id, k := range kademlias {
- //PeerPot for this node
- addr := common.Bytes2Hex(k.BaseAddr())
- pp := ppmap[addr]
- //call Healthy RPC
- h := k.GetHealthInfo(pp)
- //print info
- log.Debug(k.String())
- log.Debug("kademlia", "connectNN", h.ConnectNN, "knowNN", h.KnowNN)
- log.Debug("kademlia", "health", h.ConnectNN && h.KnowNN, "addr", hex.EncodeToString(k.BaseAddr()), "node", id)
- log.Debug("kademlia", "ill condition", !h.ConnectNN, "addr", hex.EncodeToString(k.BaseAddr()), "node", id)
- if !h.Healthy() {
- ill[id] = k
- }
- }
- if len(ill) == 0 {
- return nil, nil
- }
- }
- }
-}
-
-// kademlias returns all Kademlia instances that are set
-// in simulation bucket.
-func (s *Simulation) kademlias() (ks map[enode.ID]*network.Kademlia) {
- items := s.UpNodesItems(BucketKeyKademlia)
- log.Debug("kademlia len items", "len", len(items))
- ks = make(map[enode.ID]*network.Kademlia, len(items))
- for id, v := range items {
- k, ok := v.(*network.Kademlia)
- if !ok {
- continue
- }
- ks[id] = k
- }
- 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
-}
diff --git a/swarm/network/simulation/kademlia_test.go b/swarm/network/simulation/kademlia_test.go
deleted file mode 100644
index af50aacfd..000000000
--- a/swarm/network/simulation/kademlia_test.go
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "context"
- "sync"
- "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/simulations/adapters"
- "github.com/ethereum/go-ethereum/swarm/network"
-)
-
-/*
- TestWaitTillHealthy tests that we indeed get a healthy network after we wait for it.
- For this to be tested, a bit of a snake tail bite needs to happen:
- * 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
- * This simulation is expected to have a healthy configuration, as it uses the snapshot
- * Thus we just iterate all nodes and check that their kademlias are healthy
- * If all kademlias are healthy, the test succeeded, otherwise it failed
-*/
-func TestWaitTillHealthy(t *testing.T) {
- t.Skip("this test is flaky; disabling till underlying problem is solved")
- testNodesNum := 10
-
- // create the first simulation
- sim := New(createSimServiceMap(true))
-
- // connect and...
- nodeIDs, err := sim.AddNodesAndConnectRing(testNodesNum)
- if err != nil {
- t.Fatal(err)
- }
-
- // array of all overlay addresses
- var addrs [][]byte
- // iterate once to be able to build the peer map
- for _, node := range nodeIDs {
- //get the kademlia overlay address from this ID
- a := node.Bytes()
- //append it to the array of all overlay addresses
- addrs = append(addrs, a)
- }
- // build a PeerPot only once
- pp := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs)
-
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
- defer cancel()
-
- // ...wait until healthy
- ill, err := sim.WaitTillHealthy(ctx)
- if err != nil {
- for id, kad := range ill {
- t.Log("Node", id)
- t.Log(kad.String())
- }
- t.Fatal(err)
- }
-
- // now create a snapshot of this network
- snap, err := sim.Net.Snapshot()
- if err != nil {
- t.Fatal(err)
- }
-
- // close the initial simulation
- sim.Close()
- // create a control simulation
- controlSim := New(createSimServiceMap(false))
- defer controlSim.Close()
-
- // load the snapshot into this control simulation
- err = controlSim.Net.Load(snap)
- if err != nil {
- t.Fatal(err)
- }
- _, err = controlSim.WaitTillHealthy(ctx)
- if err != nil {
- t.Fatal(err)
- }
-
- for _, node := range nodeIDs {
- // ...get its kademlia
- item, ok := controlSim.NodeItem(node, BucketKeyKademlia)
- if !ok {
- t.Fatal("No kademlia bucket item")
- }
- kad := item.(*network.Kademlia)
- // get its base address
- kid := common.Bytes2Hex(kad.BaseAddr())
-
- //get the health info
- info := kad.GetHealthInfo(pp[kid])
- log.Trace("Health info", "info", info)
- // check that it is healthy
- healthy := info.Healthy()
- if !healthy {
- t.Fatalf("Expected node %v of control simulation to be healthy, but it is not, unhealthy kademlias: %v", node, kad.String())
- }
- }
-}
-
-// createSimServiceMap returns the services map
-// this function will create the sim services with or without discovery enabled
-// based on the flag passed
-func createSimServiceMap(discovery bool) map[string]ServiceFunc {
- return map[string]ServiceFunc{
- "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
- addr := network.NewAddr(ctx.Config.Node())
- hp := network.NewHiveParams()
- hp.Discovery = discovery
- config := &network.BzzConfig{
- OverlayAddr: addr.Over(),
- UnderlayAddr: addr.Under(),
- HiveParams: hp,
- }
- kad := network.NewKademlia(addr.Over(), network.NewKadParams())
- // store kademlia in node's bucket under BucketKeyKademlia
- // so that it can be found by WaitTillHealthy method.
- b.Store(BucketKeyKademlia, kad)
- return network.NewBzz(config, kad, nil, nil, nil), nil, nil
- },
- }
-}
-
-// 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) {
- t.Skip("test is flaky. disabling until underlying problem is addressed")
- 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")
- }
-}
diff --git a/swarm/network/simulation/node.go b/swarm/network/simulation/node.go
deleted file mode 100644
index f66b0afd0..000000000
--- a/swarm/network/simulation/node.go
+++ /dev/null
@@ -1,341 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "bytes"
- "context"
- "crypto/ecdsa"
- "encoding/json"
- "errors"
- "io/ioutil"
- "math/rand"
- "os"
- "sync"
- "time"
-
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/swarm/network"
-)
-
-var (
- BucketKeyBzzPrivateKey BucketKey = "bzzprivkey"
-)
-
-// NodeIDs returns NodeIDs for all nodes in the network.
-func (s *Simulation) NodeIDs() (ids []enode.ID) {
- nodes := s.Net.GetNodes()
- ids = make([]enode.ID, len(nodes))
- for i, node := range nodes {
- ids[i] = node.ID()
- }
- return ids
-}
-
-// UpNodeIDs returns NodeIDs for nodes that are up in the network.
-func (s *Simulation) UpNodeIDs() (ids []enode.ID) {
- nodes := s.Net.GetNodes()
- for _, node := range nodes {
- if node.Up() {
- ids = append(ids, node.ID())
- }
- }
- return ids
-}
-
-// DownNodeIDs returns NodeIDs for nodes that are stopped in the network.
-func (s *Simulation) DownNodeIDs() (ids []enode.ID) {
- nodes := s.Net.GetNodes()
- for _, node := range nodes {
- if !node.Up() {
- ids = append(ids, node.ID())
- }
- }
- return ids
-}
-
-// AddNodeOption defines the option that can be passed
-// to Simulation.AddNode method.
-type AddNodeOption func(*adapters.NodeConfig)
-
-// AddNodeWithMsgEvents sets the EnableMsgEvents option
-// to NodeConfig.
-func AddNodeWithMsgEvents(enable bool) AddNodeOption {
- return func(o *adapters.NodeConfig) {
- o.EnableMsgEvents = enable
- }
-}
-
-// AddNodeWithService specifies a service that should be
-// started on a node. This option can be repeated as variadic
-// argument toe AddNode and other add node related methods.
-// If AddNodeWithService is not specified, all services will be started.
-func AddNodeWithService(serviceName string) AddNodeOption {
- return func(o *adapters.NodeConfig) {
- o.Services = append(o.Services, serviceName)
- }
-}
-
-// AddNode creates a new node with random configuration,
-// applies provided options to the config and adds the node to network.
-// By default all services will be started on a node. If one or more
-// AddNodeWithService option are provided, only specified services will be started.
-func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error) {
- conf := adapters.RandomNodeConfig()
- for _, o := range opts {
- o(conf)
- }
- if len(conf.Services) == 0 {
- conf.Services = s.serviceNames
- }
-
- // add ENR records to the underlying node
- // most importantly the bzz overlay address
- //
- // for now we have no way of setting bootnodes or lightnodes in sims
- // so we just let them be set to false
- // they should perhaps be possible to override them with AddNodeOption
- bzzPrivateKey, err := BzzPrivateKeyFromConfig(conf)
- if err != nil {
- return enode.ID{}, err
- }
-
- enodeParams := &network.EnodeParams{
- PrivateKey: bzzPrivateKey,
- }
- record, err := network.NewEnodeRecord(enodeParams)
- conf.Record = *record
-
- // Add the bzz address to the node config
- node, err := s.Net.NewNodeWithConfig(conf)
- if err != nil {
- return id, err
- }
- s.buckets[node.ID()] = new(sync.Map)
- s.SetNodeItem(node.ID(), BucketKeyBzzPrivateKey, bzzPrivateKey)
-
- return node.ID(), s.Net.Start(node.ID())
-}
-
-// AddNodes creates new nodes with random configurations,
-// applies provided options to the config and adds nodes to network.
-func (s *Simulation) AddNodes(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
- ids = make([]enode.ID, 0, count)
- for i := 0; i < count; i++ {
- id, err := s.AddNode(opts...)
- if err != nil {
- return nil, err
- }
- ids = append(ids, id)
- }
- return ids, nil
-}
-
-// AddNodesAndConnectFull is a helpper method that combines
-// AddNodes and ConnectNodesFull. Only new nodes will be connected.
-func (s *Simulation) AddNodesAndConnectFull(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
- if count < 2 {
- return nil, errors.New("count of nodes must be at least 2")
- }
- ids, err = s.AddNodes(count, opts...)
- if err != nil {
- return nil, err
- }
- err = s.Net.ConnectNodesFull(ids)
- if err != nil {
- return nil, err
- }
- return ids, nil
-}
-
-// AddNodesAndConnectChain is a helpper method that combines
-// AddNodes and ConnectNodesChain. The chain will be continued from the last
-// added node, if there is one in simulation using ConnectToLastNode method.
-func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
- if count < 2 {
- return nil, errors.New("count of nodes must be at least 2")
- }
- id, err := s.AddNode(opts...)
- if err != nil {
- return nil, err
- }
- err = s.Net.ConnectToLastNode(id)
- if err != nil {
- return nil, err
- }
- ids, err = s.AddNodes(count-1, opts...)
- if err != nil {
- return nil, err
- }
- ids = append([]enode.ID{id}, ids...)
- err = s.Net.ConnectNodesChain(ids)
- if err != nil {
- return nil, err
- }
- return ids, nil
-}
-
-// AddNodesAndConnectRing is a helpper method that combines
-// AddNodes and ConnectNodesRing.
-func (s *Simulation) AddNodesAndConnectRing(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
- if count < 2 {
- return nil, errors.New("count of nodes must be at least 2")
- }
- ids, err = s.AddNodes(count, opts...)
- if err != nil {
- return nil, err
- }
- err = s.Net.ConnectNodesRing(ids)
- if err != nil {
- return nil, err
- }
- return ids, nil
-}
-
-// AddNodesAndConnectStar is a helpper method that combines
-// AddNodes and ConnectNodesStar.
-func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
- if count < 2 {
- return nil, errors.New("count of nodes must be at least 2")
- }
- ids, err = s.AddNodes(count, opts...)
- if err != nil {
- return nil, err
- }
- err = s.Net.ConnectNodesStar(ids[1:], ids[0])
- if err != nil {
- return nil, err
- }
- return ids, nil
-}
-
-// UploadSnapshot uploads a snapshot to the simulation
-// This method tries to open the json file provided, applies the config to all nodes
-// and then loads the snapshot into the Simulation network
-func (s *Simulation) UploadSnapshot(ctx context.Context, snapshotFile string, opts ...AddNodeOption) error {
- f, err := os.Open(snapshotFile)
- if err != nil {
- return err
- }
-
- jsonbyte, err := ioutil.ReadAll(f)
- f.Close()
- if err != nil {
- return err
- }
- var snap simulations.Snapshot
- if err := json.Unmarshal(jsonbyte, &snap); err != nil {
- return err
- }
-
- //the snapshot probably has the property EnableMsgEvents not set
- //set it to true (we need this to wait for messages before uploading)
- for i := range snap.Nodes {
- snap.Nodes[i].Node.Config.EnableMsgEvents = true
- snap.Nodes[i].Node.Config.Services = s.serviceNames
- for _, o := range opts {
- o(snap.Nodes[i].Node.Config)
- }
- }
-
- if err := s.Net.Load(&snap); err != nil {
- return err
- }
- return s.WaitTillSnapshotRecreated(ctx, &snap)
-}
-
-// StartNode starts a node by NodeID.
-func (s *Simulation) StartNode(id enode.ID) (err error) {
- return s.Net.Start(id)
-}
-
-// StartRandomNode starts a random node.
-func (s *Simulation) StartRandomNode() (id enode.ID, err error) {
- n := s.Net.GetRandomDownNode()
- if n == nil {
- return id, ErrNodeNotFound
- }
- return n.ID(), s.Net.Start(n.ID())
-}
-
-// StartRandomNodes starts random nodes.
-func (s *Simulation) StartRandomNodes(count int) (ids []enode.ID, err error) {
- ids = make([]enode.ID, 0, count)
- for i := 0; i < count; i++ {
- n := s.Net.GetRandomDownNode()
- if n == nil {
- return nil, ErrNodeNotFound
- }
- err = s.Net.Start(n.ID())
- if err != nil {
- return nil, err
- }
- ids = append(ids, n.ID())
- }
- return ids, nil
-}
-
-// StopNode stops a node by NodeID.
-func (s *Simulation) StopNode(id enode.ID) (err error) {
- return s.Net.Stop(id)
-}
-
-// StopRandomNode stops a random node.
-func (s *Simulation) StopRandomNode() (id enode.ID, err error) {
- n := s.Net.GetRandomUpNode()
- if n == nil {
- return id, ErrNodeNotFound
- }
- return n.ID(), s.Net.Stop(n.ID())
-}
-
-// StopRandomNodes stops random nodes.
-func (s *Simulation) StopRandomNodes(count int) (ids []enode.ID, err error) {
- ids = make([]enode.ID, 0, count)
- for i := 0; i < count; i++ {
- n := s.Net.GetRandomUpNode()
- if n == nil {
- return nil, ErrNodeNotFound
- }
- err = s.Net.Stop(n.ID())
- if err != nil {
- return nil, err
- }
- ids = append(ids, n.ID())
- }
- return ids, nil
-}
-
-// seed the random generator for Simulation.randomNode.
-func init() {
- rand.Seed(time.Now().UnixNano())
-}
-
-// derive a private key for swarm for the node key
-// returns the private key used to generate the bzz key
-func BzzPrivateKeyFromConfig(conf *adapters.NodeConfig) (*ecdsa.PrivateKey, error) {
- // pad the seed key some arbitrary data as ecdsa.GenerateKey takes 40 bytes seed data
- privKeyBuf := append(crypto.FromECDSA(conf.PrivateKey), []byte{0x62, 0x7a, 0x7a, 0x62, 0x7a, 0x7a, 0x62, 0x7a}...)
- bzzPrivateKey, err := ecdsa.GenerateKey(crypto.S256(), bytes.NewReader(privKeyBuf))
- if err != nil {
- return nil, err
- }
- return bzzPrivateKey, nil
-}
diff --git a/swarm/network/simulation/node_test.go b/swarm/network/simulation/node_test.go
deleted file mode 100644
index e1e20a0f1..000000000
--- a/swarm/network/simulation/node_test.go
+++ /dev/null
@@ -1,446 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "context"
- "fmt"
- "sync"
- "testing"
- "time"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/swarm/network"
-)
-
-func TestUpDownNodeIDs(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- ids, err := sim.AddNodes(10)
- if err != nil {
- t.Fatal(err)
- }
-
- gotIDs := sim.NodeIDs()
-
- if !equalNodeIDs(ids, gotIDs) {
- t.Error("returned nodes are not equal to added ones")
- }
-
- stoppedIDs, err := sim.StopRandomNodes(3)
- if err != nil {
- t.Fatal(err)
- }
-
- gotIDs = sim.UpNodeIDs()
-
- for _, id := range gotIDs {
- if !sim.Net.GetNode(id).Up() {
- t.Errorf("node %s should not be down", id)
- }
- }
-
- if !equalNodeIDs(ids, append(gotIDs, stoppedIDs...)) {
- t.Error("returned nodes are not equal to added ones")
- }
-
- gotIDs = sim.DownNodeIDs()
-
- for _, id := range gotIDs {
- if sim.Net.GetNode(id).Up() {
- t.Errorf("node %s should not be up", id)
- }
- }
-
- if !equalNodeIDs(stoppedIDs, gotIDs) {
- t.Error("returned nodes are not equal to the stopped ones")
- }
-}
-
-func equalNodeIDs(one, other []enode.ID) bool {
- if len(one) != len(other) {
- return false
- }
- var count int
- for _, a := range one {
- var found bool
- for _, b := range other {
- if a == b {
- found = true
- break
- }
- }
- if found {
- count++
- } else {
- return false
- }
- }
- return count == len(one)
-}
-
-func TestAddNode(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- id, err := sim.AddNode()
- if err != nil {
- t.Fatal(err)
- }
-
- n := sim.Net.GetNode(id)
- if n == nil {
- t.Fatal("node not found")
- }
-
- if !n.Up() {
- t.Error("node not started")
- }
-}
-
-func TestAddNodeWithMsgEvents(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- id, err := sim.AddNode(AddNodeWithMsgEvents(true))
- if err != nil {
- t.Fatal(err)
- }
-
- if !sim.Net.GetNode(id).Config.EnableMsgEvents {
- t.Error("EnableMsgEvents is false")
- }
-
- id, err = sim.AddNode(AddNodeWithMsgEvents(false))
- if err != nil {
- t.Fatal(err)
- }
-
- if sim.Net.GetNode(id).Config.EnableMsgEvents {
- t.Error("EnableMsgEvents is true")
- }
-}
-
-func TestAddNodeWithService(t *testing.T) {
- sim := New(map[string]ServiceFunc{
- "noop1": noopServiceFunc,
- "noop2": noopServiceFunc,
- })
- defer sim.Close()
-
- id, err := sim.AddNode(AddNodeWithService("noop1"))
- if err != nil {
- t.Fatal(err)
- }
-
- n := sim.Net.GetNode(id).Node.(*adapters.SimNode)
- if n.Service("noop1") == nil {
- t.Error("service noop1 not found on node")
- }
- if n.Service("noop2") != nil {
- t.Error("service noop2 should not be found on node")
- }
-}
-
-func TestAddNodeMultipleServices(t *testing.T) {
- sim := New(map[string]ServiceFunc{
- "noop1": noopServiceFunc,
- "noop2": noopService2Func,
- })
- defer sim.Close()
-
- id, err := sim.AddNode()
- if err != nil {
- t.Fatal(err)
- }
-
- n := sim.Net.GetNode(id).Node.(*adapters.SimNode)
- if n.Service("noop1") == nil {
- t.Error("service noop1 not found on node")
- }
- if n.Service("noop2") == nil {
- t.Error("service noop2 not found on node")
- }
-}
-
-func TestAddNodeDuplicateServiceError(t *testing.T) {
- sim := New(map[string]ServiceFunc{
- "noop1": noopServiceFunc,
- "noop2": noopServiceFunc,
- })
- defer sim.Close()
-
- wantErr := "duplicate service: *simulation.noopService"
- _, err := sim.AddNode()
- if err.Error() != wantErr {
- t.Errorf("got error %q, want %q", err, wantErr)
- }
-}
-
-func TestAddNodes(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- nodesCount := 12
-
- ids, err := sim.AddNodes(nodesCount)
- if err != nil {
- t.Fatal(err)
- }
-
- count := len(ids)
- if count != nodesCount {
- t.Errorf("expected %v nodes, got %v", nodesCount, count)
- }
-
- count = len(sim.Net.GetNodes())
- if count != nodesCount {
- t.Errorf("expected %v nodes, got %v", nodesCount, count)
- }
-}
-
-func TestAddNodesAndConnectFull(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- n := 12
-
- ids, err := sim.AddNodesAndConnectFull(n)
- if err != nil {
- t.Fatal(err)
- }
-
- simulations.VerifyFull(t, sim.Net, ids)
-}
-
-func TestAddNodesAndConnectChain(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- _, err := sim.AddNodesAndConnectChain(12)
- if err != nil {
- t.Fatal(err)
- }
-
- // add another set of nodes to test
- // if two chains are connected
- _, err = sim.AddNodesAndConnectChain(7)
- if err != nil {
- t.Fatal(err)
- }
-
- simulations.VerifyChain(t, sim.Net, sim.UpNodeIDs())
-}
-
-func TestAddNodesAndConnectRing(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- ids, err := sim.AddNodesAndConnectRing(12)
- if err != nil {
- t.Fatal(err)
- }
-
- simulations.VerifyRing(t, sim.Net, ids)
-}
-
-func TestAddNodesAndConnectStar(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- ids, err := sim.AddNodesAndConnectStar(12)
- if err != nil {
- t.Fatal(err)
- }
-
- simulations.VerifyStar(t, sim.Net, ids, 0)
-}
-
-//To test that uploading a snapshot works
-func TestUploadSnapshot(t *testing.T) {
- log.Debug("Creating simulation")
- s := New(map[string]ServiceFunc{
- "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
- addr := network.NewAddr(ctx.Config.Node())
- hp := network.NewHiveParams()
- hp.Discovery = false
- config := &network.BzzConfig{
- OverlayAddr: addr.Over(),
- UnderlayAddr: addr.Under(),
- HiveParams: hp,
- }
- kad := network.NewKademlia(addr.Over(), network.NewKadParams())
- b.Store(BucketKeyKademlia, kad)
- return network.NewBzz(config, kad, nil, nil, nil), nil, nil
- },
- })
- defer s.Close()
-
- nodeCount := 16
- log.Debug("Uploading snapshot")
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
- err := s.UploadSnapshot(ctx, fmt.Sprintf("../stream/testing/snapshot_%d.json", nodeCount))
- if err != nil {
- t.Fatalf("Error uploading snapshot to simulation network: %v", err)
- }
-
- log.Debug("Starting simulation...")
- s.Run(ctx, func(ctx context.Context, sim *Simulation) error {
- log.Debug("Checking")
- nodes := sim.UpNodeIDs()
- if len(nodes) != nodeCount {
- t.Fatal("Simulation network node number doesn't match snapshot node number")
- }
- return nil
- })
- log.Debug("Done.")
-}
-
-func TestStartStopNode(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- id, err := sim.AddNode()
- if err != nil {
- t.Fatal(err)
- }
-
- n := sim.Net.GetNode(id)
- if n == nil {
- t.Fatal("node not found")
- }
- if !n.Up() {
- t.Error("node not started")
- }
-
- err = sim.StopNode(id)
- if err != nil {
- t.Fatal(err)
- }
- if n.Up() {
- t.Error("node not stopped")
- }
-
- waitForPeerEventPropagation()
-
- err = sim.StartNode(id)
- if err != nil {
- t.Fatal(err)
- }
- if !n.Up() {
- t.Error("node not started")
- }
-}
-
-func TestStartStopRandomNode(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- _, err := sim.AddNodes(3)
- if err != nil {
- t.Fatal(err)
- }
-
- id, err := sim.StopRandomNode()
- if err != nil {
- t.Fatal(err)
- }
-
- n := sim.Net.GetNode(id)
- if n == nil {
- t.Fatal("node not found")
- }
- if n.Up() {
- t.Error("node not stopped")
- }
-
- id2, err := sim.StopRandomNode()
- if err != nil {
- t.Fatal(err)
- }
-
- waitForPeerEventPropagation()
-
- idStarted, err := sim.StartRandomNode()
- if err != nil {
- t.Fatal(err)
- }
-
- if idStarted != id && idStarted != id2 {
- t.Error("unexpected started node ID")
- }
-}
-
-func TestStartStopRandomNodes(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- _, err := sim.AddNodes(10)
- if err != nil {
- t.Fatal(err)
- }
-
- ids, err := sim.StopRandomNodes(3)
- if err != nil {
- t.Fatal(err)
- }
-
- for _, id := range ids {
- n := sim.Net.GetNode(id)
- if n == nil {
- t.Fatal("node not found")
- }
- if n.Up() {
- t.Error("node not stopped")
- }
- }
-
- waitForPeerEventPropagation()
-
- ids, err = sim.StartRandomNodes(2)
- if err != nil {
- t.Fatal(err)
- }
-
- for _, id := range ids {
- n := sim.Net.GetNode(id)
- if n == nil {
- t.Fatal("node not found")
- }
- if !n.Up() {
- t.Error("node not started")
- }
- }
-}
-
-func waitForPeerEventPropagation() {
- // Sleep here to ensure that Network.watchPeerEvents defer function
- // has set the `node.Up() = false` before we start the node again.
- //
- // The same node is stopped and started again, and upon start
- // watchPeerEvents is started in a goroutine. If the node is stopped
- // and then very quickly started, that goroutine may be scheduled later
- // then start and force `node.Up() = false` in its defer function.
- // This will make this test unreliable.
- time.Sleep(1 * time.Second)
-}
diff --git a/swarm/network/simulation/service.go b/swarm/network/simulation/service.go
deleted file mode 100644
index 0ac8149a9..000000000
--- a/swarm/network/simulation/service.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
-)
-
-// Service returns a single Service by name on a particular node
-// with provided id.
-func (s *Simulation) Service(name string, id enode.ID) node.Service {
- simNode, ok := s.Net.GetNode(id).Node.(*adapters.SimNode)
- if !ok {
- return nil
- }
- services := simNode.ServiceMap()
- if len(services) == 0 {
- return nil
- }
- return services[name]
-}
-
-// RandomService returns a single Service by name on a
-// randomly chosen node that is up.
-func (s *Simulation) RandomService(name string) node.Service {
- n := s.Net.GetRandomUpNode().Node.(*adapters.SimNode)
- if n == nil {
- return nil
- }
- return n.Service(name)
-}
-
-// Services returns all services with a provided name
-// from nodes that are up.
-func (s *Simulation) Services(name string) (services map[enode.ID]node.Service) {
- nodes := s.Net.GetNodes()
- services = make(map[enode.ID]node.Service)
- for _, node := range nodes {
- if !node.Up() {
- continue
- }
- simNode, ok := node.Node.(*adapters.SimNode)
- if !ok {
- continue
- }
- services[node.ID()] = simNode.Service(name)
- }
- return services
-}
diff --git a/swarm/network/simulation/service_test.go b/swarm/network/simulation/service_test.go
deleted file mode 100644
index 23b0d86f2..000000000
--- a/swarm/network/simulation/service_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "testing"
-)
-
-func TestService(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- id, err := sim.AddNode()
- if err != nil {
- t.Fatal(err)
- }
-
- _, ok := sim.Service("noop", id).(*noopService)
- if !ok {
- t.Fatalf("service is not of %T type", &noopService{})
- }
-
- _, ok = sim.RandomService("noop").(*noopService)
- if !ok {
- t.Fatalf("service is not of %T type", &noopService{})
- }
-
- _, ok = sim.Services("noop")[id].(*noopService)
- if !ok {
- t.Fatalf("service is not of %T type", &noopService{})
- }
-}
diff --git a/swarm/network/simulation/simulation.go b/swarm/network/simulation/simulation.go
deleted file mode 100644
index 5787cafda..000000000
--- a/swarm/network/simulation/simulation.go
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "context"
- "errors"
- "net/http"
- "sync"
- "time"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/swarm/network"
-)
-
-// Common errors that are returned by functions in this package.
-var (
- ErrNodeNotFound = errors.New("node not found")
-)
-
-// Simulation provides methods on network, nodes and services
-// to manage them.
-type Simulation struct {
- // Net is exposed as a way to access lower level functionalities
- // of p2p/simulations.Network.
- Net *simulations.Network
-
- serviceNames []string
- cleanupFuncs []func()
- buckets map[enode.ID]*sync.Map
- shutdownWG sync.WaitGroup
- done chan struct{}
- mu sync.RWMutex
- neighbourhoodSize int
-
- httpSrv *http.Server //attach a HTTP server via SimulationOptions
- handler *simulations.Server //HTTP handler for the server
- runC chan struct{} //channel where frontend signals it is ready
-}
-
-// ServiceFunc is used in New to declare new service constructor.
-// The first argument provides ServiceContext from the adapters package
-// giving for example the access to NodeID. Second argument is the sync.Map
-// where all "global" state related to the service should be kept.
-// All cleanups needed for constructed service and any other constructed
-// objects should ne provided in a single returned cleanup function.
-// Returned cleanup function will be called by Close function
-// after network shutdown.
-type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error)
-
-// New creates a new simulation instance
-// Services map must have unique keys as service names and
-// every ServiceFunc must return a node.Service of the unique type.
-// This restriction is required by node.Node.Start() function
-// which is used to start node.Service returned by ServiceFunc.
-func New(services map[string]ServiceFunc) (s *Simulation) {
- s = &Simulation{
- buckets: make(map[enode.ID]*sync.Map),
- done: make(chan struct{}),
- neighbourhoodSize: network.NewKadParams().NeighbourhoodSize,
- }
-
- adapterServices := make(map[string]adapters.ServiceFunc, len(services))
- for name, serviceFunc := range services {
- // Scope this variables correctly
- // as they will be in the adapterServices[name] function accessed later.
- name, serviceFunc := name, serviceFunc
- s.serviceNames = append(s.serviceNames, name)
- adapterServices[name] = func(ctx *adapters.ServiceContext) (node.Service, error) {
- s.mu.Lock()
- defer s.mu.Unlock()
- b, ok := s.buckets[ctx.Config.ID]
- if !ok {
- b = new(sync.Map)
- }
- service, cleanup, err := serviceFunc(ctx, b)
- if err != nil {
- return nil, err
- }
- if cleanup != nil {
- s.cleanupFuncs = append(s.cleanupFuncs, cleanup)
- }
- s.buckets[ctx.Config.ID] = b
- return service, nil
- }
- }
-
- s.Net = simulations.NewNetwork(
- adapters.NewTCPAdapter(adapterServices),
- &simulations.NetworkConfig{ID: "0"},
- )
-
- return s
-}
-
-// RunFunc is the function that will be called
-// on Simulation.Run method call.
-type RunFunc func(context.Context, *Simulation) error
-
-// Result is the returned value of Simulation.Run method.
-type Result struct {
- Duration time.Duration
- Error error
-}
-
-// Run calls the RunFunc function while taking care of
-// cancellation provided through the Context.
-func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result) {
- //if the option is set to run a HTTP server with the simulation,
- //init the server and start it
- start := time.Now()
- if s.httpSrv != nil {
- log.Info("Waiting for frontend to be ready...(send POST /runsim to HTTP server)")
- //wait for the frontend to connect
- select {
- case <-s.runC:
- case <-ctx.Done():
- return Result{
- Duration: time.Since(start),
- Error: ctx.Err(),
- }
- }
- log.Info("Received signal from frontend - starting simulation run.")
- }
- errc := make(chan error)
- quit := make(chan struct{})
- defer close(quit)
- go func() {
- select {
- case errc <- f(ctx, s):
- case <-quit:
- }
- }()
- var err error
- select {
- case <-ctx.Done():
- err = ctx.Err()
- case err = <-errc:
- }
- return Result{
- Duration: time.Since(start),
- Error: err,
- }
-}
-
-// Maximal number of parallel calls to cleanup functions on
-// Simulation.Close.
-var maxParallelCleanups = 10
-
-// Close calls all cleanup functions that are returned by
-// ServiceFunc, waits for all of them to finish and other
-// functions that explicitly block shutdownWG
-// (like Simulation.PeerEvents) and shuts down the network
-// at the end. It is used to clean all resources from the
-// simulation.
-func (s *Simulation) Close() {
- close(s.done)
-
- sem := make(chan struct{}, maxParallelCleanups)
- s.mu.RLock()
- cleanupFuncs := make([]func(), len(s.cleanupFuncs))
- for i, f := range s.cleanupFuncs {
- if f != nil {
- cleanupFuncs[i] = f
- }
- }
- s.mu.RUnlock()
- var cleanupWG sync.WaitGroup
- for _, cleanup := range cleanupFuncs {
- cleanupWG.Add(1)
- sem <- struct{}{}
- go func(cleanup func()) {
- defer cleanupWG.Done()
- defer func() { <-sem }()
-
- cleanup()
- }(cleanup)
- }
- cleanupWG.Wait()
-
- if s.httpSrv != nil {
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
- defer cancel()
- err := s.httpSrv.Shutdown(ctx)
- if err != nil {
- log.Error("Error shutting down HTTP server!", "err", err)
- }
- close(s.runC)
- }
-
- s.shutdownWG.Wait()
- s.Net.Shutdown()
-}
-
-// Done returns a channel that is closed when the simulation
-// is closed by Close method. It is useful for signaling termination
-// of all possible goroutines that are created within the test.
-func (s *Simulation) Done() <-chan struct{} {
- return s.done
-}
diff --git a/swarm/network/simulation/simulation_test.go b/swarm/network/simulation/simulation_test.go
deleted file mode 100644
index 1d0338f59..000000000
--- a/swarm/network/simulation/simulation_test.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package simulation
-
-import (
- "context"
- "errors"
- "flag"
- "sync"
- "testing"
- "time"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p/simulations"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/mattn/go-colorable"
-)
-
-var (
- loglevel = flag.Int("loglevel", 2, "verbosity of logs")
-)
-
-func init() {
- flag.Parse()
- log.PrintOrigins(true)
- log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))
-}
-
-// TestRun tests if Run method calls RunFunc and if it handles context properly.
-func TestRun(t *testing.T) {
- sim := New(noopServiceFuncMap)
- defer sim.Close()
-
- t.Run("call", func(t *testing.T) {
- expect := "something"
- var got string
- r := sim.Run(context.Background(), func(ctx context.Context, sim *Simulation) error {
- got = expect
- return nil
- })
-
- if r.Error != nil {
- t.Errorf("unexpected error: %v", r.Error)
- }
- if got != expect {
- t.Errorf("expected %q, got %q", expect, got)
- }
- })
-
- t.Run("cancellation", func(t *testing.T) {
- ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
- defer cancel()
-
- r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error {
- time.Sleep(time.Second)
- return nil
- })
-
- if r.Error != context.DeadlineExceeded {
- t.Errorf("unexpected error: %v", r.Error)
- }
- })
-
- t.Run("context value and duration", func(t *testing.T) {
- ctx := context.WithValue(context.Background(), "hey", "there")
- sleep := 50 * time.Millisecond
-
- r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error {
- if ctx.Value("hey") != "there" {
- return errors.New("expected context value not passed")
- }
- time.Sleep(sleep)
- return nil
- })
-
- if r.Error != nil {
- t.Errorf("unexpected error: %v", r.Error)
- }
- if r.Duration < sleep {
- t.Errorf("reported run duration less then expected: %s", r.Duration)
- }
- })
-}
-
-// TestClose tests are Close method triggers all close functions and are all nodes not up anymore.
-func TestClose(t *testing.T) {
- var mu sync.Mutex
- var cleanupCount int
-
- sleep := 50 * time.Millisecond
-
- sim := New(map[string]ServiceFunc{
- "noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
- return newNoopService(), func() {
- time.Sleep(sleep)
- mu.Lock()
- defer mu.Unlock()
- cleanupCount++
- }, nil
- },
- })
-
- nodeCount := 30
-
- _, err := sim.AddNodes(nodeCount)
- if err != nil {
- t.Fatal(err)
- }
-
- var upNodeCount int
- for _, n := range sim.Net.GetNodes() {
- if n.Up() {
- upNodeCount++
- }
- }
- if upNodeCount != nodeCount {
- t.Errorf("all nodes should be up, insted only %v are up", upNodeCount)
- }
-
- sim.Close()
-
- if cleanupCount != nodeCount {
- t.Errorf("number of cleanups expected %v, got %v", nodeCount, cleanupCount)
- }
-
- upNodeCount = 0
- for _, n := range sim.Net.GetNodes() {
- if n.Up() {
- upNodeCount++
- }
- }
- if upNodeCount != 0 {
- t.Errorf("all nodes should be down, insted %v are up", upNodeCount)
- }
-}
-
-// TestDone checks if Close method triggers the closing of done channel.
-func TestDone(t *testing.T) {
- sim := New(noopServiceFuncMap)
- sleep := 50 * time.Millisecond
- timeout := 2 * time.Second
-
- start := time.Now()
- go func() {
- time.Sleep(sleep)
- sim.Close()
- }()
-
- select {
- case <-time.After(timeout):
- t.Error("done channel closing timed out")
- case <-sim.Done():
- if d := time.Since(start); d < sleep {
- t.Errorf("done channel closed sooner then expected: %s", d)
- }
- }
-}
-
-// a helper map for usual services that do not do anything
-var noopServiceFuncMap = map[string]ServiceFunc{
- "noop": noopServiceFunc,
-}
-
-// a helper function for most basic noop service
-func noopServiceFunc(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) {
- return newNoopService(), nil, nil
-}
-
-func newNoopService() node.Service {
- return &noopService{}
-}
-
-// a helper function for most basic Noop service
-// of a different type then NoopService to test
-// multiple services on one node.
-func noopService2Func(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) {
- return new(noopService2), nil, nil
-}
-
-// NoopService2 is the service that does not do anything
-// but implements node.Service interface.
-type noopService2 struct {
- simulations.NoopService
-}
-
-type noopService struct {
- simulations.NoopService
-}