mirror of https://github.com/ethereum/go-ethereum
Fix a conflict in cmd/swarm envVarsOverride function.pull/15748/head
commit
47a8014559
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,35 @@ |
|||||||
|
// Copyright 2017 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 adapters |
||||||
|
|
||||||
|
type SimStateStore struct { |
||||||
|
m map[string][]byte |
||||||
|
} |
||||||
|
|
||||||
|
func (self *SimStateStore) Load(s string) ([]byte, error) { |
||||||
|
return self.m[s], nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *SimStateStore) Save(s string, data []byte) error { |
||||||
|
self.m[s] = data |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func NewSimStateStore() *SimStateStore { |
||||||
|
return &SimStateStore{ |
||||||
|
make(map[string][]byte), |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,192 @@ |
|||||||
|
// Copyright 2017 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 simulations simulates p2p networks.
|
||||||
|
// A mocker simulates starting and stopping real nodes in a network.
|
||||||
|
package simulations |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"math/rand" |
||||||
|
"sync" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/log" |
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover" |
||||||
|
) |
||||||
|
|
||||||
|
//a map of mocker names to its function
|
||||||
|
var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int){ |
||||||
|
"startStop": startStop, |
||||||
|
"probabilistic": probabilistic, |
||||||
|
"boot": boot, |
||||||
|
} |
||||||
|
|
||||||
|
//Lookup a mocker by its name, returns the mockerFn
|
||||||
|
func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) { |
||||||
|
return mockerList[mockerType] |
||||||
|
} |
||||||
|
|
||||||
|
//Get a list of mockers (keys of the map)
|
||||||
|
//Useful for frontend to build available mocker selection
|
||||||
|
func GetMockerList() []string { |
||||||
|
list := make([]string, 0, len(mockerList)) |
||||||
|
for k := range mockerList { |
||||||
|
list = append(list, k) |
||||||
|
} |
||||||
|
return list |
||||||
|
} |
||||||
|
|
||||||
|
//The boot mockerFn only connects the node in a ring and doesn't do anything else
|
||||||
|
func boot(net *Network, quit chan struct{}, nodeCount int) { |
||||||
|
_, err := connectNodesInRing(net, nodeCount) |
||||||
|
if err != nil { |
||||||
|
panic("Could not startup node network for mocker") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//The startStop mockerFn stops and starts nodes in a defined period (ticker)
|
||||||
|
func startStop(net *Network, quit chan struct{}, nodeCount int) { |
||||||
|
nodes, err := connectNodesInRing(net, nodeCount) |
||||||
|
if err != nil { |
||||||
|
panic("Could not startup node network for mocker") |
||||||
|
} |
||||||
|
tick := time.NewTicker(10 * time.Second) |
||||||
|
defer tick.Stop() |
||||||
|
for { |
||||||
|
select { |
||||||
|
case <-quit: |
||||||
|
log.Info("Terminating simulation loop") |
||||||
|
return |
||||||
|
case <-tick.C: |
||||||
|
id := nodes[rand.Intn(len(nodes))] |
||||||
|
log.Info("stopping node", "id", id) |
||||||
|
if err := net.Stop(id); err != nil { |
||||||
|
log.Error("error stopping node", "id", id, "err", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
select { |
||||||
|
case <-quit: |
||||||
|
log.Info("Terminating simulation loop") |
||||||
|
return |
||||||
|
case <-time.After(3 * time.Second): |
||||||
|
} |
||||||
|
|
||||||
|
log.Debug("starting node", "id", id) |
||||||
|
if err := net.Start(id); err != nil { |
||||||
|
log.Error("error starting node", "id", id, "err", err) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//The probabilistic mocker func has a more probabilistic pattern
|
||||||
|
//(the implementation could probably be improved):
|
||||||
|
//nodes are connected in a ring, then a varying number of random nodes is selected,
|
||||||
|
//mocker then stops and starts them in random intervals, and continues the loop
|
||||||
|
func probabilistic(net *Network, quit chan struct{}, nodeCount int) { |
||||||
|
nodes, err := connectNodesInRing(net, nodeCount) |
||||||
|
if err != nil { |
||||||
|
panic("Could not startup node network for mocker") |
||||||
|
} |
||||||
|
for { |
||||||
|
select { |
||||||
|
case <-quit: |
||||||
|
log.Info("Terminating simulation loop") |
||||||
|
return |
||||||
|
default: |
||||||
|
} |
||||||
|
var lowid, highid int |
||||||
|
var wg sync.WaitGroup |
||||||
|
randWait := time.Duration(rand.Intn(5000)+1000) * time.Millisecond |
||||||
|
rand1 := rand.Intn(nodeCount - 1) |
||||||
|
rand2 := rand.Intn(nodeCount - 1) |
||||||
|
if rand1 < rand2 { |
||||||
|
lowid = rand1 |
||||||
|
highid = rand2 |
||||||
|
} else if rand1 > rand2 { |
||||||
|
highid = rand1 |
||||||
|
lowid = rand2 |
||||||
|
} else { |
||||||
|
if rand1 == 0 { |
||||||
|
rand2 = 9 |
||||||
|
} else if rand1 == 9 { |
||||||
|
rand1 = 0 |
||||||
|
} |
||||||
|
lowid = rand1 |
||||||
|
highid = rand2 |
||||||
|
} |
||||||
|
var steps = highid - lowid |
||||||
|
wg.Add(steps) |
||||||
|
for i := lowid; i < highid; i++ { |
||||||
|
select { |
||||||
|
case <-quit: |
||||||
|
log.Info("Terminating simulation loop") |
||||||
|
return |
||||||
|
case <-time.After(randWait): |
||||||
|
} |
||||||
|
log.Debug(fmt.Sprintf("node %v shutting down", nodes[i])) |
||||||
|
err := net.Stop(nodes[i]) |
||||||
|
if err != nil { |
||||||
|
log.Error(fmt.Sprintf("Error stopping node %s", nodes[i])) |
||||||
|
wg.Done() |
||||||
|
continue |
||||||
|
} |
||||||
|
go func(id discover.NodeID) { |
||||||
|
time.Sleep(randWait) |
||||||
|
err := net.Start(id) |
||||||
|
if err != nil { |
||||||
|
log.Error(fmt.Sprintf("Error starting node %s", id)) |
||||||
|
} |
||||||
|
wg.Done() |
||||||
|
}(nodes[i]) |
||||||
|
} |
||||||
|
wg.Wait() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//connect nodeCount number of nodes in a ring
|
||||||
|
func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error) { |
||||||
|
ids := make([]discover.NodeID, nodeCount) |
||||||
|
for i := 0; i < nodeCount; i++ { |
||||||
|
node, err := net.NewNode() |
||||||
|
if err != nil { |
||||||
|
log.Error("Error creating a node! %s", err) |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
ids[i] = node.ID() |
||||||
|
} |
||||||
|
|
||||||
|
for _, id := range ids { |
||||||
|
if err := net.Start(id); err != nil { |
||||||
|
log.Error("Error starting a node! %s", err) |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
log.Debug(fmt.Sprintf("node %v starting up", id)) |
||||||
|
} |
||||||
|
for i, id := range ids { |
||||||
|
peerID := ids[(i+1)%len(ids)] |
||||||
|
if err := net.Connect(id, peerID); err != nil { |
||||||
|
log.Error("Error connecting a node to a peer! %s", err) |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return ids, nil |
||||||
|
} |
@ -0,0 +1,171 @@ |
|||||||
|
// Copyright 2017 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 simulations simulates p2p networks.
|
||||||
|
// A mokcer simulates starting and stopping real nodes in a network.
|
||||||
|
package simulations |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"net/http" |
||||||
|
"net/url" |
||||||
|
"strconv" |
||||||
|
"sync" |
||||||
|
"testing" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover" |
||||||
|
) |
||||||
|
|
||||||
|
func TestMocker(t *testing.T) { |
||||||
|
//start the simulation HTTP server
|
||||||
|
_, s := testHTTPServer(t) |
||||||
|
defer s.Close() |
||||||
|
|
||||||
|
//create a client
|
||||||
|
client := NewClient(s.URL) |
||||||
|
|
||||||
|
//start the network
|
||||||
|
err := client.StartNetwork() |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Could not start test network: %s", err) |
||||||
|
} |
||||||
|
//stop the network to terminate
|
||||||
|
defer func() { |
||||||
|
err = client.StopNetwork() |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Could not stop test network: %s", err) |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
//get the list of available mocker types
|
||||||
|
resp, err := http.Get(s.URL + "/mocker") |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Could not get mocker list: %s", err) |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
|
||||||
|
if resp.StatusCode != 200 { |
||||||
|
t.Fatalf("Invalid Status Code received, expected 200, got %d", resp.StatusCode) |
||||||
|
} |
||||||
|
|
||||||
|
//check the list is at least 1 in size
|
||||||
|
var mockerlist []string |
||||||
|
err = json.NewDecoder(resp.Body).Decode(&mockerlist) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Error decoding JSON mockerlist: %s", err) |
||||||
|
} |
||||||
|
|
||||||
|
if len(mockerlist) < 1 { |
||||||
|
t.Fatalf("No mockers available") |
||||||
|
} |
||||||
|
|
||||||
|
nodeCount := 10 |
||||||
|
var wg sync.WaitGroup |
||||||
|
|
||||||
|
events := make(chan *Event, 10) |
||||||
|
var opts SubscribeOpts |
||||||
|
sub, err := client.SubscribeNetwork(events, opts) |
||||||
|
defer sub.Unsubscribe() |
||||||
|
//wait until all nodes are started and connected
|
||||||
|
//store every node up event in a map (value is irrelevant, mimic Set datatype)
|
||||||
|
nodemap := make(map[discover.NodeID]bool) |
||||||
|
wg.Add(1) |
||||||
|
nodesComplete := false |
||||||
|
connCount := 0 |
||||||
|
go func() { |
||||||
|
for { |
||||||
|
select { |
||||||
|
case event := <-events: |
||||||
|
//if the event is a node Up event only
|
||||||
|
if event.Node != nil && event.Node.Up { |
||||||
|
//add the correspondent node ID to the map
|
||||||
|
nodemap[event.Node.Config.ID] = true |
||||||
|
//this means all nodes got a nodeUp event, so we can continue the test
|
||||||
|
if len(nodemap) == nodeCount { |
||||||
|
nodesComplete = true |
||||||
|
//wait for 3s as the mocker will need time to connect the nodes
|
||||||
|
//time.Sleep( 3 *time.Second)
|
||||||
|
} |
||||||
|
} else if event.Conn != nil && nodesComplete { |
||||||
|
connCount += 1 |
||||||
|
if connCount == (nodeCount-1)*2 { |
||||||
|
wg.Done() |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
case <-time.After(30 * time.Second): |
||||||
|
wg.Done() |
||||||
|
t.Fatalf("Timeout waiting for nodes being started up!") |
||||||
|
} |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
//take the last element of the mockerlist as the default mocker-type to ensure one is enabled
|
||||||
|
mockertype := mockerlist[len(mockerlist)-1] |
||||||
|
//still, use hardcoded "probabilistic" one if available ;)
|
||||||
|
for _, m := range mockerlist { |
||||||
|
if m == "probabilistic" { |
||||||
|
mockertype = m |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
//start the mocker with nodeCount number of nodes
|
||||||
|
resp, err = http.PostForm(s.URL+"/mocker/start", url.Values{"mocker-type": {mockertype}, "node-count": {strconv.Itoa(nodeCount)}}) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Could not start mocker: %s", err) |
||||||
|
} |
||||||
|
if resp.StatusCode != 200 { |
||||||
|
t.Fatalf("Invalid Status Code received for starting mocker, expected 200, got %d", resp.StatusCode) |
||||||
|
} |
||||||
|
|
||||||
|
wg.Wait() |
||||||
|
|
||||||
|
//check there are nodeCount number of nodes in the network
|
||||||
|
nodes_info, err := client.GetNodes() |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Could not get nodes list: %s", err) |
||||||
|
} |
||||||
|
|
||||||
|
if len(nodes_info) != nodeCount { |
||||||
|
t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodes_info)) |
||||||
|
} |
||||||
|
|
||||||
|
//stop the mocker
|
||||||
|
resp, err = http.Post(s.URL+"/mocker/stop", "", nil) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Could not stop mocker: %s", err) |
||||||
|
} |
||||||
|
if resp.StatusCode != 200 { |
||||||
|
t.Fatalf("Invalid Status Code received for stopping mocker, expected 200, got %d", resp.StatusCode) |
||||||
|
} |
||||||
|
|
||||||
|
//reset the network
|
||||||
|
_, err = http.Post(s.URL+"/reset", "", nil) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Could not reset network: %s", err) |
||||||
|
} |
||||||
|
|
||||||
|
//now the number of nodes in the network should be zero
|
||||||
|
nodes_info, err = client.GetNodes() |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("Could not get nodes list: %s", err) |
||||||
|
} |
||||||
|
|
||||||
|
if len(nodes_info) != 0 { |
||||||
|
t.Fatalf("Expected empty list of nodes, got: %d", len(nodes_info)) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue