github.com/AlohaMobile/go-ethereum@v1.9.7/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/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/crypto"
    28  	"github.com/ethereum/go-ethereum/p2p/enode"
    29  	"github.com/ethereum/go-ethereum/rlp"
    30  )
    31  
    32  // Constants to match up protocol versions and messages
    33  const (
    34  	lpv2 = 2
    35  	lpv3 = 3
    36  )
    37  
    38  // Supported versions of the les protocol (first is primary)
    39  var (
    40  	ClientProtocolVersions    = []uint{lpv2, lpv3}
    41  	ServerProtocolVersions    = []uint{lpv2, lpv3}
    42  	AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list
    43  )
    44  
    45  // Number of implemented message corresponding to different protocol versions.
    46  var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24}
    47  
    48  const (
    49  	NetworkId          = 1
    50  	ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message
    51  )
    52  
    53  // les protocol message codes
    54  const (
    55  	// Protocol messages inherited from LPV1
    56  	StatusMsg          = 0x00
    57  	AnnounceMsg        = 0x01
    58  	GetBlockHeadersMsg = 0x02
    59  	BlockHeadersMsg    = 0x03
    60  	GetBlockBodiesMsg  = 0x04
    61  	BlockBodiesMsg     = 0x05
    62  	GetReceiptsMsg     = 0x06
    63  	ReceiptsMsg        = 0x07
    64  	GetCodeMsg         = 0x0a
    65  	CodeMsg            = 0x0b
    66  	// Protocol messages introduced in LPV2
    67  	GetProofsV2Msg         = 0x0f
    68  	ProofsV2Msg            = 0x10
    69  	GetHelperTrieProofsMsg = 0x11
    70  	HelperTrieProofsMsg    = 0x12
    71  	SendTxV2Msg            = 0x13
    72  	GetTxStatusMsg         = 0x14
    73  	TxStatusMsg            = 0x15
    74  	// Protocol messages introduced in LPV3
    75  	StopMsg   = 0x16
    76  	ResumeMsg = 0x17
    77  )
    78  
    79  type requestInfo struct {
    80  	name     string
    81  	maxCount uint64
    82  }
    83  
    84  var requests = map[uint64]requestInfo{
    85  	GetBlockHeadersMsg:     {"GetBlockHeaders", MaxHeaderFetch},
    86  	GetBlockBodiesMsg:      {"GetBlockBodies", MaxBodyFetch},
    87  	GetReceiptsMsg:         {"GetReceipts", MaxReceiptFetch},
    88  	GetCodeMsg:             {"GetCode", MaxCodeFetch},
    89  	GetProofsV2Msg:         {"GetProofsV2", MaxProofsFetch},
    90  	GetHelperTrieProofsMsg: {"GetHelperTrieProofs", MaxHelperTrieProofsFetch},
    91  	SendTxV2Msg:            {"SendTxV2", MaxTxSend},
    92  	GetTxStatusMsg:         {"GetTxStatus", MaxTxStatus},
    93  }
    94  
    95  type errCode int
    96  
    97  const (
    98  	ErrMsgTooLarge = iota
    99  	ErrDecode
   100  	ErrInvalidMsgCode
   101  	ErrProtocolVersionMismatch
   102  	ErrNetworkIdMismatch
   103  	ErrGenesisBlockMismatch
   104  	ErrNoStatusMsg
   105  	ErrExtraStatusMsg
   106  	ErrSuspendedPeer
   107  	ErrUselessPeer
   108  	ErrRequestRejected
   109  	ErrUnexpectedResponse
   110  	ErrInvalidResponse
   111  	ErrTooManyTimeouts
   112  	ErrMissingKey
   113  )
   114  
   115  func (e errCode) String() string {
   116  	return errorToString[int(e)]
   117  }
   118  
   119  // XXX change once legacy code is out
   120  var errorToString = map[int]string{
   121  	ErrMsgTooLarge:             "Message too long",
   122  	ErrDecode:                  "Invalid message",
   123  	ErrInvalidMsgCode:          "Invalid message code",
   124  	ErrProtocolVersionMismatch: "Protocol version mismatch",
   125  	ErrNetworkIdMismatch:       "NetworkId mismatch",
   126  	ErrGenesisBlockMismatch:    "Genesis block mismatch",
   127  	ErrNoStatusMsg:             "No status message",
   128  	ErrExtraStatusMsg:          "Extra status message",
   129  	ErrSuspendedPeer:           "Suspended peer",
   130  	ErrRequestRejected:         "Request rejected",
   131  	ErrUnexpectedResponse:      "Unexpected response",
   132  	ErrInvalidResponse:         "Invalid response",
   133  	ErrTooManyTimeouts:         "Too many request timeouts",
   134  	ErrMissingKey:              "Key missing from list",
   135  }
   136  
   137  type announceBlock struct {
   138  	Hash   common.Hash // Hash of one particular block being announced
   139  	Number uint64      // Number of one particular block being announced
   140  	Td     *big.Int    // Total difficulty of one particular block being announced
   141  }
   142  
   143  // announceData is the network packet for the block announcements.
   144  type announceData struct {
   145  	Hash       common.Hash // Hash of one particular block being announced
   146  	Number     uint64      // Number of one particular block being announced
   147  	Td         *big.Int    // Total difficulty of one particular block being announced
   148  	ReorgDepth uint64
   149  	Update     keyValueList
   150  }
   151  
   152  // sanityCheck verifies that the values are reasonable, as a DoS protection
   153  func (a *announceData) sanityCheck() error {
   154  	if tdlen := a.Td.BitLen(); tdlen > 100 {
   155  		return fmt.Errorf("too large block TD: bitlen %d", tdlen)
   156  	}
   157  	return nil
   158  }
   159  
   160  // sign adds a signature to the block announcement by the given privKey
   161  func (a *announceData) sign(privKey *ecdsa.PrivateKey) {
   162  	rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
   163  	sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey)
   164  	a.Update = a.Update.add("sign", sig)
   165  }
   166  
   167  // checkSignature verifies if the block announcement has a valid signature by the given pubKey
   168  func (a *announceData) checkSignature(id enode.ID, update keyValueMap) error {
   169  	var sig []byte
   170  	if err := update.get("sign", &sig); err != nil {
   171  		return err
   172  	}
   173  	rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
   174  	recPubkey, err := crypto.SigToPub(crypto.Keccak256(rlp), sig)
   175  	if err != nil {
   176  		return err
   177  	}
   178  	if id == enode.PubkeyToIDV4(recPubkey) {
   179  		return nil
   180  	}
   181  	return errors.New("wrong signature")
   182  }
   183  
   184  type blockInfo struct {
   185  	Hash   common.Hash // Hash of one particular block being announced
   186  	Number uint64      // Number of one particular block being announced
   187  	Td     *big.Int    // Total difficulty of one particular block being announced
   188  }
   189  
   190  // getBlockHeadersData represents a block header query.
   191  type getBlockHeadersData struct {
   192  	Origin  hashOrNumber // Block from which to retrieve headers
   193  	Amount  uint64       // Maximum number of headers to retrieve
   194  	Skip    uint64       // Blocks to skip between consecutive headers
   195  	Reverse bool         // Query direction (false = rising towards latest, true = falling towards genesis)
   196  }
   197  
   198  // hashOrNumber is a combined field for specifying an origin block.
   199  type hashOrNumber struct {
   200  	Hash   common.Hash // Block hash from which to retrieve headers (excludes Number)
   201  	Number uint64      // Block hash from which to retrieve headers (excludes Hash)
   202  }
   203  
   204  // EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the
   205  // two contained union fields.
   206  func (hn *hashOrNumber) EncodeRLP(w io.Writer) error {
   207  	if hn.Hash == (common.Hash{}) {
   208  		return rlp.Encode(w, hn.Number)
   209  	}
   210  	if hn.Number != 0 {
   211  		return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
   212  	}
   213  	return rlp.Encode(w, hn.Hash)
   214  }
   215  
   216  // DecodeRLP is a specialized decoder for hashOrNumber to decode the contents
   217  // into either a block hash or a block number.
   218  func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error {
   219  	_, size, _ := s.Kind()
   220  	origin, err := s.Raw()
   221  	if err == nil {
   222  		switch {
   223  		case size == 32:
   224  			err = rlp.DecodeBytes(origin, &hn.Hash)
   225  		case size <= 8:
   226  			err = rlp.DecodeBytes(origin, &hn.Number)
   227  		default:
   228  			err = fmt.Errorf("invalid input size %d for origin", size)
   229  		}
   230  	}
   231  	return err
   232  }
   233  
   234  // CodeData is the network response packet for a node data retrieval.
   235  type CodeData []struct {
   236  	Value []byte
   237  }
   238  
   239  type proofsData [][]rlp.RawValue