github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/cmd/devp2p/internal/ethtest/types.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  	"crypto/ecdsa"
    21  	"fmt"
    22  	"time"
    23  
    24  	"github.com/ethereum/go-ethereum/eth/protocols/eth"
    25  	"github.com/ethereum/go-ethereum/p2p"
    26  	"github.com/ethereum/go-ethereum/p2p/rlpx"
    27  	"github.com/ethereum/go-ethereum/rlp"
    28  )
    29  
    30  type Message interface {
    31  	Code() int
    32  }
    33  
    34  type Error struct {
    35  	err error
    36  }
    37  
    38  func (e *Error) Unwrap() error  { return e.err }
    39  func (e *Error) Error() string  { return e.err.Error() }
    40  func (e *Error) Code() int      { return -1 }
    41  func (e *Error) String() string { return e.Error() }
    42  
    43  func errorf(format string, args ...interface{}) *Error {
    44  	return &Error{fmt.Errorf(format, args...)}
    45  }
    46  
    47  // Hello is the RLP structure of the protocol handshake.
    48  type Hello struct {
    49  	Version    uint64
    50  	Name       string
    51  	Caps       []p2p.Cap
    52  	ListenPort uint64
    53  	ID         []byte // secp256k1 public key
    54  
    55  	// Ignore additional fields (for forward compatibility).
    56  	Rest []rlp.RawValue `rlp:"tail"`
    57  }
    58  
    59  func (h Hello) Code() int { return 0x00 }
    60  
    61  // Disconnect is the RLP structure for a disconnect message.
    62  type Disconnect struct {
    63  	Reason p2p.DiscReason
    64  }
    65  
    66  func (d Disconnect) Code() int { return 0x01 }
    67  
    68  type Ping struct{}
    69  
    70  func (p Ping) Code() int { return 0x02 }
    71  
    72  type Pong struct{}
    73  
    74  func (p Pong) Code() int { return 0x03 }
    75  
    76  // Status is the network packet for the status message for eth/64 and later.
    77  type Status eth.StatusPacket
    78  
    79  func (s Status) Code() int { return 16 }
    80  
    81  // NewBlockHashes is the network packet for the block announcements.
    82  type NewBlockHashes eth.NewBlockHashesPacket
    83  
    84  func (nbh NewBlockHashes) Code() int { return 17 }
    85  
    86  type Transactions eth.TransactionsPacket
    87  
    88  func (t Transactions) Code() int { return 18 }
    89  
    90  // GetBlockHeaders represents a block header query.
    91  type GetBlockHeaders eth.GetBlockHeadersPacket
    92  
    93  func (g GetBlockHeaders) Code() int { return 19 }
    94  
    95  type BlockHeaders eth.BlockHeadersPacket
    96  
    97  func (bh BlockHeaders) Code() int { return 20 }
    98  
    99  // GetBlockBodies represents a GetBlockBodies request
   100  type GetBlockBodies eth.GetBlockBodiesPacket
   101  
   102  func (gbb GetBlockBodies) Code() int { return 21 }
   103  
   104  // BlockBodies is the network packet for block content distribution.
   105  type BlockBodies eth.BlockBodiesPacket
   106  
   107  func (bb BlockBodies) Code() int { return 22 }
   108  
   109  // NewBlock is the network packet for the block propagation message.
   110  type NewBlock eth.NewBlockPacket
   111  
   112  func (nb NewBlock) Code() int { return 23 }
   113  
   114  // NewPooledTransactionHashes is the network packet for the tx hash propagation message.
   115  type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket
   116  
   117  func (nb NewPooledTransactionHashes) Code() int { return 24 }
   118  
   119  type GetPooledTransactions eth.GetPooledTransactionsPacket
   120  
   121  func (gpt GetPooledTransactions) Code() int { return 25 }
   122  
   123  type PooledTransactions eth.PooledTransactionsPacket
   124  
   125  func (pt PooledTransactions) Code() int { return 26 }
   126  
   127  // Conn represents an individual connection with a peer
   128  type Conn struct {
   129  	*rlpx.Conn
   130  	ourKey                     *ecdsa.PrivateKey
   131  	negotiatedProtoVersion     uint
   132  	negotiatedSnapProtoVersion uint
   133  	ourHighestProtoVersion     uint
   134  	ourHighestSnapProtoVersion uint
   135  	caps                       []p2p.Cap
   136  }
   137  
   138  // Read reads an eth packet from the connection.
   139  func (c *Conn) Read() Message {
   140  	code, rawData, _, err := c.Conn.Read()
   141  	if err != nil {
   142  		return errorf("could not read from connection: %v", err)
   143  	}
   144  
   145  	var msg Message
   146  	switch int(code) {
   147  	case (Hello{}).Code():
   148  		msg = new(Hello)
   149  	case (Ping{}).Code():
   150  		msg = new(Ping)
   151  	case (Pong{}).Code():
   152  		msg = new(Pong)
   153  	case (Disconnect{}).Code():
   154  		msg = new(Disconnect)
   155  	case (Status{}).Code():
   156  		msg = new(Status)
   157  	case (GetBlockHeaders{}).Code():
   158  		msg = new(GetBlockHeaders)
   159  	case (BlockHeaders{}).Code():
   160  		msg = new(BlockHeaders)
   161  	case (GetBlockBodies{}).Code():
   162  		msg = new(GetBlockBodies)
   163  	case (BlockBodies{}).Code():
   164  		msg = new(BlockBodies)
   165  	case (NewBlock{}).Code():
   166  		msg = new(NewBlock)
   167  	case (NewBlockHashes{}).Code():
   168  		msg = new(NewBlockHashes)
   169  	case (Transactions{}).Code():
   170  		msg = new(Transactions)
   171  	case (NewPooledTransactionHashes{}).Code():
   172  		msg = new(NewPooledTransactionHashes)
   173  	case (GetPooledTransactions{}.Code()):
   174  		msg = new(GetPooledTransactions)
   175  	case (PooledTransactions{}.Code()):
   176  		msg = new(PooledTransactions)
   177  	default:
   178  		return errorf("invalid message code: %d", code)
   179  	}
   180  	// if message is devp2p, decode here
   181  	if err := rlp.DecodeBytes(rawData, msg); err != nil {
   182  		return errorf("could not rlp decode message: %v", err)
   183  	}
   184  	return msg
   185  }
   186  
   187  // Read66 reads an eth66 packet from the connection.
   188  func (c *Conn) Read66() (uint64, Message) {
   189  	code, rawData, _, err := c.Conn.Read()
   190  	if err != nil {
   191  		return 0, errorf("could not read from connection: %v", err)
   192  	}
   193  
   194  	var msg Message
   195  	switch int(code) {
   196  	case (Hello{}).Code():
   197  		msg = new(Hello)
   198  	case (Ping{}).Code():
   199  		msg = new(Ping)
   200  	case (Pong{}).Code():
   201  		msg = new(Pong)
   202  	case (Disconnect{}).Code():
   203  		msg = new(Disconnect)
   204  	case (Status{}).Code():
   205  		msg = new(Status)
   206  	case (GetBlockHeaders{}).Code():
   207  		ethMsg := new(eth.GetBlockHeadersPacket66)
   208  		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil {
   209  			return 0, errorf("could not rlp decode message: %v", err)
   210  		}
   211  		return ethMsg.RequestId, GetBlockHeaders(*ethMsg.GetBlockHeadersPacket)
   212  	case (BlockHeaders{}).Code():
   213  		ethMsg := new(eth.BlockHeadersPacket66)
   214  		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil {
   215  			return 0, errorf("could not rlp decode message: %v", err)
   216  		}
   217  		return ethMsg.RequestId, BlockHeaders(ethMsg.BlockHeadersPacket)
   218  	case (GetBlockBodies{}).Code():
   219  		ethMsg := new(eth.GetBlockBodiesPacket66)
   220  		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil {
   221  			return 0, errorf("could not rlp decode message: %v", err)
   222  		}
   223  		return ethMsg.RequestId, GetBlockBodies(ethMsg.GetBlockBodiesPacket)
   224  	case (BlockBodies{}).Code():
   225  		ethMsg := new(eth.BlockBodiesPacket66)
   226  		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil {
   227  			return 0, errorf("could not rlp decode message: %v", err)
   228  		}
   229  		return ethMsg.RequestId, BlockBodies(ethMsg.BlockBodiesPacket)
   230  	case (NewBlock{}).Code():
   231  		msg = new(NewBlock)
   232  	case (NewBlockHashes{}).Code():
   233  		msg = new(NewBlockHashes)
   234  	case (Transactions{}).Code():
   235  		msg = new(Transactions)
   236  	case (NewPooledTransactionHashes{}).Code():
   237  		msg = new(NewPooledTransactionHashes)
   238  	case (GetPooledTransactions{}.Code()):
   239  		ethMsg := new(eth.GetPooledTransactionsPacket66)
   240  		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil {
   241  			return 0, errorf("could not rlp decode message: %v", err)
   242  		}
   243  		return ethMsg.RequestId, GetPooledTransactions(ethMsg.GetPooledTransactionsPacket)
   244  	case (PooledTransactions{}.Code()):
   245  		ethMsg := new(eth.PooledTransactionsPacket66)
   246  		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil {
   247  			return 0, errorf("could not rlp decode message: %v", err)
   248  		}
   249  		return ethMsg.RequestId, PooledTransactions(ethMsg.PooledTransactionsPacket)
   250  	default:
   251  		msg = errorf("invalid message code: %d", code)
   252  	}
   253  
   254  	if msg != nil {
   255  		if err := rlp.DecodeBytes(rawData, msg); err != nil {
   256  			return 0, errorf("could not rlp decode message: %v", err)
   257  		}
   258  		return 0, msg
   259  	}
   260  	return 0, errorf("invalid message: %s", string(rawData))
   261  }
   262  
   263  // Write writes a eth packet to the connection.
   264  func (c *Conn) Write(msg Message) error {
   265  	payload, err := rlp.EncodeToBytes(msg)
   266  	if err != nil {
   267  		return err
   268  	}
   269  	_, err = c.Conn.Write(uint64(msg.Code()), payload)
   270  	return err
   271  }
   272  
   273  // Write66 writes an eth66 packet to the connection.
   274  func (c *Conn) Write66(req eth.Packet, code int) error {
   275  	payload, err := rlp.EncodeToBytes(req)
   276  	if err != nil {
   277  		return err
   278  	}
   279  	_, err = c.Conn.Write(uint64(code), payload)
   280  	return err
   281  }
   282  
   283  // ReadSnap reads a snap/1 response with the given id from the connection.
   284  func (c *Conn) ReadSnap(id uint64) (Message, error) {
   285  	respId := id + 1
   286  	start := time.Now()
   287  	for respId != id && time.Since(start) < timeout {
   288  		code, rawData, _, err := c.Conn.Read()
   289  		if err != nil {
   290  			return nil, fmt.Errorf("could not read from connection: %v", err)
   291  		}
   292  		var snpMsg interface{}
   293  		switch int(code) {
   294  		case (GetAccountRange{}).Code():
   295  			snpMsg = new(GetAccountRange)
   296  		case (AccountRange{}).Code():
   297  			snpMsg = new(AccountRange)
   298  		case (GetStorageRanges{}).Code():
   299  			snpMsg = new(GetStorageRanges)
   300  		case (StorageRanges{}).Code():
   301  			snpMsg = new(StorageRanges)
   302  		case (GetByteCodes{}).Code():
   303  			snpMsg = new(GetByteCodes)
   304  		case (ByteCodes{}).Code():
   305  			snpMsg = new(ByteCodes)
   306  		case (GetTrieNodes{}).Code():
   307  			snpMsg = new(GetTrieNodes)
   308  		case (TrieNodes{}).Code():
   309  			snpMsg = new(TrieNodes)
   310  		default:
   311  			//return nil, fmt.Errorf("invalid message code: %d", code)
   312  			continue
   313  		}
   314  		if err := rlp.DecodeBytes(rawData, snpMsg); err != nil {
   315  			return nil, fmt.Errorf("could not rlp decode message: %v", err)
   316  		}
   317  		return snpMsg.(Message), nil
   318  
   319  	}
   320  	return nil, fmt.Errorf("request timed out")
   321  }