simulation

package
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 28, 2019 License: GPL-3.0 Imports: 22 Imported by: 0

Documentation

Index

Examples

Constants

View Source
const (
	SimulationTypeInproc = iota
	SimulationTypeExec
)

Variables

View Source
var (
	DefaultHTTPSimAddr = ":8888"
)

Package defaults.

View Source
var (
	ErrNodeNotFound = errors.New("node not found")
)

Common errors that are returned by functions in this package.

Functions

func BzzPrivateKeyFromConfig

func BzzPrivateKeyFromConfig(conf *adapters.NodeConfig) (*ecdsa.PrivateKey, error)

derive a private key for swarm for the node key returns the private key used to generate the bzz key

Types

type AddNodeOption

type AddNodeOption func(*adapters.NodeConfig)

AddNodeOption defines the option that can be passed to Simulation.AddNode method.

func AddNodeWithMsgEvents

func AddNodeWithMsgEvents(enable bool) AddNodeOption

AddNodeWithMsgEvents sets the EnableMsgEvents option to NodeConfig.

func AddNodeWithService

func AddNodeWithService(serviceName string) AddNodeOption

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.

type BucketKey

type BucketKey string

BucketKey is the type that should be used for keys in simulation buckets.

var (
	BucketKeyBzzPrivateKey BucketKey = "bzzprivkey"
)
var BucketKeyKademlia BucketKey = "kademlia"

BucketKeyKademlia is the key to be used for storing the kademlia instance for particular node, usually inside the ServiceFunc function.

type PeerEvent

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
}

PeerEvent is the type of the channel returned by Simulation.PeerEvents.

type PeerEventsFilter

type PeerEventsFilter struct {
	// contains filtered or unexported fields
}

PeerEventsFilter defines a filter on PeerEvents to exclude messages with defined properties. Use PeerEventsFilter methods to set required options.

func NewPeerEventsFilter

func NewPeerEventsFilter() *PeerEventsFilter

NewPeerEventsFilter returns a new PeerEventsFilter instance.

func (*PeerEventsFilter) Connect

func (f *PeerEventsFilter) Connect() *PeerEventsFilter

Connect sets the filter to events when two nodes connect.

func (*PeerEventsFilter) Drop

Drop sets the filter to events when two nodes disconnect.

func (*PeerEventsFilter) MsgCode

func (f *PeerEventsFilter) MsgCode(c uint64) *PeerEventsFilter

MsgCode sets the filter to only one msg code.

func (*PeerEventsFilter) Protocol

func (f *PeerEventsFilter) Protocol(p string) *PeerEventsFilter

Protocol sets the filter to only one message protocol.

func (*PeerEventsFilter) ReceivedMessages

func (f *PeerEventsFilter) ReceivedMessages() *PeerEventsFilter

ReceivedMessages sets the filter to only messages that are received.

func (*PeerEventsFilter) SentMessages

func (f *PeerEventsFilter) SentMessages() *PeerEventsFilter

SentMessages sets the filter to only messages that are sent.

type Result

type Result struct {
	Duration time.Duration
	Error    error
}

Result is the returned value of Simulation.Run method.

type RunFunc

type RunFunc func(context.Context, *Simulation) error

RunFunc is the function that will be called on Simulation.Run method call.

type ServiceFunc

type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error)

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 Simulation

type Simulation struct {
	// Net is exposed as a way to access lower level functionalities
	// of p2p/simulations.Network.
	Net *simulations.Network
	// contains filtered or unexported fields
}

Simulation provides methods on network, nodes and services to manage them.

func NewExec added in v0.4.2

func NewExec(services map[string]ServiceFunc) (s *Simulation, err error)

NewExec does the same as New but lets the caller specify the adapter to use

func NewInProc added in v0.4.2

func NewInProc(services map[string]ServiceFunc) (s *Simulation)

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 (*Simulation) AddNode

func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error)

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 (*Simulation) AddNodes

func (s *Simulation) AddNodes(count int, opts ...AddNodeOption) (ids []enode.ID, err error)

AddNodes creates new nodes with random configurations, applies provided options to the config and adds nodes to network.

func (*Simulation) AddNodesAndConnectChain

func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) (ids []enode.ID, err error)

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 (*Simulation) AddNodesAndConnectFull

func (s *Simulation) AddNodesAndConnectFull(count int, opts ...AddNodeOption) (ids []enode.ID, err error)

AddNodesAndConnectFull is a helpper method that combines AddNodes and ConnectNodesFull. Only new nodes will be connected.

func (*Simulation) AddNodesAndConnectRing

func (s *Simulation) AddNodesAndConnectRing(count int, opts ...AddNodeOption) (ids []enode.ID, err error)

AddNodesAndConnectRing is a helpper method that combines AddNodes and ConnectNodesRing.

func (*Simulation) AddNodesAndConnectStar

func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (ids []enode.ID, err error)

AddNodesAndConnectStar is a helpper method that combines AddNodes and ConnectNodesStar.

func (*Simulation) Close

func (s *Simulation) Close()

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 (*Simulation) Done

