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