This commit adds all changes needed for the merge of swarm-network-rewrite. The changes: - build: increase linter timeout - contracts/ens: export ensNode - log: add Output method and enable fractional seconds in format - metrics: relax test timeout - p2p: reduced some log levels, updates to simulation packages - rpc: increased maxClientSubscriptionBuffer to 20000
		
			
				
	
	
		
			161 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/ethereum/go-ethereum/p2p/discover"
 | 
						|
	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
 | 
						|
)
 | 
						|
 | 
						|
// TestNetworkSimulation creates a multi-node simulation network with each node
 | 
						|
// connected in a ring topology, checks that all nodes successfully handshake
 | 
						|
// with each other and that a snapshot fully represents the desired topology
 | 
						|
func TestNetworkSimulation(t *testing.T) {
 | 
						|
	// create simulation network with 20 testService nodes
 | 
						|
	adapter := adapters.NewSimAdapter(adapters.Services{
 | 
						|
		"test": newTestService,
 | 
						|
	})
 | 
						|
	network := NewNetwork(adapter, &NetworkConfig{
 | 
						|
		DefaultService: "test",
 | 
						|
	})
 | 
						|
	defer network.Shutdown()
 | 
						|
	nodeCount := 20
 | 
						|
	ids := make([]discover.NodeID, nodeCount)
 | 
						|
	for i := 0; i < nodeCount; i++ {
 | 
						|
		conf := adapters.RandomNodeConfig()
 | 
						|
		node, err := network.NewNodeWithConfig(conf)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatalf("error creating node: %s", err)
 | 
						|
		}
 | 
						|
		if err := network.Start(node.ID()); err != nil {
 | 
						|
			t.Fatalf("error starting node: %s", err)
 | 
						|
		}
 | 
						|
		ids[i] = node.ID()
 | 
						|
	}
 | 
						|
 | 
						|
	// perform a check which connects the nodes in a ring (so each node is
 | 
						|
	// connected to exactly two peers) and then checks that all nodes
 | 
						|
	// performed two handshakes by checking their peerCount
 | 
						|
	action := func(_ context.Context) error {
 | 
						|
		for i, id := range ids {
 | 
						|
			peerID := ids[(i+1)%len(ids)]
 | 
						|
			if err := network.Connect(id, peerID); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	check := func(ctx context.Context, id discover.NodeID) (bool, error) {
 | 
						|
		// check we haven't run out of time
 | 
						|
		select {
 | 
						|
		case <-ctx.Done():
 | 
						|
			return false, ctx.Err()
 | 
						|
		default:
 | 
						|
		}
 | 
						|
 | 
						|
		// get the node
 | 
						|
		node := network.GetNode(id)
 | 
						|
		if node == nil {
 | 
						|
			return false, fmt.Errorf("unknown node: %s", id)
 | 
						|
		}
 | 
						|
 | 
						|
		// check it has exactly two peers
 | 
						|
		client, err := node.Client()
 | 
						|
		if err != nil {
 | 
						|
			return false, err
 | 
						|
		}
 | 
						|
		var peerCount int64
 | 
						|
		if err := client.CallContext(ctx, &peerCount, "test_peerCount"); err != nil {
 | 
						|
			return false, err
 | 
						|
		}
 | 
						|
		switch {
 | 
						|
		case peerCount < 2:
 | 
						|
			return false, nil
 | 
						|
		case peerCount == 2:
 | 
						|
			return true, nil
 | 
						|
		default:
 | 
						|
			return false, fmt.Errorf("unexpected peerCount: %d", peerCount)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	timeout := 30 * time.Second
 | 
						|
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	// trigger a check every 100ms
 | 
						|
	trigger := make(chan discover.NodeID)
 | 
						|
	go triggerChecks(ctx, ids, trigger, 100*time.Millisecond)
 | 
						|
 | 
						|
	result := NewSimulation(network).Run(ctx, &Step{
 | 
						|
		Action:  action,
 | 
						|
		Trigger: trigger,
 | 
						|
		Expect: &Expectation{
 | 
						|
			Nodes: ids,
 | 
						|
			Check: check,
 | 
						|
		},
 | 
						|
	})
 | 
						|
	if result.Error != nil {
 | 
						|
		t.Fatalf("simulation failed: %s", result.Error)
 | 
						|
	}
 | 
						|
 | 
						|
	// take a network snapshot and check it contains the correct topology
 | 
						|
	snap, err := network.Snapshot()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	if len(snap.Nodes) != nodeCount {
 | 
						|
		t.Fatalf("expected snapshot to contain %d nodes, got %d", nodeCount, len(snap.Nodes))
 | 
						|
	}
 | 
						|
	if len(snap.Conns) != nodeCount {
 | 
						|
		t.Fatalf("expected snapshot to contain %d connections, got %d", nodeCount, len(snap.Conns))
 | 
						|
	}
 | 
						|
	for i, id := range ids {
 | 
						|
		conn := snap.Conns[i]
 | 
						|
		if conn.One != id {
 | 
						|
			t.Fatalf("expected conn[%d].One to be %s, got %s", i, id, conn.One)
 | 
						|
		}
 | 
						|
		peerID := ids[(i+1)%len(ids)]
 | 
						|
		if conn.Other != peerID {
 | 
						|
			t.Fatalf("expected conn[%d].Other to be %s, got %s", i, peerID, conn.Other)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func triggerChecks(ctx context.Context, ids []discover.NodeID, trigger chan discover.NodeID, interval time.Duration) {
 | 
						|
	tick := time.NewTicker(interval)
 | 
						|
	defer tick.Stop()
 | 
						|
	for {
 | 
						|
		select {
 | 
						|
		case <-tick.C:
 | 
						|
			for _, id := range ids {
 | 
						|
				select {
 | 
						|
				case trigger <- id:
 | 
						|
				case <-ctx.Done():
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
		case <-ctx.Done():
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |