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