Skip to content

Commit

Permalink
p2p/simulations: Add node property (e.g bootnode, etc) support to sim…
Browse files Browse the repository at this point in the history
…ulation networks + Expanded node getter utility functions
  • Loading branch information
chadsr committed Oct 16, 2019
1 parent cf8d752 commit d7bc2a8
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 240 deletions.
20 changes: 8 additions & 12 deletions p2p/simulations/adapters/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,6 @@ type NodeConfig struct {
// Enable peer events for Msgs
EnableMsgEvents bool

// Node will run services as a bootnode
BootNode bool

// Node will run services as a lightnode
LightNode bool

// Name is a human friendly name for the node like "node01"
Name string

Expand All @@ -107,6 +101,11 @@ type NodeConfig struct {
// services registered by calling the RegisterService function)
Services []string

// Properties are the names of the properties this node should hold
// within running services (e.g. "bootnode", "lightnode" or any custom values)
// These values need to be checked and acted upon by node Services
Properties []string

// Enode
node *enode.Node

Expand All @@ -126,9 +125,8 @@ type nodeConfigJSON struct {
PrivateKey string `json:"private_key"`
Name string `json:"name"`
Services []string `json:"services"`
Properties []string `json:"properties"`
EnableMsgEvents bool `json:"enable_msg_events"`
BootNode bool `json:"bootnode"`
LightNode bool `json:"lightnode"`
Port uint16 `json:"port"`
}

Expand All @@ -139,10 +137,9 @@ func (n *NodeConfig) MarshalJSON() ([]byte, error) {
ID: n.ID.String(),
Name: n.Name,
Services: n.Services,
Properties: n.Properties,
Port: n.Port,
EnableMsgEvents: n.EnableMsgEvents,
BootNode: n.BootNode,
LightNode: n.LightNode,
}
if n.PrivateKey != nil {
confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey))
Expand Down Expand Up @@ -178,10 +175,9 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error {

n.Name = confJSON.Name
n.Services = confJSON.Services
n.Properties = confJSON.Properties
n.Port = confJSON.Port
n.EnableMsgEvents = confJSON.EnableMsgEvents
n.BootNode = confJSON.BootNode
n.LightNode = confJSON.LightNode

return nil
}
Expand Down
179 changes: 62 additions & 117 deletions p2p/simulations/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ type Network struct {
Nodes []*Node `json:"nodes"`
nodeMap map[enode.ID]int

// Node subtypes are also mapped separately, so they can be distinguished quickly
bootNodeMap map[enode.ID]int
lightNodeMap map[enode.ID]int
// Maps a node property string to node indexes of all nodes that hold this property
propertyMap map[string][]int

Conns []*Conn `json:"conns"`
connMap map[string]int
Expand All @@ -75,8 +74,7 @@ func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network
NetworkConfig: *conf,
nodeAdapter: nodeAdapter,
nodeMap: make(map[enode.ID]int),
bootNodeMap: make(map[enode.ID]int),
lightNodeMap: make(map[enode.ID]int),
propertyMap: make(map[string][]int),
connMap: make(map[string]int),
quitc: make(chan struct{}),
}
Expand Down Expand Up @@ -128,15 +126,14 @@ func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error)
log.Trace("Node created", "id", conf.ID)

nodeIndex := len(net.Nodes)
if conf.BootNode {
net.bootNodeMap[conf.ID] = nodeIndex
} else if conf.LightNode {
net.lightNodeMap[conf.ID] = nodeIndex
}

net.nodeMap[conf.ID] = nodeIndex
net.Nodes = append(net.Nodes, node)

// Register any node properties with the network-level propertyMap
for _, property := range conf.Properties {
net.propertyMap[property] = append(net.propertyMap[property], nodeIndex)
}

// emit a "control" event
net.events.Send(ControlEvent(node))

Expand Down Expand Up @@ -424,7 +421,7 @@ func (net *Network) getNode(id enode.ID) *Node {
return net.Nodes[i]
}

