Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p2p/simulations: add node properties support and utility functions #20060

Merged
merged 3 commits into from
Oct 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions p2p/simulations/adapters/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,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 @@ -120,6 +125,7 @@ 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"`
Port uint16 `json:"port"`
}
Expand All @@ -131,6 +137,7 @@ 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,
}
Expand Down Expand Up @@ -168,6 +175,7 @@ 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

Expand Down
122 changes: 114 additions & 8 deletions p2p/simulations/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ type Network struct {
Nodes []*Node `json:"nodes"`
nodeMap 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 @@ -71,6 +74,7 @@ func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network
NetworkConfig: *conf,
nodeAdapter: nodeAdapter,
nodeMap: make(map[enode.ID]int),
propertyMap: make(map[string][]int),
connMap: make(map[string]int),
quitc: make(chan struct{}),
}
Expand Down Expand Up @@ -120,9 +124,16 @@ func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error)
Config: conf,
}
log.Trace("Node created", "id", conf.ID)
net.nodeMap[conf.ID] = len(net.Nodes)

nodeIndex := len(net.Nodes)
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 @@ -410,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 @@ -427,19 +438,104 @@ func (net *Network) getNodeByName(name string) *Node {
return nil
}

// GetNodes returns the existing nodes
func (net *Network) GetNodes() (nodes []*Node) {
// 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 {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getNodes(excludeIDs)
}

func (net *Network) getNodes(excludeIDs []enode.ID) []*Node {
if len(excludeIDs) > 0 {
nodeIDs := net.getNodeIDs(excludeIDs)
return net.getNodesByID(nodeIDs)
} else {
return net.Nodes
}
}

// GetNodesByID returns existing nodes with the given enode.IDs.
// If a node doesn't exist with a given enode.ID, it is ignored.
func (net *Network) GetNodesByID(nodeIDs []enode.ID) []*Node {
net.lock.RLock()
defer net.lock.RUnlock()

return net.getNodesByID(nodeIDs)
}

func (net *Network) getNodesByID(nodeIDs []enode.ID) []*Node {
nodes := make([]*Node, 0, len(nodeIDs))
for _, id := range nodeIDs {
node := net.getNode(id)
if node != nil {
nodes = append(nodes, node)
}
}

return nodes
}

// 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.getNodes()
return net.getNodesByProperty(property)
}

func (net *Network) getNodes() (nodes []*Node) {
nodes = append(nodes, net.Nodes...)
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 nodes
}

// 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.getNodeIDsByProperty(property)
}

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 nodeIDs
}

// GetRandomUpNode returns a random node on the network, which is running.
func (net *Network) GetRandomUpNode(excludeIDs ...enode.ID) *Node {
net.lock.RLock()
Expand Down Expand Up @@ -469,14 +565,21 @@ func (net *Network) GetRandomDownNode(excludeIDs ...enode.ID) *Node {
}

func (net *Network) getDownNodeIDs() (ids []enode.ID) {
for _, node := range net.getNodes() {
for _, node := range net.Nodes {
if !node.Up() {
ids = append(ids, node.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 @@ -616,6 +719,7 @@ func (net *Network) Reset() {
//re-initialize the maps
net.connMap = make(map[string]int)
net.nodeMap = make(map[enode.ID]int)
net.propertyMap = make(map[string][]int)

net.Nodes = nil
net.Conns = nil
Expand All @@ -634,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