github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/les/protocol.go (about)

     1  // Copyright 2016 The Spectrum Authors
     2  // This file is part of the Spectrum library.
     3  //
     4  // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package les implements the Light Ethereum Subprotocol.
    18  package les
    19  
    20  import (
    21  	"bytes"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"math/big"
    28  
    29  	"github.com/SmartMeshFoundation/Spectrum/common"
    30  	"github.com/SmartMeshFoundation/Spectrum/core"
    31  	"github.com/SmartMeshFoundation/Spectrum/crypto"
    32  	"github.com/SmartMeshFoundation/Spectrum/crypto/secp256k1"
    33  	"github.com/SmartMeshFoundation/Spectrum/rlp"
    34  )
    35  
    36  // Constants to match up protocol versions and messages
    37  const (
    38  	lpv1 = 1
    39  	lpv2 = 2
    40  )
    41  
    42  // Supported versions of the les protocol (first is primary)
    43  var (
    44  	ClientProtocolVersions = []uint{lpv2, lpv1}
    45  	ServerProtocolVersions = []uint{lpv2, lpv1}
    46  )
    47  
    48  // Number of implemented message corresponding to different protocol versions.
    49  var ProtocolLengths = map[uint]uint64{lpv1: 15, lpv2: 22}
    50  
    51  const (
    52  	NetworkId          = 1
    53  	ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message
    54  )
    55  
    56  // les protocol message codes
    57  const (
    58  	// Protocol messages belonging to LPV1
    59  	StatusMsg          = 0x00
    60  	AnnounceMsg        = 0x01
    61  	GetBlockHeadersMsg = 0x02
    62  	BlockHeadersMsg    = 0x03
    63  	GetBlockBodiesMsg  = 0x04
    64  	BlockBodiesMsg     = 0x05
    65  	GetReceiptsMsg     = 0x06
    66  	ReceiptsMsg        = 0x07
    67  	GetProofsV1Msg     = 0x08
    68  	ProofsV1Msg        = 0x09
    69  	GetCodeMsg         = 0x0a
    70  	CodeMsg            = 0x0b
    71  	SendTxMsg          = 0x0c
    72  	GetHeaderProofsMsg = 0x0d
    73  	HeaderProofsMsg    = 0x0e
    74  	// Protocol messages belonging to LPV2
    75  	GetProofsV2Msg         = 0x0f
    76  	ProofsV2Msg            = 0x10
    77  	GetHelperTrieProofsMsg = 0x11
    78  	HelperTrieProofsMsg    = 0x12
    79  	SendTxV2Msg            = 0x13
    80  	GetTxStatusMsg         = 0x14
    81  	TxStatusMsg            = 0x15
    82  )
    83  
    84  type errCode int
    85  
    86  const (
    87  	ErrMsgTooLarge = iota
    88  	ErrDecode
    89  	ErrInvalidMsgCode
    90  	ErrProtocolVersionMismatch
    91  	ErrNetworkIdMismatch
    92  	ErrGenesisBlockMismatch
    93  	ErrNoStatusMsg
    94  	ErrExtraStatusMsg
    95  	ErrSuspendedPeer
    96  	ErrUselessPeer
    97  	ErrRequestRejected
    98  	ErrUnexpectedResponse
    99  	ErrInvalidResponse
   100  	ErrTooManyTimeouts
   101  	ErrMissingKey
   102  )
   103  
   104  func (e errCode) String() string {
   105  	return errorToString[int(e)]
   106  }
   107  
   108  // XXX change once legacy code is out
   109  var errorToString = map[int]string{
   110  	ErrMsgTooLarge:             "Message too long",
   111  	ErrDecode:                  "Invalid message",
   112  	ErrInvalidMsgCode:          "Invalid message code",
   113  	ErrProtocolVersionMismatch: "Protocol version mismatch",
   114  	ErrNetworkIdMismatch:       "NetworkId mismatch",
   115  	ErrGenesisBlockMismatch:    "Genesis block mismatch",
   116  	ErrNoStatusMsg:             "No status message",
   117  	ErrExtraStatusMsg:          "Extra status message",
   118  	ErrSuspendedPeer:           "Suspended peer",
   119  	ErrRequestRejected:         "Request rejected",
   120  	ErrUnexpectedResponse:      "Unexpected response",
   121  	ErrInvalidResponse:         "Invalid response",
   122  	ErrTooManyTimeouts:         "Too many request timeouts",
   123  	ErrMissingKey:              "Key missing from list",
   124  }
   125  
   126  type announceBlock struct {
   127  	Hash   common.Hash // Hash of one particular block being announced
   128  	Number uint64      // Number of one particular block being announced
   129  	Td     *big.Int    // Total difficulty of one particular block being announced
   130  }
   131  
   132  // announceData is the network packet for the block announcements.
   133  type announceData struct {
   134  	Hash       common.Hash // Hash of one particular block being announced
   135  	Number     uint64      // Number of one particular block being announced
   136  	Td         *big.Int    // Total difficulty of one particular block being announced
   137  	ReorgDepth uint64
   138  	Update     keyValueList
   139  }
   140  
   141  // sign adds a signature to the block announcement by the given privKey
   142  func (a *announceData) sign(privKey *ecdsa.PrivateKey) {
   143  	rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
   144  	sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey)
   145  	a.Update = a.Update.add("sign", sig)
   146  }
   147  
   148  // checkSignature verifies if the block announcement has a valid signature by the given pubKey
   149  func (a *announceData) checkSignature(pubKey *ecdsa.PublicKey) error {
   150  	var sig []byte
   151  	if err := a.Update.decode().get("sign", &sig); err != nil {
   152  		return err
   153  	}
   154  	rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
   155  	recPubkey, err := secp256k1.RecoverPubkey(crypto.Keccak256(rlp), sig)
   156  	if err != nil {
   157  		return err
   158  	}
   159  	pbytes := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y)
   160  	if bytes.Equal(pbytes, recPubkey) {
   161  		return nil
   162  	} else {
   163  		return errors.New("Wrong signature")
   164  	}
   165  }
   166  
   167  type blockInfo struct {
   168  	Hash   common.Hash // Hash of one particular block being announced
   169  	Number uint64      // Number of one particular block being announced
   170  	Td     *big.Int    // Total difficulty of one particular block being announced
   171  }
   172  
   173  // getBlockHeadersData represents a block header query.
   174  type getBlockHeadersData struct {
   175  	Origin  hashOrNumber // Block from which to retrieve headers
   176  	Amount  uint64       // Maximum number of headers to retrieve
   177  	Skip    uint64       // Blocks to skip between consecutive headers
   178  	Reverse bool         // Query direction (false = rising towards latest, true = falling towards genesis)
   179  }
   180  
   181  // hashOrNumber is a combined field for specifying an origin block.
   182  type hashOrNumber struct {
   183  	Hash   common.Hash // Block hash from which to retrieve headers (excludes Number)
   184  	Number uint64      // Block hash from which to retrieve headers (excludes Hash)
   185  }
   186  
   187  // EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the
   188  // two contained union fields.
   189  func (hn *hashOrNumber) EncodeRLP(w io.Writer) error {
   190  	if hn.Hash == (common.Hash{}) {
   191  		return rlp.Encode(w, hn.Number)
   192  	}
   193  	if hn.Number != 0 {
   194  		return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
   195  	}
   196  	return rlp.Encode(w, hn.Hash)
   197  }
   198  
   199  // DecodeRLP is a specialized decoder for hashOrNumber to decode the contents
   200  // into either a block hash or a block number.
   201  func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error {
   202  	_, size, _ := s.Kind()
   203  	origin, err := s.Raw()
   204  	if err == nil {
   205  		switch {
   206  		case size == 32:
   207  			err = rlp.DecodeBytes(origin, &hn.Hash)
   208  		case size <= 8:
   209  			err = rlp.DecodeBytes(origin, &hn.Number)
   210  		default:
   211  			err = fmt.Errorf("invalid input size %d for origin", size)
   212  		}
   213  	}
   214  	return err
   215  }
   216  
   217  // CodeData is the network response packet for a node data retrieval.
   218  type CodeData []struct {
   219  	Value []byte
   220  }
   221  
   222  type proofsData [][]rlp.RawValue
   223  
   224  type txStatus struct {
   225  	Status core.TxStatus
   226  	Lookup *core.TxLookupEntry
   227  	Error  error
   228  }