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