github.com/evdatsion/aphelion-dpos-bft@v0.32.1/p2p/test_util.go (about) 1 package p2p 2 3 import ( 4 "fmt" 5 "net" 6 "time" 7 8 "github.com/evdatsion/aphelion-dpos-bft/crypto" 9 "github.com/evdatsion/aphelion-dpos-bft/crypto/ed25519" 10 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 11 "github.com/evdatsion/aphelion-dpos-bft/libs/log" 12 13 "github.com/evdatsion/aphelion-dpos-bft/config" 14 "github.com/evdatsion/aphelion-dpos-bft/p2p/conn" 15 ) 16 17 const testCh = 0x01 18 19 //------------------------------------------------ 20 21 type mockNodeInfo struct { 22 addr *NetAddress 23 } 24 25 func (ni mockNodeInfo) ID() ID { return ni.addr.ID } 26 func (ni mockNodeInfo) NetAddress() (*NetAddress, error) { return ni.addr, nil } 27 func (ni mockNodeInfo) Validate() error { return nil } 28 func (ni mockNodeInfo) CompatibleWith(other NodeInfo) error { return nil } 29 30 func AddPeerToSwitchPeerSet(sw *Switch, peer Peer) { 31 sw.peers.Add(peer) 32 } 33 34 func CreateRandomPeer(outbound bool) *peer { 35 addr, netAddr := CreateRoutableAddr() 36 p := &peer{ 37 peerConn: peerConn{ 38 outbound: outbound, 39 socketAddr: netAddr, 40 }, 41 nodeInfo: mockNodeInfo{netAddr}, 42 mconn: &conn.MConnection{}, 43 metrics: NopMetrics(), 44 } 45 p.SetLogger(log.TestingLogger().With("peer", addr)) 46 return p 47 } 48 49 func CreateRoutableAddr() (addr string, netAddr *NetAddress) { 50 for { 51 var err error 52 addr = fmt.Sprintf("%X@%v.%v.%v.%v:26656", cmn.RandBytes(20), cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256) 53 netAddr, err = NewNetAddressString(addr) 54 if err != nil { 55 panic(err) 56 } 57 if netAddr.Routable() { 58 break 59 } 60 } 61 return 62 } 63 64 //------------------------------------------------------------------ 65 // Connects switches via arbitrary net.Conn. Used for testing. 66 67 const TEST_HOST = "localhost" 68 69 // MakeConnectedSwitches returns n switches, connected according to the connect func. 70 // If connect==Connect2Switches, the switches will be fully connected. 71 // initSwitch defines how the i'th switch should be initialized (ie. with what reactors). 72 // NOTE: panics if any switch fails to start. 73 func MakeConnectedSwitches(cfg *config.P2PConfig, n int, initSwitch func(int, *Switch) *Switch, connect func([]*Switch, int, int)) []*Switch { 74 switches := make([]*Switch, n) 75 for i := 0; i < n; i++ { 76 switches[i] = MakeSwitch(cfg, i, TEST_HOST, "123.123.123", initSwitch) 77 } 78 79 if err := StartSwitches(switches); err != nil { 80 panic(err) 81 } 82 83 for i := 0; i < n; i++ { 84 for j := i + 1; j < n; j++ { 85 connect(switches, i, j) 86 } 87 } 88 89 return switches 90 } 91 92 // Connect2Switches will connect switches i and j via net.Pipe(). 93 // Blocks until a connection is established. 94 // NOTE: caller ensures i and j are within bounds. 95 func Connect2Switches(switches []*Switch, i, j int) { 96 switchI := switches[i] 97 switchJ := switches[j] 98 99 c1, c2 := conn.NetPipe() 100 101 doneCh := make(chan struct{}) 102 go func() { 103 err := switchI.addPeerWithConnection(c1) 104 if err != nil { 105 panic(err) 106 } 107 doneCh <- struct{}{} 108 }() 109 go func() { 110 err := switchJ.addPeerWithConnection(c2) 111 if err != nil { 112 panic(err) 113 } 114 doneCh <- struct{}{} 115 }() 116 <-doneCh 117 <-doneCh 118 } 119 120 func (sw *Switch) addPeerWithConnection(conn net.Conn) error { 121 pc, err := testInboundPeerConn(conn, sw.config, sw.nodeKey.PrivKey) 122 if err != nil { 123 if err := conn.Close(); err != nil { 124 sw.Logger.Error("Error closing connection", "err", err) 125 } 126 return err 127 } 128 129 ni, err := handshake(conn, time.Second, sw.nodeInfo) 130 if err != nil { 131 if err := conn.Close(); err != nil { 132 sw.Logger.Error("Error closing connection", "err", err) 133 } 134 return err 135 } 136 137 p := newPeer( 138 pc, 139 MConnConfig(sw.config), 140 ni, 141 sw.reactorsByCh, 142 sw.chDescs, 143 sw.StopPeerForError, 144 ) 145 146 if err = sw.addPeer(p); err != nil { 147 pc.CloseConn() 148 return err 149 } 150 151 return nil 152 } 153 154 // StartSwitches calls sw.Start() for each given switch. 155 // It returns the first encountered error. 156 func StartSwitches(switches []*Switch) error { 157 for _, s := range switches { 158 err := s.Start() // start switch and reactors 159 if err != nil { 160 return err 161 } 162 } 163 return nil 164 } 165 166 func MakeSwitch( 167 cfg *config.P2PConfig, 168 i int, 169 network, version string, 170 initSwitch func(int, *Switch) *Switch, 171 opts ...SwitchOption, 172 ) *Switch { 173 174 nodeKey := NodeKey{ 175 PrivKey: ed25519.GenPrivKey(), 176 } 177 nodeInfo := testNodeInfo(nodeKey.ID(), fmt.Sprintf("node%d", i)) 178 addr, err := NewNetAddressString( 179 IDAddressString(nodeKey.ID(), nodeInfo.(DefaultNodeInfo).ListenAddr), 180 ) 181 if err != nil { 182 panic(err) 183 } 184 185 t := NewMultiplexTransport(nodeInfo, nodeKey, MConnConfig(cfg)) 186 187 if err := t.Listen(*addr); err != nil { 188 panic(err) 189 } 190 191 // TODO: let the config be passed in? 192 sw := initSwitch(i, NewSwitch(cfg, t, opts...)) 193 sw.SetLogger(log.TestingLogger().With("switch", i)) 194 sw.SetNodeKey(&nodeKey) 195 196 ni := nodeInfo.(DefaultNodeInfo) 197 for ch := range sw.reactorsByCh { 198 ni.Channels = append(ni.Channels, ch) 199 } 200 nodeInfo = ni 201 202 // TODO: We need to setup reactors ahead of time so the NodeInfo is properly 203 // populated and we don't have to do those awkward overrides and setters. 204 t.nodeInfo = nodeInfo 205 sw.SetNodeInfo(nodeInfo) 206 207 return sw 208 } 209 210 func testInboundPeerConn( 211 conn net.Conn, 212 config *config.P2PConfig, 213 ourNodePrivKey crypto.PrivKey, 214 ) (peerConn, error) { 215 return testPeerConn(conn, config, false, false, ourNodePrivKey, nil) 216 } 217 218 func testPeerConn( 219 rawConn net.Conn, 220 cfg *config.P2PConfig, 221 outbound, persistent bool, 222 ourNodePrivKey crypto.PrivKey, 223 socketAddr *NetAddress, 224 ) (pc peerConn, err error) { 225 conn := rawConn 226 227 // Fuzz connection 228 if cfg.TestFuzz { 229 // so we have time to do peer handshakes and get set up 230 conn = FuzzConnAfterFromConfig(conn, 10*time.Second, cfg.TestFuzzConfig) 231 } 232 233 // Encrypt connection 234 conn, err = upgradeSecretConn(conn, cfg.HandshakeTimeout, ourNodePrivKey) 235 if err != nil { 236 return pc, cmn.ErrorWrap(err, "Error creating peer") 237 } 238 239 // Only the information we already have 240 return newPeerConn(outbound, persistent, conn, socketAddr), nil 241 } 242 243 //---------------------------------------------------------------- 244 // rand node info 245 246 func testNodeInfo(id ID, name string) NodeInfo { 247 return testNodeInfoWithNetwork(id, name, "testing") 248 } 249 250 func testNodeInfoWithNetwork(id ID, name, network string) NodeInfo { 251 return DefaultNodeInfo{ 252 ProtocolVersion: defaultProtocolVersion, 253 ID_: id, 254 ListenAddr: fmt.Sprintf("127.0.0.1:%d", getFreePort()), 255 Network: network, 256 Version: "1.2.3-rc0-deadbeef", 257 Channels: []byte{testCh}, 258 Moniker: name, 259 Other: DefaultNodeInfoOther{ 260 TxIndex: "on", 261 RPCAddress: fmt.Sprintf("127.0.0.1:%d", getFreePort()), 262 }, 263 } 264 } 265 266 func getFreePort() int { 267 port, err := cmn.GetFreePort() 268 if err != nil { 269 panic(err) 270 } 271 return port 272 }