github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/cmd/devp2p/internal/ethtest/helpers.go (about) 1 // Copyright 2020 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 ethtest 18 19 import ( 20 "fmt" 21 "net" 22 "reflect" 23 "strings" 24 "time" 25 26 "github.com/davecgh/go-spew/spew" 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/ethereum/go-ethereum/eth/protocols/eth" 31 "github.com/ethereum/go-ethereum/internal/utesting" 32 "github.com/ethereum/go-ethereum/p2p" 33 "github.com/ethereum/go-ethereum/p2p/rlpx" 34 ) 35 36 var ( 37 pretty = spew.ConfigState{ 38 Indent: " ", 39 DisableCapacities: true, 40 DisablePointerAddresses: true, 41 SortKeys: true, 42 } 43 timeout = 20 * time.Second 44 ) 45 46 // Is_66 checks if the node supports the eth66 protocol version, 47 // and if not, exists the test suite 48 func (s *Suite) Is_66(t *utesting.T) { 49 conn, err := s.dial66() 50 if err != nil { 51 t.Fatalf("dial failed: %v", err) 52 } 53 if err := conn.handshake(); err != nil { 54 t.Fatalf("handshake failed: %v", err) 55 } 56 if conn.negotiatedProtoVersion < 66 { 57 t.Fail() 58 } 59 } 60 61 // dial attempts to dial the given node and perform a handshake, 62 // returning the created Conn if successful. 63 func (s *Suite) dial() (*Conn, error) { 64 // dial 65 fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP())) 66 if err != nil { 67 return nil, err 68 } 69 conn := Conn{Conn: rlpx.NewConn(fd, s.Dest.Pubkey())} 70 // do encHandshake 71 conn.ourKey, _ = crypto.GenerateKey() 72 _, err = conn.Handshake(conn.ourKey) 73 if err != nil { 74 conn.Close() 75 return nil, err 76 } 77 // set default p2p capabilities 78 conn.caps = []p2p.Cap{ 79 {Name: "eth", Version: 64}, 80 {Name: "eth", Version: 65}, 81 } 82 conn.ourHighestProtoVersion = 65 83 return &conn, nil 84 } 85 86 // dial66 attempts to dial the given node and perform a handshake, 87 // returning the created Conn with additional eth66 capabilities if 88 // successful 89 func (s *Suite) dial66() (*Conn, error) { 90 conn, err := s.dial() 91 if err != nil { 92 return nil, fmt.Errorf("dial failed: %v", err) 93 } 94 conn.caps = append(conn.caps, p2p.Cap{Name: "eth", Version: 66}) 95 conn.ourHighestProtoVersion = 66 96 return conn, nil 97 } 98 99 // dial66 attempts to dial the given node and perform a handshake, 100 // returning the created Conn with additional snap/1 capabilities if 101 // successful. 102 func (s *Suite) dialSnap() (*Conn, error) { 103 conn, err := s.dial66() 104 if err != nil { 105 return nil, fmt.Errorf("dial failed: %v", err) 106 } 107 conn.caps = append(conn.caps, p2p.Cap{Name: "snap", Version: 1}) 108 conn.ourHighestSnapProtoVersion = 1 109 return conn, nil 110 } 111 112 // peer performs both the protocol handshake and the status message 113 // exchange with the node in order to peer with it. 114 func (c *Conn) peer(chain *Chain, status *Status) error { 115 if err := c.handshake(); err != nil { 116 return fmt.Errorf("handshake failed: %v", err) 117 } 118 if _, err := c.statusExchange(chain, status); err != nil { 119 return fmt.Errorf("status exchange failed: %v", err) 120 } 121 return nil 122 } 123 124 // handshake performs a protocol handshake with the node. 125 func (c *Conn) handshake() error { 126 defer c.SetDeadline(time.Time{}) 127 c.SetDeadline(time.Now().Add(10 * time.Second)) 128 // write hello to client 129 pub0 := crypto.FromECDSAPub(&c.ourKey.PublicKey)[1:] 130 ourHandshake := &Hello{ 131 Version: 5, 132 Caps: c.caps, 133 ID: pub0, 134 } 135 if err := c.Write(ourHandshake); err != nil { 136 return fmt.Errorf("write to connection failed: %v", err) 137 } 138 // read hello from client 139 switch msg := c.Read().(type) { 140 case *Hello: 141 // set snappy if version is at least 5 142 if msg.Version >= 5 { 143 c.SetSnappy(true) 144 } 145 c.negotiateEthProtocol(msg.Caps) 146 if c.negotiatedProtoVersion == 0 { 147 return fmt.Errorf("could not negotiate eth protocol (remote caps: %v, local eth version: %v)", msg.Caps, c.ourHighestProtoVersion) 148 } 149 // If we require snap, verify that it was negotiated 150 if c.ourHighestSnapProtoVersion != c.negotiatedSnapProtoVersion { 151 return fmt.Errorf("could not negotiate snap protocol (remote caps: %v, local snap version: %v)", msg.Caps, c.ourHighestSnapProtoVersion) 152 } 153 return nil 154 default: 155 return fmt.Errorf("bad handshake: %#v", msg) 156 } 157 } 158 159 // negotiateEthProtocol sets the Conn's eth protocol version to highest 160 // advertised capability from peer. 161 func (c *Conn) negotiateEthProtocol(caps []p2p.Cap) { 162 var highestEthVersion uint 163 var highestSnapVersion uint 164 for _, capability := range caps { 165 switch capability.Name { 166 case "eth": 167 if capability.Version > highestEthVersion && capability.Version <= c.ourHighestProtoVersion { 168 highestEthVersion = capability.Version 169 } 170 case "snap": 171 if capability.Version > highestSnapVersion && capability.Version <= c.ourHighestSnapProtoVersion { 172 highestSnapVersion = capability.Version 173 } 174 } 175 } 176 c.negotiatedProtoVersion = highestEthVersion 177 c.negotiatedSnapProtoVersion = highestSnapVersion 178 } 179 180 // statusExchange performs a `Status` message exchange with the given node. 181 func (c *Conn) statusExchange(chain *Chain, status *Status) (Message, error) { 182 defer c.SetDeadline(time.Time{}) 183 c.SetDeadline(time.Now().Add(20 * time.Second)) 184 185 // read status message from client 186 var message Message 187 loop: 188 for { 189 switch msg := c.Read().(type) { 190 case *Status: 191 if have, want := msg.Head, chain.blocks[chain.Len()-1].Hash(); have != want { 192 return nil, fmt.Errorf("wrong head block in status, want: %#x (block %d) have %#x", 193 want, chain.blocks[chain.Len()-1].NumberU64(), have) 194 } 195 if have, want := msg.TD.Cmp(chain.TD()), 0; have != want { 196 return nil, fmt.Errorf("wrong TD in status: have %v want %v", have, want) 197 } 198 if have, want := msg.ForkID, chain.ForkID(); !reflect.DeepEqual(have, want) { 199 return nil, fmt.Errorf("wrong fork ID in status: have %v, want %v", have, want) 200 } 201 if have, want := msg.ProtocolVersion, c.ourHighestProtoVersion; have != uint32(want) { 202 return nil, fmt.Errorf("wrong protocol version: have %v, want %v", have, want) 203 } 204 message = msg 205 break loop 206 case *Disconnect: 207 return nil, fmt.Errorf("disconnect received: %v", msg.Reason) 208 case *Ping: 209 c.Write(&Pong{}) // TODO (renaynay): in the future, this should be an error 210 // (PINGs should not be a response upon fresh connection) 211 default: 212 return nil, fmt.Errorf("bad status message: %s", pretty.Sdump(msg)) 213 } 214 } 215 // make sure eth protocol version is set for negotiation 216 if c.negotiatedProtoVersion == 0 { 217 return nil, fmt.Errorf("eth protocol version must be set in Conn") 218 } 219 if status == nil { 220 // default status message 221 status = &Status{ 222 ProtocolVersion: uint32(c.negotiatedProtoVersion), 223 NetworkID: chain.chainConfig.ChainID.Uint64(), 224 TD: chain.TD(), 225 Head: chain.blocks[chain.Len()-1].Hash(), 226 Genesis: chain.blocks[0].Hash(), 227 ForkID: chain.ForkID(), 228 } 229 } 230 if err := c.Write(status); err != nil { 231 return nil, fmt.Errorf("write to connection failed: %v", err) 232 } 233 return message, nil 234 } 235 236 // createSendAndRecvConns creates two connections, one for sending messages to the 237 // node, and one for receiving messages from the node. 238 func (s *Suite) createSendAndRecvConns(isEth66 bool) (*Conn, *Conn, error) { 239 var ( 240 sendConn *Conn 241 recvConn *Conn 242 err error 243 ) 244 if isEth66 { 245 sendConn, err = s.dial66() 246 if err != nil { 247 return nil, nil, fmt.Errorf("dial failed: %v", err) 248 } 249 recvConn, err = s.dial66() 250 if err != nil { 251 sendConn.Close() 252 return nil, nil, fmt.Errorf("dial failed: %v", err) 253 } 254 } else { 255 sendConn, err = s.dial() 256 if err != nil { 257 return nil, nil, fmt.Errorf("dial failed: %v", err) 258 } 259 recvConn, err = s.dial() 260 if err != nil { 261 sendConn.Close() 262 return nil, nil, fmt.Errorf("dial failed: %v", err) 263 } 264 } 265 return sendConn, recvConn, nil 266 } 267 268 func (c *Conn) readAndServe(chain *Chain, timeout time.Duration) Message { 269 if c.negotiatedProtoVersion == 66 { 270 _, msg := c.readAndServe66(chain, timeout) 271 return msg 272 } 273 return c.readAndServe65(chain, timeout) 274 } 275 276 // readAndServe serves GetBlockHeaders requests while waiting 277 // on another message from the node. 278 func (c *Conn) readAndServe65(chain *Chain, timeout time.Duration) Message { 279 start := time.Now() 280 for time.Since(start) < timeout { 281 c.SetReadDeadline(time.Now().Add(5 * time.Second)) 282 switch msg := c.Read().(type) { 283 case *Ping: 284 c.Write(&Pong{}) 285 case *GetBlockHeaders: 286 req := *msg 287 headers, err := chain.GetHeaders(req) 288 if err != nil { 289 return errorf("could not get headers for inbound header request: %v", err) 290 } 291 if err := c.Write(headers); err != nil { 292 return errorf("could not write to connection: %v", err) 293 } 294 default: 295 return msg 296 } 297 } 298 return errorf("no message received within %v", timeout) 299 } 300 301 // readAndServe66 serves eth66 GetBlockHeaders requests while waiting 302 // on another message from the node. 303 func (c *Conn) readAndServe66(chain *Chain, timeout time.Duration) (uint64, Message) { 304 start := time.Now() 305 for time.Since(start) < timeout { 306 c.SetReadDeadline(time.Now().Add(10 * time.Second)) 307 308 reqID, msg := c.Read66() 309 310 switch msg := msg.(type) { 311 case *Ping: 312 c.Write(&Pong{}) 313 case GetBlockHeaders: 314 headers, err := chain.GetHeaders(msg) 315 if err != nil { 316 return 0, errorf("could not get headers for inbound header request: %v", err) 317 } 318 resp := ð.BlockHeadersPacket66{ 319 RequestId: reqID, 320 BlockHeadersPacket: eth.BlockHeadersPacket(headers), 321 } 322 if err := c.Write66(resp, BlockHeaders{}.Code()); err != nil { 323 return 0, errorf("could not write to connection: %v", err) 324 } 325 default: 326 return reqID, msg 327 } 328 } 329 return 0, errorf("no message received within %v", timeout) 330 } 331 332 // headersRequest executes the given `GetBlockHeaders` request. 333 func (c *Conn) headersRequest(request *GetBlockHeaders, chain *Chain, isEth66 bool, reqID uint64) (BlockHeaders, error) { 334 defer c.SetReadDeadline(time.Time{}) 335 c.SetReadDeadline(time.Now().Add(20 * time.Second)) 336 // if on eth66 connection, perform eth66 GetBlockHeaders request 337 if isEth66 { 338 return getBlockHeaders66(chain, c, request, reqID) 339 } 340 if err := c.Write(request); err != nil { 341 return nil, err 342 } 343 switch msg := c.readAndServe(chain, timeout).(type) { 344 case *BlockHeaders: 345 return *msg, nil 346 default: 347 return nil, fmt.Errorf("invalid message: %s", pretty.Sdump(msg)) 348 } 349 } 350 351 func (c *Conn) snapRequest(msg Message, id uint64, chain *Chain) (Message, error) { 352 defer c.SetReadDeadline(time.Time{}) 353 c.SetReadDeadline(time.Now().Add(5 * time.Second)) 354 if err := c.Write(msg); err != nil { 355 return nil, fmt.Errorf("could not write to connection: %v", err) 356 } 357 return c.ReadSnap(id) 358 } 359 360 // getBlockHeaders66 executes the given `GetBlockHeaders` request over the eth66 protocol. 361 func getBlockHeaders66(chain *Chain, conn *Conn, request *GetBlockHeaders, id uint64) (BlockHeaders, error) { 362 // write request 363 packet := eth.GetBlockHeadersPacket(*request) 364 req := ð.GetBlockHeadersPacket66{ 365 RequestId: id, 366 GetBlockHeadersPacket: &packet, 367 } 368 if err := conn.Write66(req, GetBlockHeaders{}.Code()); err != nil { 369 return nil, fmt.Errorf("could not write to connection: %v", err) 370 } 371 // wait for response 372 msg := conn.waitForResponse(chain, timeout, req.RequestId) 373 headers, ok := msg.(BlockHeaders) 374 if !ok { 375 return nil, fmt.Errorf("unexpected message received: %s", pretty.Sdump(msg)) 376 } 377 return headers, nil 378 } 379 380 // headersMatch returns whether the received headers match the given request 381 func headersMatch(expected BlockHeaders, headers BlockHeaders) bool { 382 return reflect.DeepEqual(expected, headers) 383 } 384 385 // waitForResponse reads from the connection until a response with the expected 386 // request ID is received. 387 func (c *Conn) waitForResponse(chain *Chain, timeout time.Duration, requestID uint64) Message { 388 for { 389 id, msg := c.readAndServe66(chain, timeout) 390 if id == requestID { 391 return msg 392 } 393 } 394 } 395 396 // sendNextBlock broadcasts the next block in the chain and waits 397 // for the node to propagate the block and import it into its chain. 398 func (s *Suite) sendNextBlock(isEth66 bool) error { 399 // set up sending and receiving connections 400 sendConn, recvConn, err := s.createSendAndRecvConns(isEth66) 401 if err != nil { 402 return err 403 } 404 defer sendConn.Close() 405 defer recvConn.Close() 406 if err = sendConn.peer(s.chain, nil); err != nil { 407 return fmt.Errorf("peering failed: %v", err) 408 } 409 if err = recvConn.peer(s.chain, nil); err != nil { 410 return fmt.Errorf("peering failed: %v", err) 411 } 412 // create new block announcement 413 nextBlock := s.fullChain.blocks[s.chain.Len()] 414 blockAnnouncement := &NewBlock{ 415 Block: nextBlock, 416 TD: s.fullChain.TotalDifficultyAt(s.chain.Len()), 417 } 418 // send announcement and wait for node to request the header 419 if err = s.testAnnounce(sendConn, recvConn, blockAnnouncement); err != nil { 420 return fmt.Errorf("failed to announce block: %v", err) 421 } 422 // wait for client to update its chain 423 if err = s.waitForBlockImport(recvConn, nextBlock, isEth66); err != nil { 424 return fmt.Errorf("failed to receive confirmation of block import: %v", err) 425 } 426 // update test suite chain 427 s.chain.blocks = append(s.chain.blocks, nextBlock) 428 return nil 429 } 430 431 // testAnnounce writes a block announcement to the node and waits for the node 432 // to propagate it. 433 func (s *Suite) testAnnounce(sendConn, receiveConn *Conn, blockAnnouncement *NewBlock) error { 434 if err := sendConn.Write(blockAnnouncement); err != nil { 435 return fmt.Errorf("could not write to connection: %v", err) 436 } 437 return s.waitAnnounce(receiveConn, blockAnnouncement) 438 } 439 440 // waitAnnounce waits for a NewBlock or NewBlockHashes announcement from the node. 441 func (s *Suite) waitAnnounce(conn *Conn, blockAnnouncement *NewBlock) error { 442 for { 443 switch msg := conn.readAndServe(s.chain, timeout).(type) { 444 case *NewBlock: 445 if !reflect.DeepEqual(blockAnnouncement.Block.Header(), msg.Block.Header()) { 446 return fmt.Errorf("wrong header in block announcement: \nexpected %v "+ 447 "\ngot %v", blockAnnouncement.Block.Header(), msg.Block.Header()) 448 } 449 if !reflect.DeepEqual(blockAnnouncement.TD, msg.TD) { 450 return fmt.Errorf("wrong TD in announcement: expected %v, got %v", blockAnnouncement.TD, msg.TD) 451 } 452 return nil 453 case *NewBlockHashes: 454 hashes := *msg 455 if blockAnnouncement.Block.Hash() != hashes[0].Hash { 456 return fmt.Errorf("wrong block hash in announcement: expected %v, got %v", blockAnnouncement.Block.Hash(), hashes[0].Hash) 457 } 458 return nil 459 case *NewPooledTransactionHashes: 460 // ignore tx announcements from previous tests 461 continue 462 default: 463 return fmt.Errorf("unexpected: %s", pretty.Sdump(msg)) 464 } 465 } 466 } 467 468 func (s *Suite) waitForBlockImport(conn *Conn, block *types.Block, isEth66 bool) error { 469 defer conn.SetReadDeadline(time.Time{}) 470 conn.SetReadDeadline(time.Now().Add(20 * time.Second)) 471 // create request 472 req := &GetBlockHeaders{ 473 Origin: eth.HashOrNumber{ 474 Hash: block.Hash(), 475 }, 476 Amount: 1, 477 } 478 // loop until BlockHeaders response contains desired block, confirming the 479 // node imported the block 480 for { 481 var ( 482 headers BlockHeaders 483 err error 484 ) 485 if isEth66 { 486 requestID := uint64(54) 487 headers, err = conn.headersRequest(req, s.chain, eth66, requestID) 488 } else { 489 headers, err = conn.headersRequest(req, s.chain, eth65, 0) 490 } 491 if err != nil { 492 return fmt.Errorf("GetBlockHeader request failed: %v", err) 493 } 494 // if headers response is empty, node hasn't imported block yet, try again 495 if len(headers) == 0 { 496 time.Sleep(100 * time.Millisecond) 497 continue 498 } 499 if !reflect.DeepEqual(block.Header(), headers[0]) { 500 return fmt.Errorf("wrong header returned: wanted %v, got %v", block.Header(), headers[0]) 501 } 502 return nil 503 } 504 } 505 506 func (s *Suite) oldAnnounce(isEth66 bool) error { 507 sendConn, receiveConn, err := s.createSendAndRecvConns(isEth66) 508 if err != nil { 509 return err 510 } 511 defer sendConn.Close() 512 defer receiveConn.Close() 513 if err := sendConn.peer(s.chain, nil); err != nil { 514 return fmt.Errorf("peering failed: %v", err) 515 } 516 if err := receiveConn.peer(s.chain, nil); err != nil { 517 return fmt.Errorf("peering failed: %v", err) 518 } 519 // create old block announcement 520 oldBlockAnnounce := &NewBlock{ 521 Block: s.chain.blocks[len(s.chain.blocks)/2], 522 TD: s.chain.blocks[len(s.chain.blocks)/2].Difficulty(), 523 } 524 if err := sendConn.Write(oldBlockAnnounce); err != nil { 525 return fmt.Errorf("could not write to connection: %v", err) 526 } 527 // wait to see if the announcement is propagated 528 switch msg := receiveConn.readAndServe(s.chain, time.Second*8).(type) { 529 case *NewBlock: 530 block := *msg 531 if block.Block.Hash() == oldBlockAnnounce.Block.Hash() { 532 return fmt.Errorf("unexpected: block propagated: %s", pretty.Sdump(msg)) 533 } 534 case *NewBlockHashes: 535 hashes := *msg 536 for _, hash := range hashes { 537 if hash.Hash == oldBlockAnnounce.Block.Hash() { 538 return fmt.Errorf("unexpected: block announced: %s", pretty.Sdump(msg)) 539 } 540 } 541 case *Error: 542 errMsg := *msg 543 // check to make sure error is timeout (propagation didn't come through == test successful) 544 if !strings.Contains(errMsg.String(), "timeout") { 545 return fmt.Errorf("unexpected error: %v", pretty.Sdump(msg)) 546 } 547 default: 548 return fmt.Errorf("unexpected: %s", pretty.Sdump(msg)) 549 } 550 return nil 551 } 552 553 func (s *Suite) maliciousHandshakes(t *utesting.T, isEth66 bool) error { 554 var ( 555 conn *Conn 556 err error 557 ) 558 if isEth66 { 559 conn, err = s.dial66() 560 if err != nil { 561 return fmt.Errorf("dial failed: %v", err) 562 } 563 } else { 564 conn, err = s.dial() 565 if err != nil { 566 return fmt.Errorf("dial failed: %v", err) 567 } 568 } 569 defer conn.Close() 570 // write hello to client 571 pub0 := crypto.FromECDSAPub(&conn.ourKey.PublicKey)[1:] 572 handshakes := []*Hello{ 573 { 574 Version: 5, 575 Caps: []p2p.Cap{ 576 {Name: largeString(2), Version: 64}, 577 }, 578 ID: pub0, 579 }, 580 { 581 Version: 5, 582 Caps: []p2p.Cap{ 583 {Name: "eth", Version: 64}, 584 {Name: "eth", Version: 65}, 585 }, 586 ID: append(pub0, byte(0)), 587 }, 588 { 589 Version: 5, 590 Caps: []p2p.Cap{ 591 {Name: "eth", Version: 64}, 592 {Name: "eth", Version: 65}, 593 }, 594 ID: append(pub0, pub0...), 595 }, 596 { 597 Version: 5, 598 Caps: []p2p.Cap{ 599 {Name: "eth", Version: 64}, 600 {Name: "eth", Version: 65}, 601 }, 602 ID: largeBuffer(2), 603 }, 604 { 605 Version: 5, 606 Caps: []p2p.Cap{ 607 {Name: largeString(2), Version: 64}, 608 }, 609 ID: largeBuffer(2), 610 }, 611 } 612 for i, handshake := range handshakes { 613 t.Logf("Testing malicious handshake %v\n", i) 614 if err := conn.Write(handshake); err != nil { 615 return fmt.Errorf("could not write to connection: %v", err) 616 } 617 // check that the peer disconnected 618 for i := 0; i < 2; i++ { 619 switch msg := conn.readAndServe(s.chain, 20*time.Second).(type) { 620 case *Disconnect: 621 case *Error: 622 case *Hello: 623 // Discard one hello as Hello's are sent concurrently 624 continue 625 default: 626 return fmt.Errorf("unexpected: %s", pretty.Sdump(msg)) 627 } 628 } 629 // dial for the next round 630 if isEth66 { 631 conn, err = s.dial66() 632 if err != nil { 633 return fmt.Errorf("dial failed: %v", err) 634 } 635 } else { 636 conn, err = s.dial() 637 if err != nil { 638 return fmt.Errorf("dial failed: %v", err) 639 } 640 } 641 } 642 return nil 643 } 644 645 func (s *Suite) maliciousStatus(conn *Conn) error { 646 if err := conn.handshake(); err != nil { 647 return fmt.Errorf("handshake failed: %v", err) 648 } 649 status := &Status{ 650 ProtocolVersion: uint32(conn.negotiatedProtoVersion), 651 NetworkID: s.chain.chainConfig.ChainID.Uint64(), 652 TD: largeNumber(2), 653 Head: s.chain.blocks[s.chain.Len()-1].Hash(), 654 Genesis: s.chain.blocks[0].Hash(), 655 ForkID: s.chain.ForkID(), 656 } 657 // get status 658 msg, err := conn.statusExchange(s.chain, status) 659 if err != nil { 660 return fmt.Errorf("status exchange failed: %v", err) 661 } 662 switch msg := msg.(type) { 663 case *Status: 664 default: 665 return fmt.Errorf("expected status, got: %#v ", msg) 666 } 667 // wait for disconnect 668 switch msg := conn.readAndServe(s.chain, timeout).(type) { 669 case *Disconnect: 670 return nil 671 case *Error: 672 return nil 673 default: 674 return fmt.Errorf("expected disconnect, got: %s", pretty.Sdump(msg)) 675 } 676 } 677 678 func (s *Suite) hashAnnounce(isEth66 bool) error { 679 // create connections 680 sendConn, recvConn, err := s.createSendAndRecvConns(isEth66) 681 if err != nil { 682 return fmt.Errorf("failed to create connections: %v", err) 683 } 684 defer sendConn.Close() 685 defer recvConn.Close() 686 if err := sendConn.peer(s.chain, nil); err != nil { 687 return fmt.Errorf("peering failed: %v", err) 688 } 689 if err := recvConn.peer(s.chain, nil); err != nil { 690 return fmt.Errorf("peering failed: %v", err) 691 } 692 // create NewBlockHashes announcement 693 type anno struct { 694 Hash common.Hash // Hash of one particular block being announced 695 Number uint64 // Number of one particular block being announced 696 } 697 nextBlock := s.fullChain.blocks[s.chain.Len()] 698 announcement := anno{Hash: nextBlock.Hash(), Number: nextBlock.Number().Uint64()} 699 newBlockHash := &NewBlockHashes{announcement} 700 if err := sendConn.Write(newBlockHash); err != nil { 701 return fmt.Errorf("failed to write to connection: %v", err) 702 } 703 // Announcement sent, now wait for a header request 704 var ( 705 id uint64 706 msg Message 707 blockHeaderReq GetBlockHeaders 708 ) 709 if isEth66 { 710 id, msg = sendConn.Read66() 711 switch msg := msg.(type) { 712 case GetBlockHeaders: 713 blockHeaderReq = msg 714 default: 715 return fmt.Errorf("unexpected %s", pretty.Sdump(msg)) 716 } 717 if blockHeaderReq.Amount != 1 { 718 return fmt.Errorf("unexpected number of block headers requested: %v", blockHeaderReq.Amount) 719 } 720 if blockHeaderReq.Origin.Hash != announcement.Hash { 721 return fmt.Errorf("unexpected block header requested. Announced:\n %v\n Remote request:\n%v", 722 pretty.Sdump(announcement), 723 pretty.Sdump(blockHeaderReq)) 724 } 725 if err := sendConn.Write66(ð.BlockHeadersPacket66{ 726 RequestId: id, 727 BlockHeadersPacket: eth.BlockHeadersPacket{ 728 nextBlock.Header(), 729 }, 730 }, BlockHeaders{}.Code()); err != nil { 731 return fmt.Errorf("failed to write to connection: %v", err) 732 } 733 } else { 734 msg = sendConn.Read() 735 switch msg := msg.(type) { 736 case *GetBlockHeaders: 737 blockHeaderReq = *msg 738 default: 739 return fmt.Errorf("unexpected %s", pretty.Sdump(msg)) 740 } 741 if blockHeaderReq.Amount != 1 { 742 return fmt.Errorf("unexpected number of block headers requested: %v", blockHeaderReq.Amount) 743 } 744 if blockHeaderReq.Origin.Hash != announcement.Hash { 745 return fmt.Errorf("unexpected block header requested. Announced:\n %v\n Remote request:\n%v", 746 pretty.Sdump(announcement), 747 pretty.Sdump(blockHeaderReq)) 748 } 749 if err := sendConn.Write(&BlockHeaders{nextBlock.Header()}); err != nil { 750 return fmt.Errorf("failed to write to connection: %v", err) 751 } 752 } 753 // wait for block announcement 754 msg = recvConn.readAndServe(s.chain, timeout) 755 switch msg := msg.(type) { 756 case *NewBlockHashes: 757 hashes := *msg 758 if len(hashes) != 1 { 759 return fmt.Errorf("unexpected new block hash announcement: wanted 1 announcement, got %d", len(hashes)) 760 } 761 if nextBlock.Hash() != hashes[0].Hash { 762 return fmt.Errorf("unexpected block hash announcement, wanted %v, got %v", nextBlock.Hash(), 763 hashes[0].Hash) 764 } 765 case *NewBlock: 766 // node should only propagate NewBlock without having requested the body if the body is empty 767 nextBlockBody := nextBlock.Body() 768 if len(nextBlockBody.Transactions) != 0 || len(nextBlockBody.Uncles) != 0 { 769 return fmt.Errorf("unexpected non-empty new block propagated: %s", pretty.Sdump(msg)) 770 } 771 if msg.Block.Hash() != nextBlock.Hash() { 772 return fmt.Errorf("mismatched hash of propagated new block: wanted %v, got %v", 773 nextBlock.Hash(), msg.Block.Hash()) 774 } 775 // check to make sure header matches header that was sent to the node 776 if !reflect.DeepEqual(nextBlock.Header(), msg.Block.Header()) { 777 return fmt.Errorf("incorrect header received: wanted %v, got %v", nextBlock.Header(), msg.Block.Header()) 778 } 779 default: 780 return fmt.Errorf("unexpected: %s", pretty.Sdump(msg)) 781 } 782 // confirm node imported block 783 if err := s.waitForBlockImport(recvConn, nextBlock, isEth66); err != nil { 784 return fmt.Errorf("error waiting for node to import new block: %v", err) 785 } 786 // update the chain 787 s.chain.blocks = append(s.chain.blocks, nextBlock) 788 return nil 789 }