github.com/dim4egster/coreth@v0.10.2/peer/network_test.go (about) 1 // (c) 2019-2022, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package peer 5 6 import ( 7 "context" 8 "errors" 9 "fmt" 10 "sync" 11 "sync/atomic" 12 "testing" 13 "time" 14 15 "github.com/dim4egster/qmallgo/snow/engine/common" 16 17 "github.com/dim4egster/coreth/plugin/evm/message" 18 19 "github.com/dim4egster/qmallgo/codec" 20 "github.com/dim4egster/qmallgo/codec/linearcodec" 21 "github.com/dim4egster/qmallgo/ids" 22 "github.com/dim4egster/qmallgo/version" 23 "github.com/stretchr/testify/assert" 24 ) 25 26 var ( 27 defaultPeerVersion = &version.Application{ 28 Major: 1, 29 Minor: 0, 30 Patch: 0, 31 } 32 33 _ message.Request = &HelloRequest{} 34 _ = &HelloResponse{} 35 _ = &GreetingRequest{} 36 _ = &GreetingResponse{} 37 _ = &TestMessage{} 38 39 _ message.RequestHandler = &HelloGreetingRequestHandler{} 40 _ message.RequestHandler = &testRequestHandler{} 41 42 _ common.AppSender = testAppSender{} 43 _ message.GossipMessage = HelloGossip{} 44 _ message.GossipHandler = &testGossipHandler{} 45 ) 46 47 func TestNetworkDoesNotConnectToItself(t *testing.T) { 48 selfNodeID := ids.GenerateTestNodeID() 49 n := NewNetwork(nil, nil, selfNodeID, 1) 50 assert.NoError(t, n.Connected(selfNodeID, defaultPeerVersion)) 51 assert.EqualValues(t, 0, n.Size()) 52 } 53 54 func TestRequestAnyRequestsRoutingAndResponse(t *testing.T) { 55 callNum := uint32(0) 56 senderWg := &sync.WaitGroup{} 57 var net Network 58 sender := testAppSender{ 59 sendAppRequestFn: func(nodes ids.NodeIDSet, requestID uint32, requestBytes []byte) error { 60 nodeID, _ := nodes.Pop() 61 senderWg.Add(1) 62 go func() { 63 defer senderWg.Done() 64 if err := net.AppRequest(nodeID, requestID, time.Now().Add(5*time.Second), requestBytes); err != nil { 65 panic(err) 66 } 67 }() 68 return nil 69 }, 70 sendAppResponseFn: func(nodeID ids.NodeID, requestID uint32, responseBytes []byte) error { 71 senderWg.Add(1) 72 go func() { 73 defer senderWg.Done() 74 if err := net.AppResponse(nodeID, requestID, responseBytes); err != nil { 75 panic(err) 76 } 77 atomic.AddUint32(&callNum, 1) 78 }() 79 return nil 80 }, 81 } 82 83 codecManager := buildCodec(t, HelloRequest{}, HelloResponse{}) 84 net = NewNetwork(sender, codecManager, ids.EmptyNodeID, 16) 85 net.SetRequestHandler(&HelloGreetingRequestHandler{codec: codecManager}) 86 client := NewNetworkClient(net) 87 nodeID := ids.GenerateTestNodeID() 88 assert.NoError(t, net.Connected(nodeID, defaultPeerVersion)) 89 90 requestMessage := HelloRequest{Message: "this is a request"} 91 92 defer net.Shutdown() 93 assert.NoError(t, net.Connected(nodeID, defaultPeerVersion)) 94 95 totalRequests := 5000 96 numCallsPerRequest := 1 // on sending response 97 totalCalls := totalRequests * numCallsPerRequest 98 99 requestWg := &sync.WaitGroup{} 100 requestWg.Add(totalCalls) 101 for i := 0; i < totalCalls; i++ { 102 go func(wg *sync.WaitGroup) { 103 defer wg.Done() 104 requestBytes, err := message.RequestToBytes(codecManager, requestMessage) 105 assert.NoError(t, err) 106 responseBytes, _, err := client.RequestAny(defaultPeerVersion, requestBytes) 107 assert.NoError(t, err) 108 assert.NotNil(t, responseBytes) 109 110 var response TestMessage 111 if _, err = codecManager.Unmarshal(responseBytes, &response); err != nil { 112 panic(fmt.Errorf("unexpected error during unmarshal: %w", err)) 113 } 114 assert.Equal(t, "Hi", response.Message) 115 }(requestWg) 116 } 117 118 requestWg.Wait() 119 senderWg.Wait() 120 assert.Equal(t, totalCalls, int(atomic.LoadUint32(&callNum))) 121 } 122 123 func TestRequestRequestsRoutingAndResponse(t *testing.T) { 124 callNum := uint32(0) 125 senderWg := &sync.WaitGroup{} 126 var net Network 127 var lock sync.Mutex 128 contactedNodes := make(map[ids.NodeID]struct{}) 129 sender := testAppSender{ 130 sendAppRequestFn: func(nodes ids.NodeIDSet, requestID uint32, requestBytes []byte) error { 131 nodeID, _ := nodes.Pop() 132 lock.Lock() 133 contactedNodes[nodeID] = struct{}{} 134 lock.Unlock() 135 senderWg.Add(1) 136 go func() { 137 defer senderWg.Done() 138 if err := net.AppRequest(nodeID, requestID, time.Now().Add(5*time.Second), requestBytes); err != nil { 139 panic(err) 140 } 141 }() 142 return nil 143 }, 144 sendAppResponseFn: func(nodeID ids.NodeID, requestID uint32, responseBytes []byte) error { 145 senderWg.Add(1) 146 go func() { 147 defer senderWg.Done() 148 if err := net.AppResponse(nodeID, requestID, responseBytes); err != nil { 149 panic(err) 150 } 151 atomic.AddUint32(&callNum, 1) 152 }() 153 return nil 154 }, 155 } 156 157 codecManager := buildCodec(t, HelloRequest{}, HelloResponse{}) 158 net = NewNetwork(sender, codecManager, ids.EmptyNodeID, 16) 159 net.SetRequestHandler(&HelloGreetingRequestHandler{codec: codecManager}) 160 client := NewNetworkClient(net) 161 162 nodes := []ids.NodeID{ 163 ids.GenerateTestNodeID(), 164 ids.GenerateTestNodeID(), 165 ids.GenerateTestNodeID(), 166 ids.GenerateTestNodeID(), 167 ids.GenerateTestNodeID(), 168 } 169 for _, nodeID := range nodes { 170 assert.NoError(t, net.Connected(nodeID, defaultPeerVersion)) 171 } 172 173 requestMessage := HelloRequest{Message: "this is a request"} 174 defer net.Shutdown() 175 176 totalRequests := 5000 177 numCallsPerRequest := 1 // on sending response 178 totalCalls := totalRequests * numCallsPerRequest 179 180 requestWg := &sync.WaitGroup{} 181 requestWg.Add(totalCalls) 182 nodeIdx := 0 183 for i := 0; i < totalCalls; i++ { 184 nodeIdx = (nodeIdx + 1) % (len(nodes)) 185 nodeID := nodes[nodeIdx] 186 go func(wg *sync.WaitGroup, nodeID ids.NodeID) { 187 defer wg.Done() 188 requestBytes, err := message.RequestToBytes(codecManager, requestMessage) 189 assert.NoError(t, err) 190 responseBytes, err := client.Request(nodeID, requestBytes) 191 assert.NoError(t, err) 192 assert.NotNil(t, responseBytes) 193 194 var response TestMessage 195 if _, err = codecManager.Unmarshal(responseBytes, &response); err != nil { 196 panic(fmt.Errorf("unexpected error during unmarshal: %w", err)) 197 } 198 assert.Equal(t, "Hi", response.Message) 199 }(requestWg, nodeID) 200 } 201 202 requestWg.Wait() 203 senderWg.Wait() 204 assert.Equal(t, totalCalls, int(atomic.LoadUint32(&callNum))) 205 for _, nodeID := range nodes { 206 if _, exists := contactedNodes[nodeID]; !exists { 207 t.Fatalf("expected nodeID %s to be contacted but was not", nodeID) 208 } 209 } 210 211 // ensure empty nodeID is not allowed 212 _, err := client.Request(ids.EmptyNodeID, []byte("hello there")) 213 assert.Error(t, err) 214 assert.Contains(t, err.Error(), "cannot send request to empty nodeID") 215 } 216 217 func TestRequestMinVersion(t *testing.T) { 218 callNum := uint32(0) 219 nodeID := ids.GenerateTestNodeID() 220 codecManager := buildCodec(t, TestMessage{}) 221 222 var net Network 223 sender := testAppSender{ 224 sendAppRequestFn: func(nodes ids.NodeIDSet, reqID uint32, messageBytes []byte) error { 225 atomic.AddUint32(&callNum, 1) 226 assert.True(t, nodes.Contains(nodeID), "request nodes should contain expected nodeID") 227 assert.Len(t, nodes, 1, "request nodes should contain exactly one node") 228 229 go func() { 230 time.Sleep(200 * time.Millisecond) 231 atomic.AddUint32(&callNum, 1) 232 responseBytes, err := codecManager.Marshal(message.Version, TestMessage{Message: "this is a response"}) 233 if err != nil { 234 panic(err) 235 } 236 err = net.AppResponse(nodeID, reqID, responseBytes) 237 assert.NoError(t, err) 238 }() 239 return nil 240 }, 241 } 242 243 // passing nil as codec works because the net.AppRequest is never called 244 net = NewNetwork(sender, codecManager, ids.EmptyNodeID, 1) 245 client := NewNetworkClient(net) 246 requestMessage := TestMessage{Message: "this is a request"} 247 requestBytes, err := message.RequestToBytes(codecManager, requestMessage) 248 assert.NoError(t, err) 249 assert.NoError(t, 250 net.Connected( 251 nodeID, 252 &version.Application{ 253 Major: 1, 254 Minor: 7, 255 Patch: 1, 256 }, 257 ), 258 ) 259 260 // ensure version does not match 261 responseBytes, _, err := client.RequestAny( 262 &version.Application{ 263 Major: 2, 264 Minor: 0, 265 Patch: 0, 266 }, 267 requestBytes, 268 ) 269 assert.Equal(t, err.Error(), "no peers found matching version avalanche/2.0.0 out of 1 peers") 270 assert.Nil(t, responseBytes) 271 272 // ensure version matches and the request goes through 273 responseBytes, _, err = client.RequestAny(defaultPeerVersion, requestBytes) 274 assert.NoError(t, err) 275 276 var response TestMessage 277 if _, err = codecManager.Unmarshal(responseBytes, &response); err != nil { 278 t.Fatal("unexpected error during unmarshal", err) 279 } 280 assert.Equal(t, "this is a response", response.Message) 281 } 282 283 func TestOnRequestHonoursDeadline(t *testing.T) { 284 var net Network 285 responded := false 286 sender := testAppSender{ 287 sendAppRequestFn: func(nodes ids.NodeIDSet, reqID uint32, message []byte) error { 288 return nil 289 }, 290 sendAppResponseFn: func(nodeID ids.NodeID, reqID uint32, message []byte) error { 291 responded = true 292 return nil 293 }, 294 } 295 296 codecManager := buildCodec(t, TestMessage{}) 297 298 requestBytes, err := marshalStruct(codecManager, TestMessage{Message: "hello there"}) 299 assert.NoError(t, err) 300 301 requestHandler := &testRequestHandler{ 302 processingDuration: 500 * time.Millisecond, 303 } 304 net = NewNetwork(sender, codecManager, ids.EmptyNodeID, 1) 305 net.SetRequestHandler(requestHandler) 306 nodeID := ids.GenerateTestNodeID() 307 308 requestHandler.response, err = marshalStruct(codecManager, TestMessage{Message: "hi there"}) 309 assert.NoError(t, err) 310 err = net.AppRequest(nodeID, 1, time.Now().Add(1*time.Millisecond), requestBytes) 311 assert.NoError(t, err) 312 // ensure the handler didn't get called (as peer.Network would've dropped the request) 313 assert.EqualValues(t, requestHandler.calls, 0) 314 315 requestHandler.processingDuration = 0 316 err = net.AppRequest(nodeID, 2, time.Now().Add(250*time.Millisecond), requestBytes) 317 assert.NoError(t, err) 318 assert.True(t, responded) 319 assert.EqualValues(t, requestHandler.calls, 1) 320 } 321 322 func TestGossip(t *testing.T) { 323 codecManager := buildCodec(t, HelloGossip{}) 324 325 nodeID := ids.GenerateTestNodeID() 326 var clientNetwork Network 327 wg := &sync.WaitGroup{} 328 sentGossip := false 329 wg.Add(1) 330 sender := testAppSender{ 331 sendAppGossipFn: func(msg []byte) error { 332 go func() { 333 defer wg.Done() 334 err := clientNetwork.AppGossip(nodeID, msg) 335 assert.NoError(t, err) 336 }() 337 sentGossip = true 338 return nil 339 }, 340 } 341 342 gossipHandler := &testGossipHandler{} 343 clientNetwork = NewNetwork(sender, codecManager, ids.EmptyNodeID, 1) 344 clientNetwork.SetGossipHandler(gossipHandler) 345 346 assert.NoError(t, clientNetwork.Connected(nodeID, defaultPeerVersion)) 347 348 client := NewNetworkClient(clientNetwork) 349 defer clientNetwork.Shutdown() 350 351 b, err := buildGossip(codecManager, HelloGossip{Msg: "hello there!"}) 352 assert.NoError(t, err) 353 354 err = client.Gossip(b) 355 assert.NoError(t, err) 356 357 wg.Wait() 358 assert.True(t, sentGossip) 359 assert.True(t, gossipHandler.received) 360 } 361 362 func TestHandleInvalidMessages(t *testing.T) { 363 codecManager := buildCodec(t, HelloGossip{}, TestMessage{}) 364 365 nodeID := ids.GenerateTestNodeID() 366 requestID := uint32(1) 367 sender := testAppSender{} 368 369 clientNetwork := NewNetwork(sender, codecManager, ids.EmptyNodeID, 1) 370 clientNetwork.SetGossipHandler(message.NoopMempoolGossipHandler{}) 371 clientNetwork.SetRequestHandler(&testRequestHandler{}) 372 373 assert.NoError(t, clientNetwork.Connected(nodeID, defaultPeerVersion)) 374 375 defer clientNetwork.Shutdown() 376 377 // Ensure a valid gossip message sent as any App specific message type does not trigger a fatal error 378 gossipMsg, err := buildGossip(codecManager, HelloGossip{Msg: "hello there!"}) 379 assert.NoError(t, err) 380 381 // Ensure a valid request message sent as any App specific message type does not trigger a fatal error 382 requestMessage, err := marshalStruct(codecManager, TestMessage{Message: "Hello"}) 383 assert.NoError(t, err) 384 385 // Ensure a random message sent as any App specific message type does not trigger a fatal error 386 garbageResponse := make([]byte, 10) 387 // Ensure a zero-length message sent as any App specific message type does not trigger a fatal error 388 emptyResponse := make([]byte, 0) 389 // Ensure a nil byte slice sent as any App specific message type does not trigger a fatal error 390 var nilResponse []byte 391 392 // Check for edge cases 393 assert.NoError(t, clientNetwork.AppGossip(nodeID, gossipMsg)) 394 assert.NoError(t, clientNetwork.AppGossip(nodeID, requestMessage)) 395 assert.NoError(t, clientNetwork.AppGossip(nodeID, garbageResponse)) 396 assert.NoError(t, clientNetwork.AppGossip(nodeID, emptyResponse)) 397 assert.NoError(t, clientNetwork.AppGossip(nodeID, nilResponse)) 398 assert.NoError(t, clientNetwork.AppRequest(nodeID, requestID, time.Now().Add(time.Second), gossipMsg)) 399 assert.NoError(t, clientNetwork.AppRequest(nodeID, requestID, time.Now().Add(time.Second), requestMessage)) 400 assert.NoError(t, clientNetwork.AppRequest(nodeID, requestID, time.Now().Add(time.Second), garbageResponse)) 401 assert.NoError(t, clientNetwork.AppRequest(nodeID, requestID, time.Now().Add(time.Second), emptyResponse)) 402 assert.NoError(t, clientNetwork.AppRequest(nodeID, requestID, time.Now().Add(time.Second), nilResponse)) 403 assert.NoError(t, clientNetwork.AppResponse(nodeID, requestID, gossipMsg)) 404 assert.NoError(t, clientNetwork.AppResponse(nodeID, requestID, requestMessage)) 405 assert.NoError(t, clientNetwork.AppResponse(nodeID, requestID, garbageResponse)) 406 assert.NoError(t, clientNetwork.AppResponse(nodeID, requestID, emptyResponse)) 407 assert.NoError(t, clientNetwork.AppResponse(nodeID, requestID, nilResponse)) 408 assert.NoError(t, clientNetwork.AppRequestFailed(nodeID, requestID)) 409 } 410 411 func TestNetworkPropagatesRequestHandlerError(t *testing.T) { 412 codecManager := buildCodec(t, TestMessage{}) 413 414 nodeID := ids.GenerateTestNodeID() 415 requestID := uint32(1) 416 sender := testAppSender{} 417 418 clientNetwork := NewNetwork(sender, codecManager, ids.EmptyNodeID, 1) 419 clientNetwork.SetGossipHandler(message.NoopMempoolGossipHandler{}) 420 clientNetwork.SetRequestHandler(&testRequestHandler{err: errors.New("fail")}) // Return an error from the request handler 421 422 assert.NoError(t, clientNetwork.Connected(nodeID, defaultPeerVersion)) 423 424 defer clientNetwork.Shutdown() 425 426 // Ensure a valid request message sent as any App specific message type does not trigger a fatal error 427 requestMessage, err := marshalStruct(codecManager, TestMessage{Message: "Hello"}) 428 assert.NoError(t, err) 429 430 // Check that if the request handler returns an error, it is propagated as a fatal error. 431 assert.Error(t, clientNetwork.AppRequest(nodeID, requestID, time.Now().Add(time.Second), requestMessage)) 432 } 433 434 func buildCodec(t *testing.T, types ...interface{}) codec.Manager { 435 codecManager := codec.NewDefaultManager() 436 c := linearcodec.NewDefault() 437 for _, typ := range types { 438 assert.NoError(t, c.RegisterType(typ)) 439 } 440 assert.NoError(t, codecManager.RegisterCodec(message.Version, c)) 441 return codecManager 442 } 443 444 // marshalStruct is a helper method used to marshal an object as `interface{}` 445 // so that the codec is able to include the TypeID in the resulting bytes 446 func marshalStruct(codec codec.Manager, obj interface{}) ([]byte, error) { 447 return codec.Marshal(message.Version, &obj) 448 } 449 450 func buildGossip(codec codec.Manager, msg message.GossipMessage) ([]byte, error) { 451 return codec.Marshal(message.Version, &msg) 452 } 453 454 type testAppSender struct { 455 sendAppRequestFn func(ids.NodeIDSet, uint32, []byte) error 456 sendAppResponseFn func(ids.NodeID, uint32, []byte) error 457 sendAppGossipFn func([]byte) error 458 } 459 460 func (t testAppSender) SendAppGossipSpecific(ids.NodeIDSet, []byte) error { 461 panic("not implemented") 462 } 463 464 func (t testAppSender) SendAppRequest(nodeIDs ids.NodeIDSet, requestID uint32, message []byte) error { 465 return t.sendAppRequestFn(nodeIDs, requestID, message) 466 } 467 468 func (t testAppSender) SendAppResponse(nodeID ids.NodeID, requestID uint32, message []byte) error { 469 return t.sendAppResponseFn(nodeID, requestID, message) 470 } 471 472 func (t testAppSender) SendAppGossip(message []byte) error { 473 return t.sendAppGossipFn(message) 474 } 475 476 type HelloRequest struct { 477 Message string `serialize:"true"` 478 } 479 480 func (h HelloRequest) Handle(ctx context.Context, nodeID ids.NodeID, requestID uint32, handler message.RequestHandler) ([]byte, error) { 481 // casting is only necessary for test since RequestHandler does not implement anything at the moment 482 return handler.(TestRequestHandler).HandleHelloRequest(ctx, nodeID, requestID, &h) 483 } 484 485 func (h HelloRequest) String() string { 486 return fmt.Sprintf("HelloRequest(%s)", h.Message) 487 } 488 489 type GreetingRequest struct { 490 Greeting string `serialize:"true"` 491 } 492 493 func (g GreetingRequest) Handle(ctx context.Context, nodeID ids.NodeID, requestID uint32, handler message.RequestHandler) ([]byte, error) { 494 // casting is only necessary for test since RequestHandler does not implement anything at the moment 495 return handler.(TestRequestHandler).HandleGreetingRequest(ctx, nodeID, requestID, &g) 496 } 497 498 func (g GreetingRequest) String() string { 499 return fmt.Sprintf("GreetingRequest(%s)", g.Greeting) 500 } 501 502 type HelloResponse struct { 503 Response string `serialize:"true"` 504 } 505 506 type GreetingResponse struct { 507 Greet string `serialize:"true"` 508 } 509 510 type TestRequestHandler interface { 511 HandleHelloRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, request *HelloRequest) ([]byte, error) 512 HandleGreetingRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, request *GreetingRequest) ([]byte, error) 513 } 514 515 type HelloGreetingRequestHandler struct { 516 message.RequestHandler 517 codec codec.Manager 518 } 519 520 func (h *HelloGreetingRequestHandler) HandleHelloRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, request *HelloRequest) ([]byte, error) { 521 return h.codec.Marshal(message.Version, HelloResponse{Response: "Hi"}) 522 } 523 524 func (h *HelloGreetingRequestHandler) HandleGreetingRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, request *GreetingRequest) ([]byte, error) { 525 return h.codec.Marshal(message.Version, GreetingResponse{Greet: "Hey there"}) 526 } 527 528 type TestMessage struct { 529 Message string `serialize:"true"` 530 } 531 532 func (t TestMessage) Handle(ctx context.Context, nodeID ids.NodeID, requestID uint32, handler message.RequestHandler) ([]byte, error) { 533 return handler.(*testRequestHandler).handleTestRequest(ctx, nodeID, requestID, &t) 534 } 535 536 func (t TestMessage) String() string { 537 return fmt.Sprintf("TestMessage(%s)", t.Message) 538 } 539 540 type HelloGossip struct { 541 Msg string `serialize:"true"` 542 } 543 544 func (h HelloGossip) Handle(handler message.GossipHandler, nodeID ids.NodeID) error { 545 return handler.HandleEthTxs(nodeID, message.EthTxsGossip{}) 546 } 547 548 func (h HelloGossip) String() string { 549 return fmt.Sprintf("HelloGossip(%s)", h.Msg) 550 } 551 552 func (h HelloGossip) initialize(_ []byte) { 553 // no op 554 } 555 556 func (h HelloGossip) Bytes() []byte { 557 // no op 558 return nil 559 } 560 561 type testGossipHandler struct { 562 received bool 563 nodeID ids.NodeID 564 msg []byte 565 } 566 567 func (t *testGossipHandler) HandleAtomicTx(nodeID ids.NodeID, msg message.AtomicTxGossip) error { 568 t.received = true 569 t.nodeID = nodeID 570 return nil 571 } 572 573 func (t *testGossipHandler) HandleEthTxs(nodeID ids.NodeID, msg message.EthTxsGossip) error { 574 t.received = true 575 t.nodeID = nodeID 576 return nil 577 } 578 579 type testRequestHandler struct { 580 message.RequestHandler 581 calls uint32 582 processingDuration time.Duration 583 response []byte 584 err error 585 } 586 587 func (r *testRequestHandler) handleTestRequest(ctx context.Context, _ ids.NodeID, _ uint32, _ *TestMessage) ([]byte, error) { 588 r.calls++ 589 select { 590 case <-time.After(r.processingDuration): 591 break 592 case <-ctx.Done(): 593 return nil, ctx.Err() 594 } 595 return r.response, r.err 596 }