simulation

package
v0.0.0-...-ac8b7ce Latest Latest
Warning

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

Go to latest
Published: Jan 27, 2021 License: GPL-3.0 Imports: 20 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrNodeNotFound = errors.New("node not found")
	ErrNoPivotNode  = errors.New("no pivot node set")
)

Common errors that are returned by functions in this package.

View Source
var (
	DefaultHTTPSimAddr = ":8888"
)

Package defaults.

Functions

This section is empty.

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 BucketKeyKademlia BucketKey = "kademlia"

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

type PeerEvent

type PeerEvent struct {
	// NodeID is the ID of node that the event is caught on.
	NodeID discover.NodeID
	// Event is the event that is caught.
	Event *p2p.PeerEvent
	// 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) 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) Type

Type sets the filter to only one peer event type.

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 New

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

New creates a new Simulation instance with new simulations.Network initialized with provided services.

func (*Simulation) AddNode

func (s *Simulation) AddNode(opts ...AddNodeOption) (id discover.NodeID, 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 []discover.NodeID, 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 []discover.NodeID, 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 []discover.NodeID, 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 []discover.NodeID, err error)

AddNodesAndConnectRing is a helpper method that combines AddNodes and ConnectNodesRing.

func (*Simulation) AddNodesAndConnectStar

func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (ids []discover.NodeID, 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) ConnectNodesChain

func (s *Simulation) ConnectNodesChain(ids []discover.NodeID) (err error)

ConnectNodesChain connects all nodes in a chain topology. If ids argument is nil, all nodes that are up will be connected.

func (*Simulation) ConnectNodesFull

func (s *Simulation) ConnectNodesFull(ids []discover.NodeID) (err error)

ConnectNodesFull connects all nodes one to another. It provides a complete connectivity in the network which should be rarely needed.

func (*Simulation) ConnectNodesRing

func (s *Simulation) ConnectNodesRing(ids []discover.NodeID) (err error)

ConnectNodesRing connects all nodes in a ring topology. If ids argument is nil, all nodes that are up will be connected.

func (*Simulation) ConnectNodesStar

func (s *Simulation) ConnectNodesStar(id discover.NodeID, ids []discover.NodeID) (err error)

ConnectNodesStar connects all nodes in a star topology with the center at provided NodeID. If ids argument is nil, all nodes that are up will be connected.

func (*Simulation) ConnectNodesStarPivot

func (s *Simulation) ConnectNodesStarPivot(ids []discover.NodeID) (err error)

ConnectNodesStarPivot connects all nodes in a star topology with the center at already set pivot node. If ids argument is nil, all nodes that are up will be connected.

func (*Simulation) ConnectToLastNode

func (s *Simulation) ConnectToLastNode(id discover.NodeID) (err error)

ConnectToLastNode connects the node with provided NodeID to the last node that is up, and avoiding connection to self. It is useful when constructing a chain network topology when simulation adds and removes nodes dynamically.

func (*Simulation) ConnectToPivotNode

func (s *Simulation) ConnectToPivotNode(id discover.NodeID) (err error)

ConnectToPivotNode connects the node with provided NodeID to the pivot node, already set by Simulation.SetPivotNode method. It is useful when constructing a star network topology when simulation adds and removes nodes dynamically.

func (*Simulation) ConnectToRandomNode

func (s *Simulation) ConnectToRandomNode(id discover.NodeID) (err error)

ConnectToRandomNode connects the node with provieded NodeID to a random node that is up.

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 []discover.NodeID)

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

func (*Simulation) NodeIDs

func (s *Simulation) NodeIDs() (ids []discover.NodeID)

NodeIDs returns NodeIDs for all nodes in the network.

func (*Simulation) NodeItem

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

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

func (*Simulation) NodesItems

func (s *Simulation) NodesItems(key interface{}) (values map[discover.NodeID]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 []discover.NodeID, 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/blockchain-analysis-study/go-ethereum-analysis/log"
	"github.com/blockchain-analysis-study/go-ethereum-analysis/swarm/network/simulation"
)

func main() {
	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.Event.Peer, "msgcode", e.Event.MsgCode)
		}
	}()
}
Output:

Example (Disconnections)

Detect when a nodes drop a peer.

package main

import (
	"context"

	"github.com/blockchain-analysis-study/go-ethereum-analysis/log"
	"github.com/blockchain-analysis-study/go-ethereum-analysis/p2p"
	"github.com/blockchain-analysis-study/go-ethereum-analysis/swarm/network/simulation"
)

func main() {
	sim := simulation.New(nil)
	defer sim.Close()

	disconnections := sim.PeerEvents(
		context.Background(),
		sim.NodeIDs(),
		simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop),
	)

	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.Event.Peer)
		}
	}()
}
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/blockchain-analysis-study/go-ethereum-analysis/log"
	"github.com/blockchain-analysis-study/go-ethereum-analysis/p2p"
	"github.com/blockchain-analysis-study/go-ethereum-analysis/swarm/network/simulation"
)

func main() {
	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().Type(p2p.PeerEventTypeMsgRecv).Protocol("bzz").MsgCode(1),
		simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).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.Event.Peer)
		}
	}()
}
Output:

func (*Simulation) PivotNodeID

func (s *Simulation) PivotNodeID() (id *discover.NodeID)

PivotNodeID returns NodeID of the pivot node set by Simulation.SetPivotNode method.

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) RandomUpNode

func (s *Simulation) RandomUpNode(exclude ...discover.NodeID) *adapters.SimNode

RandomUpNode returns a random SimNode that is up. Arguments are NodeIDs for nodes that should not be returned.

func (*Simulation) Run

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

Run calls the RunFunc function while taking care of cancelation 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 discover.NodeID) 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[discover.NodeID]node.Service)

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

func (*Simulation) SetNodeItem

func (s *Simulation) SetNodeItem(id discover.NodeID, 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) SetPivotNode

func (s *Simulation) SetPivotNode(id discover.NodeID)

SetPivotNode sets the NodeID of the network's pivot node. Pivot node is just a specific node that should be treated differently then other nodes in test. SetPivotNode and PivotNodeID are just a convenient functions to set and retrieve it.

func (*Simulation) StartNode

func (s *Simulation) StartNode(id discover.NodeID) (err error)

StartNode starts a node by NodeID.

func (*Simulation) StartRandomNode

func (s *Simulation) StartRandomNode() (id discover.NodeID, err error)

StartRandomNode starts a random node.

func (*Simulation) StartRandomNodes

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

StartRandomNodes starts random nodes.

func (*Simulation) StopNode

func (s *Simulation) StopNode(id discover.NodeID) (err error)

StopNode stops a node by NodeID.

func (*Simulation) StopRandomNode

func (s *Simulation) StopRandomNode() (id discover.NodeID, err error)

StopRandomNode stops a random node.

func (*Simulation) StopRandomNodes

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

StopRandomNodes stops random nodes.

func (*Simulation) UpNodeIDs

func (s *Simulation) UpNodeIDs() (ids []discover.NodeID)

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

func (*Simulation) UpNodesItems

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

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

func (*Simulation) UploadSnapshot

func (s *Simulation) UploadSnapshot(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, kadMinProxSize int) (ill map[discover.NodeID]*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.

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 Kadmlias healthy.

package main

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

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

func main() {
	sim := simulation.New(map[string]simulation.ServiceFunc{
		"bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
			addr := network.NewAddrFromNodeID(ctx.Config.ID)
			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, 2)
	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) 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