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