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