func (s *Simulation) Done() <-chan struct{}

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 (*Simulation) DownNodeIDs

func (s *Simulation) DownNodeIDs() (ids []enode.ID)

DownNodeIDs returns NodeIDs for nodes that are stopped in the network.

func (*Simulation) NodeIDs

func (s *Simulation) NodeIDs() (ids []enode.ID)

NodeIDs returns NodeIDs for all nodes in the network.

func (*Simulation) NodeItem

func (s *Simulation) NodeItem(id enode.ID, key interface{}) (value interface{}, ok bool)

NodeItem returns an item set in ServiceFunc function for a particular node.

func (*Simulation) NodesItems

func (s *Simulation) NodesItems(key interface{}) (values map[enode.ID]interface{})

NodesItems returns a map of items from all nodes that are all set under the same BucketKey.

func (*Simulation) PeerEvents

func (s *Simulation) PeerEvents(ctx context.Context, ids []enode.ID, filters ...*PeerEventsFilter) <-chan PeerEvent

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.

Example

Watch all peer events in the simulation network, buy receiving from a channel.

package main

import (
	"context"

	"github.com/ethereum/go-ethereum/log"
	"github.com/ethersphere/swarm/network/simulation"
)

func main() {
	sim := simulation.NewInProc(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)
		}
	}()
}
Output:

Example (Disconnections)

Detect when a nodes drop a peer.

package main

import (
	"context"

	"github.com/ethereum/go-ethereum/log"
	"github.com/ethersphere/swarm/network/simulation"
)

func main() {
	sim := simulation.NewInProc(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)
		}
	}()
}
Output:

Example (MultipleFilters)

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.

package main

import (
	"context"

	"github.com/ethereum/go-ethereum/log"
	"github.com/ethersphere/swarm/network/simulation"
)

func main() {
	sim := simulation.NewInProc(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)
		}
	}()
}
Output:

func (*Simulation) RandomService

func (s *Simulation) RandomService(name string) node.Service

RandomService returns a single Service by name on a randomly chosen node that is up.

func (*Simulation) Run

func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result)

Run calls the RunFunc function while taking care of cancellation provided through the Context.

func (*Simulation) RunSimulation

func (s *Simulation) RunSimulation(w http.ResponseWriter, req *http.Request)

RunSimulation is the actual POST endpoint runner

func (*Simulation) Service

func (s *Simulation) Service(name string, id enode.ID) node.Service

Service returns a single Service by name on a particular node with provided id.

func (*Simulation) Services

func (s *Simulation) Services(name string) (services map[enode.ID]node.Service)

Services returns all services with a provided name from nodes that are up.

func (*Simulation) SetNodeItem

func (s *Simulation) SetNodeItem(id enode.ID, key interface{}, value interface{})

SetNodeItem sets a new item associated with the node with provided NodeID. Buckets should be used to avoid managing separate simulation global state.

func (*Simulation) StartNode

func (s *Simulation) StartNode(id enode.ID) (err error)

StartNode starts a node by NodeID.

func (*Simulation) StartRandomNode

func (s *Simulation) StartRandomNode() (id enode.ID, err error)

StartRandomNode starts a random node.

func (*Simulation) StartRandomNodes

func (s *Simulation) StartRandomNodes(count int) (ids []enode.ID, err error)

StartRandomNodes starts random nodes.

func (*Simulation) StopNode

func (s *Simulation) StopNode(id enode.ID) (err error)

StopNode stops a node by NodeID.

func (*Simulation) StopRandomNode

func (s *Simulation) StopRandomNode() (id enode.ID, err error)

StopRandomNode stops a random node.

func (*Simulation) StopRandomNodes

func (s *Simulation) StopRandomNodes(count int) (ids []enode.ID, err error)

StopRandomNodes stops random nodes.

func (*Simulation) UpNodeIDs

func (s *Simulation) UpNodeIDs() (ids []enode.ID)

UpNodeIDs returns NodeIDs for nodes that are up in the network.

func (*Simulation) UpNodesItems

func (s *Simulation) UpNodesItems(key interface{}) (values map[enode.ID]interface{})

UpNodesItems returns a map of items with the same BucketKey from all nodes that are up.

func (*Simulation) UploadSnapshot

func (s *Simulation) UploadSnapshot(ctx context.Context, snapshotFile string, opts ...AddNodeOption) error

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 (*Simulation) WaitTillHealthy

func (s *Simulation) WaitTillHealthy(ctx context.Context) (ill map[enode.ID]*network.Kademlia, err error)

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

Example

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.

package main

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/node"
	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
	"github.com/ethersphere/swarm/network"
	"github.com/ethersphere/swarm/network/simulation"
)

func main() {

	sim := simulation.NewInProc(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

}
Output:

func (*Simulation) WaitTillSnapshotRecreated

func (s *Simulation) WaitTillSnapshotRecreated(ctx context.Context, snap *simulations.Snapshot) error

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 (*Simulation) WithServer

func (s *Simulation) WithServer(addr string) *Simulation

WithServer implements the builder pattern constructor for Simulation to start with a HTTP server

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL