github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/cmd/devp2p/internal/ethtest/types.go (about)

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