github.com/bcnmy/go-ethereum@v1.10.27/p2p/simulations/connect.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package simulations
    18  
    19  import (
    20  	"errors"
    21  	"strings"
    22  
    23  	"github.com/ethereum/go-ethereum/p2p/enode"
    24  )
    25  
    26  var (
    27  	ErrNodeNotFound = errors.New("node not found")
    28  )
    29  
    30  // ConnectToLastNode connects the node with provided NodeID
    31  // to the last node that is up, and avoiding connection to self.
    32  // It is useful when constructing a chain network topology
    33  // when Network adds and removes nodes dynamically.
    34  func (net *Network) ConnectToLastNode(id enode.ID) (err error) {
    35  	net.lock.Lock()
    36  	defer net.lock.Unlock()
    37  
    38  	ids := net.getUpNodeIDs()
    39  	l := len(ids)
    40  	if l < 2 {
    41  		return nil
    42  	}
    43  	last := ids[l-1]
    44  	if last == id {
    45  		last = ids[l-2]
    46  	}
    47  	return net.connectNotConnected(last, id)
    48  }
    49  
    50  // ConnectToRandomNode connects the node with provided NodeID
    51  // to a random node that is up.
    52  func (net *Network) ConnectToRandomNode(id enode.ID) (err error) {
    53  	net.lock.Lock()
    54  	defer net.lock.Unlock()
    55  
    56  	selected := net.getRandomUpNode(id)
    57  	if selected == nil {
    58  		return ErrNodeNotFound
    59  	}
    60  	return net.connectNotConnected(selected.ID(), id)
    61  }
    62  
    63  // ConnectNodesFull connects all nodes one to another.
    64  // It provides a complete connectivity in the network
    65  // which should be rarely needed.
    66  func (net *Network) ConnectNodesFull(ids []enode.ID) (err error) {
    67  	net.lock.Lock()
    68  	defer net.lock.Unlock()
    69  
    70  	if ids == nil {
    71  		ids = net.getUpNodeIDs()
    72  	}
    73  	for i, lid := range ids {
    74  		for _, rid := range ids[i+1:] {
    75  			if err = net.connectNotConnected(lid, rid); err != nil {
    76  				return err
    77  			}
    78  		}
    79  	}
    80  	return nil
    81  }
    82  
    83  // ConnectNodesChain connects all nodes in a chain topology.
    84  // If ids argument is nil, all nodes that are up will be connected.
    85  func (net *Network) ConnectNodesChain(ids []enode.ID) (err error) {
    86  	net.lock.Lock()
    87  	defer net.lock.Unlock()
    88  
    89  	return net.connectNodesChain(ids)
    90  }
    91  
    92  func (net *Network) connectNodesChain(ids []enode.ID) (err error) {
    93  	if ids == nil {
    94  		ids = net.getUpNodeIDs()
    95  	}
    96  	l := len(ids)
    97  	for i := 0; i < l-1; i++ {
    98  		if err := net.connectNotConnected(ids[i], ids[i+1]); err != nil {
    99  			return err
   100  		}
   101  	}
   102  	return nil
   103  }
   104  
   105  // ConnectNodesRing connects all nodes in a ring topology.
   106  // If ids argument is nil, all nodes that are up will be connected.
   107  func (net *Network) ConnectNodesRing(ids []enode.ID) (err error) {
   108  	net.lock.Lock()
   109  	defer net.lock.Unlock()
   110  
   111  	if ids == nil {
   112  		ids = net.getUpNodeIDs()
   113  	}
   114  	l := len(ids)
   115  	if l < 2 {
   116  		return nil
   117  	}
   118  	if err := net.connectNodesChain(ids); err != nil {
   119  		return err
   120  	}
   121  	return net.connectNotConnected(ids[l-1], ids[0])
   122  }
   123  
   124  // ConnectNodesStar connects all nodes into a star topology
   125  // If ids argument is nil, all nodes that are up will be connected.
   126  func (net *Network) ConnectNodesStar(ids []enode.ID, center enode.ID) (err error) {
   127  	net.lock.Lock()
   128  	defer net.lock.Unlock()
   129  
   130  	if ids == nil {
   131  		ids = net.getUpNodeIDs()
   132  	}
   133  	for _, id := range ids {
   134  		if center == id {
   135  			continue
   136  		}
   137  		if err := net.connectNotConnected(center, id); err != nil {
   138  			return err
   139  		}
   140  	}
   141  	return nil
   142  }
   143  
   144  func (net *Network) connectNotConnected(oneID, otherID enode.ID) error {
   145  	return ignoreAlreadyConnectedErr(net.connect(oneID, otherID))
   146  }
   147  
   148  func ignoreAlreadyConnectedErr(err error) error {
   149  	if err == nil || strings.Contains(err.Error(), "already connected") {
   150  		return nil
   151  	}
   152  	return err
   153  }