github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/cmd/devp2p/internal/ethtest/helpers.go (about)

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