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 := &eth.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 := &eth.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(&eth.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  }