// GetNode gets the node with the given name, returning nil if the node does
// GetNodeByName gets the node with the given name, returning nil if the node does
// not exist
func (net *Network) GetNodeByName(name string) *Node {
net.lock.RLock()
Expand All @@ -441,6 +438,30 @@ func (net *Network) getNodeByName(name string) *Node {
return nil
}

// GetNodeIDs returns the IDs of all existing nodes
// Nodes can optionally be excluded by specifying their enode.ID.
func (net *Network) GetNodeIDs(excludeIDs ...enode.ID) []enode.ID {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getNodeIDs(excludeIDs)
}

func (net *Network) getNodeIDs(excludeIDs []enode.ID) []enode.ID {
// Get all curent nodeIDs
nodeIDs := make([]enode.ID, 0, len(net.nodeMap))
for id := range net.nodeMap {
nodeIDs = append(nodeIDs, id)
}

if len(excludeIDs) > 0 {
// Return the difference of nodeIDs and excludeIDs
return filterIDs(nodeIDs, excludeIDs)
} else {
return nodeIDs
}
}

// GetNodes returns the existing nodes.
// Nodes can optionally be excluded by specifying their enode.ID.
func (net *Network) GetNodes(excludeIDs ...enode.ID) []*Node {
Expand All @@ -452,15 +473,8 @@ func (net *Network) GetNodes(excludeIDs ...enode.ID) []*Node {

func (net *Network) getNodes(excludeIDs []enode.ID) []*Node {
if len(excludeIDs) > 0 {
// Get all curent nodeIDs
nodeIDs := make([]enode.ID, 0, len(net.nodeMap))
for id := range net.nodeMap {
nodeIDs = append(nodeIDs, id)
}

// Return the difference of nodeIDs and excludeIDs
filteredIDs := filterIDs(nodeIDs, excludeIDs)
return net.getNodesByID(filteredIDs)
nodeIDs := net.getNodeIDs(excludeIDs)
return net.getNodesByID(nodeIDs)
} else {
return net.Nodes
}
Expand All @@ -487,116 +501,39 @@ func (net *Network) getNodesByID(nodeIDs []enode.ID) []*Node {
return nodes
}

// GetBootNodes returns all configured bootnodes in the network.
func (net *Network) GetBootNodes() []*Node {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getBootNodes()
}

func (net *Network) getBootNodes() []*Node {
bootNodes := make([]*Node, 0, len(net.bootNodeMap))
for _, i := range net.bootNodeMap {
bootNodes = append(bootNodes, net.Nodes[i])
}

return bootNodes
}

// GetBootNodeIDs returns a slice of all bootnode enode.ID
func (net *Network) GetBootNodeIDs() []enode.ID {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getBootNodeIDs()
}

func (net *Network) getBootNodeIDs() []enode.ID {
bootNodeIDs := make([]enode.ID, 0, len(net.bootNodeMap))
for id := range net.bootNodeMap {
bootNodeIDs = append(bootNodeIDs, id)
}

return bootNodeIDs
}

// GetLightNodes returns all configured light nodes in the network.
func (net *Network) GetLightNodes() []*Node {
// GetNodesByProperty returns existing nodes that have the given property string registered in their NodeConfig
func (net *Network) GetNodesByProperty(property string) []*Node {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getLightNodes()
return net.getNodesByProperty(property)
}

func (net *Network) getLightNodes() []*Node {
lightNodes := make([]*Node, 0, len(net.lightNodeMap))
for _, i := range net.lightNodeMap {
lightNodes = append(lightNodes, net.Nodes[i])
func (net *Network) getNodesByProperty(property string) []*Node {
nodes := make([]*Node, 0, len(net.propertyMap[property]))
for _, nodeIndex := range net.propertyMap[property] {
nodes = append(nodes, net.Nodes[nodeIndex])
}

return lightNodes
}

// GetLightNodeIDs returns a slice of all light node enode.ID
func (net *Network) GetLightNodeIDs() []enode.ID {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getLightNodeIDs()
}

func (net *Network) getLightNodeIDs() []enode.ID {
lightNodeIDs := make([]enode.ID, 0, len(net.lightNodeMap))
for id := range net.lightNodeMap {
lightNodeIDs = append(lightNodeIDs, id)
}

return lightNodeIDs
}

// GetFullNodes returns all configured full nodes in the network.
// This excludes bootnodes and lightnodes.
func (net *Network) GetFullNodes() []*Node {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getFullNodes()
}

// Collect the enode.IDs of all nodes types that are not full nodes and provide them to getNodes for exclusion
func (net *Network) getFullNodes() []*Node {
excludeNodeCount := len(net.lightNodeMap) + len(net.bootNodeMap)
excludeIDs := make([]enode.ID, 0, excludeNodeCount)
for ID := range net.lightNodeMap {
excludeIDs = append(excludeIDs, ID)
}

for ID := range net.bootNodeMap {
excludeIDs = append(excludeIDs, ID)
}

return net.getNodes(excludeIDs)
return nodes
}

// GetFullNodeIDs returns a slice of all full node enode.ID
func (net *Network) GetFullNodeIDs() []enode.ID {
// GetNodeIDsByProperty returns existing node's enode IDs that have the given property string registered in the NodeConfig
func (net *Network) GetNodeIDsByProperty(property string) []enode.ID {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getFullNodeIDs()
return net.getNodeIDsByProperty(property)
}

func (net *Network) getFullNodeIDs() []enode.ID {
// The number of full nodes is the total number minus all sub mapping counts
fullNodeCount := len(net.nodeMap) - len(net.lightNodeMap) - len(net.bootNodeMap)
fullNodeIDs := make([]enode.ID, 0, fullNodeCount)

for _, node := range net.getFullNodes() {
fullNodeIDs = append(fullNodeIDs, node.ID())
func (net *Network) getNodeIDsByProperty(property string) []enode.ID {
nodeIDs := make([]enode.ID, 0, len(net.propertyMap[property]))
for _, nodeIndex := range net.propertyMap[property] {
node := net.Nodes[nodeIndex]
nodeIDs = append(nodeIDs, node.ID())
}

return fullNodeIDs
return nodeIDs
}

// GetRandomUpNode returns a random node on the network, which is running.
Expand Down Expand Up @@ -636,6 +573,13 @@ func (net *Network) getDownNodeIDs() (ids []enode.ID) {
return ids
}

// GetRandomNode returns a random node on the network, regardless of whether it is running or not
func (net *Network) GetRandomNode(excludeIDs ...enode.ID) *Node {
net.lock.RLock()
defer net.lock.RUnlock()
return net.getRandomNode(net.getNodeIDs(nil), excludeIDs) // no need to exclude twice
}

func (net *Network) getRandomNode(ids []enode.ID, excludeIDs []enode.ID) *Node {
filtered := filterIDs(ids, excludeIDs)

Expand Down Expand Up @@ -775,8 +719,7 @@ func (net *Network) Reset() {
//re-initialize the maps
net.connMap = make(map[string]int)
net.nodeMap = make(map[enode.ID]int)
net.bootNodeMap = make(map[enode.ID]int)
net.lightNodeMap = make(map[enode.ID]int)
net.propertyMap = make(map[string][]int)

net.Nodes = nil
net.Conns = nil
Expand All @@ -795,12 +738,14 @@ type Node struct {
upMu sync.RWMutex
}

// Up returns whether the node is currently up (online)
func (n *Node) Up() bool {
n.upMu.RLock()
defer n.upMu.RUnlock()
return n.up
}

// SetUp sets the up (online) status of the nodes with the given value
func (n *Node) SetUp(up bool) {
n.upMu.Lock()
defer n.upMu.Unlock()
Expand Down
Loading

0 comments on commit d7bc2a8

Please sign in to comment.