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