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 }