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