Skip to content
This repository has been archived by the owner on Aug 2, 2021. It is now read-only.

Leaner swarm/network and p2p/simulations #1076

Closed
wants to merge 18 commits into from
Closed
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
2 changes: 1 addition & 1 deletion p2p/simulations/adapters/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import (

func init() {
// Register a reexec function to start a simulation node when the current binary is
// executed as "p2p-node" (rather than whataver the main() function would normally do).
// executed as "p2p-node" (rather than whatever the main() function would normally do).
reexec.Register("p2p-node", execP2PNode)
}

Expand Down
16 changes: 1 addition & 15 deletions p2p/simulations/adapters/inproc.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (s *SimAdapter) Dial(dest *enode.Node) (conn net.Conn, err error) {
return nil, err
}
// this is simulated 'listening'
// asynchronously call the dialed destintion node's p2p server
// asynchronously call the dialed destination node's p2p server
// to set up connection on the 'listening' side
go srv.SetupConn(pipe1, 0, nil)
return pipe2, nil
Expand Down Expand Up @@ -351,17 +351,3 @@ func (sn *SimNode) NodeInfo() *p2p.NodeInfo {
}
return server.NodeInfo()
}

func setSocketBuffer(conn net.Conn, socketReadBuffer int, socketWriteBuffer int) error {
if v, ok := conn.(*net.UnixConn); ok {
err := v.SetReadBuffer(socketReadBuffer)
if err != nil {
return err
}
err = v.SetWriteBuffer(socketWriteBuffer)
if err != nil {
return err
}
}
return nil
}
110 changes: 0 additions & 110 deletions p2p/simulations/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,73 +17,11 @@
package simulations

import (
"errors"
"strings"

"github.com/ethereum/go-ethereum/p2p/enode"
)

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

// ConnectToPivotNode connects the node with provided NodeID
// to the pivot node, already set by Network.SetPivotNode method.
// It is useful when constructing a star network topology
// when Network adds and removes nodes dynamically.
func (net *Network) ConnectToPivotNode(id enode.ID) (err error) {
pivot := net.GetPivotNode()
if pivot == nil {
return ErrNoPivotNode
}
return net.connect(pivot.ID(), id)
}

// 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 Network adds and removes nodes dynamically.
func (net *Network) ConnectToLastNode(id enode.ID) (err error) {
ids := net.getUpNodeIDs()
l := len(ids)
if l < 2 {
return nil
}
last := ids[l-1]
if last == id {
last = ids[l-2]
}
return net.connect(last, id)
}

// ConnectToRandomNode connects the node with provided NodeID
// to a random node that is up.
func (net *Network) ConnectToRandomNode(id enode.ID) (err error) {
selected := net.GetRandomUpNode(id)
if selected == nil {
return ErrNodeNotFound
}
return net.connect(selected.ID(), id)
}

// ConnectNodesFull connects all nodes one to another.
// It provides a complete connectivity in the network
// which should be rarely needed.
func (net *Network) ConnectNodesFull(ids []enode.ID) (err error) {
if ids == nil {
ids = net.getUpNodeIDs()
}
for i, lid := range ids {
for _, rid := range ids[i+1:] {
if err = net.connect(lid, rid); err != nil {
return err
}
}
}
return nil
}

// ConnectNodesChain connects all nodes in a chain topology.
// If ids argument is nil, all nodes that are up will be connected.
func (net *Network) ConnectNodesChain(ids []enode.ID) (err error) {
Expand Down Expand Up @@ -115,35 +53,6 @@ func (net *Network) ConnectNodesRing(ids []enode.ID) (err error) {
return net.connect(ids[l-1], ids[0])
}

// 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 (net *Network) ConnectNodesStar(pivot enode.ID, ids []enode.ID) (err error) {
if ids == nil {
ids = net.getUpNodeIDs()
}
for _, id := range ids {
if pivot == id {
continue
}
if err := net.connect(pivot, id); err != nil {
return err
}
}
return nil
}

// 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 (net *Network) ConnectNodesStarPivot(ids []enode.ID) (err error) {
pivot := net.GetPivotNode()
if pivot == nil {
return ErrNoPivotNode
}
return net.ConnectNodesStar(pivot.ID(), ids)
}

// connect connects two nodes but ignores already connected error.
func (net *Network) connect(oneID, otherID enode.ID) error {
return ignoreAlreadyConnectedErr(net.Connect(oneID, otherID))
Expand All @@ -155,22 +64,3 @@ func ignoreAlreadyConnectedErr(err error) error {
}
return err
}

// 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
// GetPivotNode are just a convenient functions to set and
// retrieve it.
func (net *Network) SetPivotNode(id enode.ID) {
net.lock.Lock()
defer net.lock.Unlock()
net.pivotNodeID = id
}

// GetPivotNode returns NodeID of the pivot node set by
// Network.SetPivotNode method.
func (net *Network) GetPivotNode() (node *Node) {
net.lock.RLock()
defer net.lock.RUnlock()
return net.getNode(net.pivotNodeID)
}
141 changes: 36 additions & 105 deletions p2p/simulations/connect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
)

