github.com/theQRL/go-zond@v0.1.1/les/protocol.go (about)

     1  // Copyright 2016 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 les
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"math/big"
    25  
    26  	"github.com/theQRL/go-zond/common"
    27  	"github.com/theQRL/go-zond/core/types"
    28  	"github.com/theQRL/go-zond/crypto"
    29  	vfc "github.com/theQRL/go-zond/les/vflux/client"
    30  	"github.com/theQRL/go-zond/p2p/enode"
    31  	"github.com/theQRL/go-zond/rlp"
    32  )
    33  
    34  // Constants to match up protocol versions and messages
    35  const (
    36  	lpv2 = 2
    37  	lpv3 = 3
    38  	lpv4 = 4
    39  )
    40  
    41  // Supported versions of the les protocol (first is primary)
    42  var (
    43  	ClientProtocolVersions = []uint{lpv2, lpv3, lpv4}
    44  	ServerProtocolVersions = []uint{lpv2, lpv3, lpv4}
    45  )
    46  
    47  // ProtocolLengths is the number of implemented message corresponding to different protocol versions.
    48  var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24, lpv4: 24}
    49  
    50  const (
    51  	NetworkId          = 1
    52  	ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message
    53  	blockSafetyMargin  = 4                // safety margin applied to block ranges specified relative to head block
    54  
    55  	txIndexUnlimited    = 0 // this value in the "recentTxLookup" handshake field means the entire tx index history is served
    56  	txIndexDisabled     = 1 // this value means tx index is not served at all
    57  	txIndexRecentOffset = 1 // txIndexRecentOffset + N in the handshake field means then tx index of the last N blocks is supported
    58  )
    59  
    60  // les protocol message codes
    61  const (
    62  	// Protocol messages inherited from LPV1
    63  	StatusMsg          = 0x00
    64  	AnnounceMsg        = 0x01
    65  	GetBlockHeadersMsg = 0x02
    66  	BlockHeadersMsg    = 0x03
    67  	GetBlockBodiesMsg  = 0x04
    68  	BlockBodiesMsg     = 0x05
    69  	GetReceiptsMsg     = 0x06
    70  	ReceiptsMsg        = 0x07
    71  	GetCodeMsg         = 0x0a
    72  	CodeMsg            = 0x0b
    73  	// Protocol messages introduced in LPV2
    74  	GetProofsV2Msg         = 0x0f
    75  	ProofsV2Msg            = 0x10
    76  	GetHelperTrieProofsMsg = 0x11
    77  	HelperTrieProofsMsg    = 0x12
    78  	SendTxV2Msg            = 0x13
    79  	GetTxStatusMsg         = 0x14
    80  	TxStatusMsg            = 0x15
    81  	// Protocol messages introduced in LPV3
    82  	StopMsg   = 0x16
    83  	ResumeMsg = 0x17
    84  )
    85  
    86  // GetBlockHeadersData represents a block header query (the request ID is not included)
    87  type GetBlockHeadersData struct {
    88  	Origin  hashOrNumber // Block from which to retrieve headers
    89  	Amount  uint64       // Maximum number of headers to retrieve
    90  	Skip    uint64       // Blocks to skip between consecutive headers
    91  	Reverse bool         // Query direction (false = rising towards latest, true = falling towards genesis)
    92  }
    93  
    94  // GetBlockHeadersPacket represents a block header request
    95  type GetBlockHeadersPacket struct {
    96  	ReqID uint64
    97  	Query GetBlockHeadersData
    98  }
    99  
   100  // GetBlockBodiesPacket represents a block body request
   101  type GetBlockBodiesPacket struct {
   102  	ReqID  uint64
   103  	Hashes []common.Hash
   104  }
   105  
   106  // GetCodePacket represents a contract code request
   107  type GetCodePacket struct {
   108  	ReqID uint64
   109  	Reqs  []CodeReq
   110  }
   111  
   112  // GetReceiptsPacket represents a block receipts request
   113  type GetReceiptsPacket struct {
   114  	ReqID  uint64
   115  	Hashes []common.Hash
   116  }
   117  
   118  // GetProofsPacket represents a proof request
   119  type GetProofsPacket struct {
   120  	ReqID uint64
   121  	Reqs  []ProofReq
   122  }
   123  
   124  // GetHelperTrieProofsPacket represents a helper trie proof request
   125  type GetHelperTrieProofsPacket struct {
   126  	ReqID uint64
   127  	Reqs  []HelperTrieReq
   128  }
   129  
   130  // SendTxPacket represents a transaction propagation request
   131  type SendTxPacket struct {
   132  	ReqID uint64
   133  	Txs   []*types.Transaction
   134  }
   135  
   136  // GetTxStatusPacket represents a transaction status query
   137  type GetTxStatusPacket struct {
   138  	ReqID  uint64
   139  	Hashes []common.Hash
   140  }
   141  
   142  type requestInfo struct {
   143  	name                          string
   144  	maxCount                      uint64
   145  	refBasketFirst, refBasketRest float64
   146  }
   147  
   148  // reqMapping maps an LES request to one or two vflux service vector entries.
   149  // If rest != -1 and the request type is used with amounts larger than one then the
   150  // first one of the multi-request is mapped to first while the rest is mapped to rest.
   151  type reqMapping struct {
   152  	first, rest int
   153  }
   154  
   155  var (
   156  	// requests describes the available LES request types and their initializing amounts
   157  	// in the vfc.ValueTracker reference basket. Initial values are estimates
   158  	// based on the same values as the server's default cost estimates (reqAvgTimeCost).
   159  	requests = map[uint64]requestInfo{
   160  		GetBlockHeadersMsg:     {"GetBlockHeaders", MaxHeaderFetch, 10, 1000},
   161  		GetBlockBodiesMsg:      {"GetBlockBodies", MaxBodyFetch, 1, 0},
   162  		GetReceiptsMsg:         {"GetReceipts", MaxReceiptFetch, 1, 0},
   163  		GetCodeMsg:             {"GetCode", MaxCodeFetch, 1, 0},
   164  		GetProofsV2Msg:         {"GetProofsV2", MaxProofsFetch, 10, 0},
   165  		GetHelperTrieProofsMsg: {"GetHelperTrieProofs", MaxHelperTrieProofsFetch, 10, 100},
   166  		SendTxV2Msg:            {"SendTxV2", MaxTxSend, 1, 0},
   167  		GetTxStatusMsg:         {"GetTxStatus", MaxTxStatus, 10, 0},
   168  	}
   169  	requestList    []vfc.RequestInfo
   170  	requestMapping map[uint32]reqMapping
   171  )
   172  
   173  // init creates a request list and mapping between protocol message codes and vflux
   174  // service vector indices.
   175  func init() {
   176  	requestMapping = make(map[uint32]reqMapping)
   177  	for code, req := range requests {
   178  		cost := reqAvgTimeCost[code]
   179  		rm := reqMapping{len(requestList), -1}
   180  		requestList = append(requestList, vfc.RequestInfo{
   181  			Name:       req.name + ".first",
   182  			InitAmount: req.refBasketFirst,
   183  			InitValue:  float64(cost.baseCost + cost.reqCost),
   184  		})
   185  		if req.refBasketRest != 0 {
   186  			rm.rest = len(requestList)
   187  			requestList = append(requestList, vfc.RequestInfo{
   188  				Name:       req.name + ".rest",
   189  				InitAmount: req.refBasketRest,
   190  				InitValue:  float64(cost.reqCost),
   191  			})
   192  		}
   193  		requestMapping[uint32(code)] = rm
   194  	}
   195  }
   196  
   197  type errCode int
   198  
   199  const (
   200  	ErrMsgTooLarge = iota
   201  	ErrDecode
   202  	ErrInvalidMsgCode
   203  	ErrProtocolVersionMismatch
   204  	ErrNetworkIdMismatch
   205  	ErrGenesisBlockMismatch
   206  	ErrNoStatusMsg
   207  	ErrExtraStatusMsg
   208  	ErrSuspendedPeer
   209  	ErrUselessPeer
   210  	ErrRequestRejected
   211  	ErrUnexpectedResponse
   212  	ErrInvalidResponse
   213  	ErrTooManyTimeouts
   214  	ErrMissingKey
   215  	ErrForkIDRejected
   216  )
   217  
   218  func (e errCode) String() string {
   219  	return errorToString[int(e)]
   220  }
   221  
   222  // XXX change once legacy code is out
   223  var errorToString = map[int]string{
   224  	ErrMsgTooLarge:             "Message too long",
   225  	ErrDecode:                  "Invalid message",
   226  	ErrInvalidMsgCode:          "Invalid message code",
   227  	ErrProtocolVersionMismatch: "Protocol version mismatch",
   228  	ErrNetworkIdMismatch:       "NetworkId mismatch",
   229  	ErrGenesisBlockMismatch:    "Genesis block mismatch",
   230  	ErrNoStatusMsg:             "No status message",
   231  	ErrExtraStatusMsg:          "Extra status message",
   232  	ErrSuspendedPeer:           "Suspended peer",
   233  	ErrRequestRejected:         "Request rejected",
   234  	ErrUnexpectedResponse:      "Unexpected response",
   235  	ErrInvalidResponse:         "Invalid response",
   236  	ErrTooManyTimeouts:         "Too many request timeouts",
   237  	ErrMissingKey:              "Key missing from list",
   238  	ErrForkIDRejected:          "ForkID rejected",
   239  }
   240  
   241  // announceData is the network packet for the block announcements.
   242  type announceData struct {
   243  	Hash       common.Hash // Hash of one particular block being announced
   244  	Number     uint64      // Number of one particular block being announced
   245  	Td         *big.Int    // Total difficulty of one particular block being announced
   246  	ReorgDepth uint64
   247  	Update     keyValueList
   248  }
   249  
   250  // sanityCheck verifies that the values are reasonable, as a DoS protection
   251  func (a *announceData) sanityCheck() error {
   252  	if tdlen := a.Td.BitLen(); tdlen > 100 {
   253  		return fmt.Errorf("too large block TD: bitlen %d", tdlen)
   254  	}
   255  	return nil
   256  }
   257  
   258  // sign adds a signature to the block announcement by the given privKey
   259  func (a *announceData) sign(privKey *ecdsa.PrivateKey) {
   260  	rlp, _ := rlp.EncodeToBytes(blockInfo{a.Hash, a.Number, a.Td})
   261  	sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey)
   262  	a.Update = a.Update.add("sign", sig)
   263  }
   264  
   265  // checkSignature verifies if the block announcement has a valid signature by the given pubKey
   266  func (a *announceData) checkSignature(id enode.ID, update keyValueMap) error {
   267  	var sig []byte
   268  	if err := update.get("sign", &sig); err != nil {
   269  		return err
   270  	}
   271  	rlp, _ := rlp.EncodeToBytes(blockInfo{a.Hash, a.Number, a.Td})
   272  	recPubkey, err := crypto.SigToPub(crypto.Keccak256(rlp), sig)
   273  	if err != nil {
   274  		return err
   275  	}
   276  	if id == enode.PubkeyToIDV4(recPubkey) {
   277  		return nil
   278  	}
   279  	return errors.New("wrong signature")
   280  }
   281  
   282  type blockInfo struct {
   283  	Hash   common.Hash // Hash of one particular block being announced
   284  	Number uint64      // Number of one particular block being announced
   285  	Td     *big.Int    // Total difficulty of one particular block being announced
   286  }
   287  
   288  // hashOrNumber is a combined field for specifying an origin block.
   289  type hashOrNumber struct {
   290  	Hash   common.Hash // Block hash from which to retrieve headers (excludes Number)
   291  	Number uint64      // Block hash from which to retrieve headers (excludes Hash)
   292  }
   293  
   294  // EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the
   295  // two contained union fields.
   296  func (hn *hashOrNumber) EncodeRLP(w io.Writer) error {
   297  	if hn.Hash == (common.Hash{}) {
   298  		return rlp.Encode(w, hn.Number)
   299  	}
   300  	if hn.Number != 0 {
   301  		return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
   302  	}
   303  	return rlp.Encode(w, hn.Hash)
   304  }
   305  
   306  // DecodeRLP is a specialized decoder for hashOrNumber to decode the contents
   307  // into either a block hash or a block number.
   308  func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error {
   309  	_, size, err := s.Kind()
   310  	switch {
   311  	case err != nil:
   312  		return err
   313  	case size == 32:
   314  		hn.Number = 0
   315  		return s.Decode(&hn.Hash)
   316  	case size <= 8:
   317  		hn.Hash = common.Hash{}
   318  		return s.Decode(&hn.Number)
   319  	default:
   320  		return fmt.Errorf("invalid input size %d for origin", size)
   321  	}
   322  }
   323  
   324  // CodeData is the network response packet for a node data retrieval.
   325  type CodeData []struct {
   326  	Value []byte
   327  }