func newTestNetwork(t *testing.T, nodeCount int) (*Network, []enode.ID) {
t.Helper()
adapter := adapters.NewSimAdapter(adapters.Services{
"noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
return NewNoopService(nil), nil
Expand Down Expand Up @@ -57,94 +58,35 @@ func newTestNetwork(t *testing.T, nodeCount int) (*Network, []enode.ID) {
return network, ids
}

func TestConnectToPivotNode(t *testing.T) {
net, ids := newTestNetwork(t, 2)
defer net.Shutdown()

pivot := ids[0]
net.SetPivotNode(pivot)

other := ids[1]
err := net.ConnectToPivotNode(other)
if err != nil {
t.Fatal(err)
}

if net.GetConn(pivot, other) == nil {
t.Error("pivot and the other node are not connected")
}
}

func TestConnectToLastNode(t *testing.T) {
func TestConnectNodesChain(t *testing.T) {
net, ids := newTestNetwork(t, 10)
defer net.Shutdown()

first := ids[0]
if err := net.ConnectToLastNode(first); err != nil {
err := net.ConnectNodesChain(ids)
if err != nil {
t.Fatal(err)
}

last := ids[len(ids)-1]
for i, id := range ids {
if id == first || id == last {
continue
}

if net.GetConn(first, id) != nil {
t.Errorf("connection must not exist with node(ind: %v, id: %v)", i, id)
}
}

if net.GetConn(first, last) == nil {
t.Error("first and last node must be connected")
}
verifyChain(t, net, ids)
}

func TestConnectToRandomNode(t *testing.T) {
net, ids := newTestNetwork(t, 10)
defer net.Shutdown()

err := net.ConnectToRandomNode(ids[0])
if err != nil {
t.Fatal(err)
}

var cc int
for i, a := range ids {
for _, b := range ids[i:] {
if net.GetConn(a, b) != nil {
cc++
func verifyChain(t *testing.T, net *Network, ids []enode.ID) {
t.Helper()
n := len(ids)
for i := 0; i < n; i++ {
for j := i + 1; j < n; j++ {
c := net.GetConn(ids[i], ids[j])
if i == j-1 {
if c == nil {
t.Errorf("nodes %v and %v are not connected, but they should be", i, j)
}
} else {
if c != nil {
t.Errorf("nodes %v and %v are connected, but they should not be", i, j)
}
}
}
}

if cc != 1 {
t.Errorf("expected one connection, got %v", cc)
}
}

func TestConnectNodesFull(t *testing.T) {
net, ids := newTestNetwork(t, 12)
defer net.Shutdown()

err := net.ConnectNodesFull(ids)
if err != nil {
t.Fatal(err)
}

VerifyFull(t, net, ids)
}

func TestConnectNodesChain(t *testing.T) {
net, ids := newTestNetwork(t, 10)
defer net.Shutdown()

err := net.ConnectNodesChain(ids)
if err != nil {
t.Fatal(err)
}

VerifyChain(t, net, ids)
}

func TestConnectNodesRing(t *testing.T) {
Expand All @@ -156,35 +98,24 @@ func TestConnectNodesRing(t *testing.T) {
t.Fatal(err)
}

VerifyRing(t, net, ids)
verifyRing(t, net, ids)
}

func TestConnectNodesStar(t *testing.T) {
net, ids := newTestNetwork(t, 10)
defer net.Shutdown()

pivotIndex := 2

err := net.ConnectNodesStar(ids[pivotIndex], ids)
if err != nil {
t.Fatal(err)
}

VerifyStar(t, net, ids, pivotIndex)
}

func TestConnectNodesStarPivot(t *testing.T) {
net, ids := newTestNetwork(t, 10)
defer net.Shutdown()

pivotIndex := 4

net.SetPivotNode(ids[pivotIndex])

err := net.ConnectNodesStarPivot(ids)
if err != nil {
t.Fatal(err)
func verifyRing(t *testing.T, net *Network, ids []enode.ID) {
t.Helper()
n := len(ids)
for i := 0; i < n; i++ {
for j := i + 1; j < n; j++ {
c := net.GetConn(ids[i], ids[j])
if i == j-1 || (i == 0 && j == n-1) {
if c == nil {
t.Errorf("nodes %v and %v are not connected, but they should be", i, j)
}
} else {
if c != nil {
t.Errorf("nodes %v and %v are connected, but they should not be", i, j)
}
}
}
}

VerifyStar(t, net, ids, pivotIndex)
}
3 changes: 2 additions & 1 deletion p2p/simulations/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/rpc"
colorable "github.com/mattn/go-colorable"
"github.com/mattn/go-colorable"
)

var (
Expand Down Expand Up @@ -294,6 +294,7 @@ var testServices = adapters.Services{
}

func testHTTPServer(t *testing.T) (*Network, *httptest.Server) {
t.Helper()
adapter := adapters.NewSimAdapter(testServices)
network := NewNetwork(adapter, &NetworkConfig{
DefaultService: "test",
Expand Down
Loading