github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/les/odr_requests.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  	"encoding/binary"
    21  	"errors"
    22  	"fmt"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/core/rawdb"
    26  	"github.com/ethereum/go-ethereum/core/types"
    27  	"github.com/ethereum/go-ethereum/crypto"
    28  	"github.com/ethereum/go-ethereum/ethdb"
    29  	"github.com/ethereum/go-ethereum/light"
    30  	"github.com/ethereum/go-ethereum/log"
    31  	"github.com/ethereum/go-ethereum/rlp"
    32  	"github.com/ethereum/go-ethereum/trie"
    33  )
    34  
    35  var (
    36  	errInvalidMessageType  = errors.New("invalid message type")
    37  	errInvalidEntryCount   = errors.New("invalid number of response entries")
    38  	errHeaderUnavailable   = errors.New("header unavailable")
    39  	errTxHashMismatch      = errors.New("transaction hash mismatch")
    40  	errUncleHashMismatch   = errors.New("uncle hash mismatch")
    41  	errReceiptHashMismatch = errors.New("receipt hash mismatch")
    42  	errDataHashMismatch    = errors.New("data hash mismatch")
    43  	errCHTHashMismatch     = errors.New("cht hash mismatch")
    44  	errCHTNumberMismatch   = errors.New("cht number mismatch")
    45  	errUselessNodes        = errors.New("useless nodes in merkle proof nodeset")
    46  )
    47  
    48  type LesOdrRequest interface {
    49  	GetCost(*peer) uint64
    50  	CanSend(*peer) bool
    51  	Request(uint64, *peer) error
    52  	Validate(ethdb.Database, *Msg) error
    53  }
    54  
    55  func LesRequest(req light.OdrRequest) LesOdrRequest {
    56  	switch r := req.(type) {
    57  	case *light.BlockRequest:
    58  		return (*BlockRequest)(r)
    59  	case *light.ReceiptsRequest:
    60  		return (*ReceiptsRequest)(r)
    61  	case *light.TrieRequest:
    62  		return (*TrieRequest)(r)
    63  	case *light.CodeRequest:
    64  		return (*CodeRequest)(r)
    65  	case *light.ChtRequest:
    66  		return (*ChtRequest)(r)
    67  	case *light.BloomRequest:
    68  		return (*BloomRequest)(r)
    69  	default:
    70  		return nil
    71  	}
    72  }
    73  
    74  // BlockRequest is the ODR request type for block bodies
    75  type BlockRequest light.BlockRequest
    76  
    77  // GetCost returns the cost of the given ODR request according to the serving
    78  // peer's cost table (implementation of LesOdrRequest)
    79  func (r *BlockRequest) GetCost(peer *peer) uint64 {
    80  	return peer.GetRequestCost(GetBlockBodiesMsg, 1)
    81  }
    82  
    83  // CanSend tells if a certain peer is suitable for serving the given request
    84  func (r *BlockRequest) CanSend(peer *peer) bool {
    85  	return peer.HasBlock(r.Hash, r.Number, false)
    86  }
    87  
    88  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
    89  func (r *BlockRequest) Request(reqID uint64, peer *peer) error {
    90  	peer.Log().Debug("Requesting block body", "hash", r.Hash)
    91  	return peer.RequestBodies(reqID, r.GetCost(peer), []common.Hash{r.Hash})
    92  }
    93  
    94  // Valid processes an ODR request reply message from the LES network
    95  // returns true and stores results in memory if the message was a valid reply
    96  // to the request (implementation of LesOdrRequest)
    97  func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error {
    98  	log.Debug("Validating block body", "hash", r.Hash)
    99  
   100  	// Ensure we have a correct message with a single block body
   101  	if msg.MsgType != MsgBlockBodies {
   102  		return errInvalidMessageType
   103  	}
   104  	bodies := msg.Obj.([]*types.Body)
   105  	if len(bodies) != 1 {
   106  		return errInvalidEntryCount
   107  	}
   108  	body := bodies[0]
   109  
   110  	// Retrieve our stored header and validate block content against it
   111  	header := rawdb.ReadHeader(db, r.Hash, r.Number)
   112  	if header == nil {
   113  		return errHeaderUnavailable
   114  	}
   115  	if header.TxHash != types.DeriveSha(types.Transactions(body.Transactions)) {
   116  		return errTxHashMismatch
   117  	}
   118  	if header.UncleHash != types.CalcUncleHash(body.Uncles) {
   119  		return errUncleHashMismatch
   120  	}
   121  	// Validations passed, encode and store RLP
   122  	data, err := rlp.EncodeToBytes(body)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	r.Rlp = data
   127  	return nil
   128  }
   129  
   130  // ReceiptsRequest is the ODR request type for block receipts by block hash
   131  type ReceiptsRequest light.ReceiptsRequest
   132  
   133  // GetCost returns the cost of the given ODR request according to the serving
   134  // peer's cost table (implementation of LesOdrRequest)
   135  func (r *ReceiptsRequest) GetCost(peer *peer) uint64 {
   136  	return peer.GetRequestCost(GetReceiptsMsg, 1)
   137  }
   138  
   139  // CanSend tells if a certain peer is suitable for serving the given request
   140  func (r *ReceiptsRequest) CanSend(peer *peer) bool {
   141  	return peer.HasBlock(r.Hash, r.Number, false)
   142  }
   143  
   144  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   145  func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
   146  	peer.Log().Debug("Requesting block receipts", "hash", r.Hash)
   147  	return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Hash})
   148  }
   149  
   150  // Valid processes an ODR request reply message from the LES network
   151  // returns true and stores results in memory if the message was a valid reply
   152  // to the request (implementation of LesOdrRequest)
   153  func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
   154  	log.Debug("Validating block receipts", "hash", r.Hash)
   155  
   156  	// Ensure we have a correct message with a single block receipt
   157  	if msg.MsgType != MsgReceipts {
   158  		return errInvalidMessageType
   159  	}
   160  	receipts := msg.Obj.([]types.Receipts)
   161  	if len(receipts) != 1 {
   162  		return errInvalidEntryCount
   163  	}
   164  	receipt := receipts[0]
   165  
   166  	// Retrieve our stored header and validate receipt content against it
   167  	header := rawdb.ReadHeader(db, r.Hash, r.Number)
   168  	if header == nil {
   169  		return errHeaderUnavailable
   170  	}
   171  	if header.ReceiptHash != types.DeriveSha(receipt) {
   172  		return errReceiptHashMismatch
   173  	}
   174  	// Validations passed, store and return
   175  	r.Receipts = receipt
   176  	return nil
   177  }
   178  
   179  type ProofReq struct {
   180  	BHash       common.Hash
   181  	AccKey, Key []byte
   182  	FromLevel   uint
   183  }
   184  
   185  // ODR request type for state/storage trie entries, see LesOdrRequest interface
   186  type TrieRequest light.TrieRequest
   187  
   188  // GetCost returns the cost of the given ODR request according to the serving
   189  // peer's cost table (implementation of LesOdrRequest)
   190  func (r *TrieRequest) GetCost(peer *peer) uint64 {
   191  	return peer.GetRequestCost(GetProofsV2Msg, 1)
   192  }
   193  
   194  // CanSend tells if a certain peer is suitable for serving the given request
   195  func (r *TrieRequest) CanSend(peer *peer) bool {
   196  	return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true)
   197  }
   198  
   199  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   200  func (r *TrieRequest) Request(reqID uint64, peer *peer) error {
   201  	peer.Log().Debug("Requesting trie proof", "root", r.Id.Root, "key", r.Key)
   202  	req := ProofReq{
   203  		BHash:  r.Id.BlockHash,
   204  		AccKey: r.Id.AccKey,
   205  		Key:    r.Key,
   206  	}
   207  	return peer.RequestProofs(reqID, r.GetCost(peer), []ProofReq{req})
   208  }
   209  
   210  // Valid processes an ODR request reply message from the LES network
   211  // returns true and stores results in memory if the message was a valid reply
   212  // to the request (implementation of LesOdrRequest)
   213  func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
   214  	log.Debug("Validating trie proof", "root", r.Id.Root, "key", r.Key)
   215  
   216  	if msg.MsgType != MsgProofsV2 {
   217  		return errInvalidMessageType
   218  	}
   219  	proofs := msg.Obj.(light.NodeList)
   220  	// Verify the proof and store if checks out
   221  	nodeSet := proofs.NodeSet()
   222  	reads := &readTraceDB{db: nodeSet}
   223  	if _, _, err := trie.VerifyProof(r.Id.Root, r.Key, reads); err != nil {
   224  		return fmt.Errorf("merkle proof verification failed: %v", err)
   225  	}
   226  	// check if all nodes have been read by VerifyProof
   227  	if len(reads.reads) != nodeSet.KeyCount() {
   228  		return errUselessNodes
   229  	}
   230  	r.Proof = nodeSet
   231  	return nil
   232  }
   233  
   234  type CodeReq struct {
   235  	BHash  common.Hash
   236  	AccKey []byte
   237  }
   238  
   239  // ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface
   240  type CodeRequest light.CodeRequest
   241  
   242  // GetCost returns the cost of the given ODR request according to the serving
   243  // peer's cost table (implementation of LesOdrRequest)
   244  func (r *CodeRequest) GetCost(peer *peer) uint64 {
   245  	return peer.GetRequestCost(GetCodeMsg, 1)
   246  }
   247  
   248  // CanSend tells if a certain peer is suitable for serving the given request
   249  func (r *CodeRequest) CanSend(peer *peer) bool {
   250  	return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true)
   251  }
   252  
   253  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   254  func (r *CodeRequest) Request(reqID uint64, peer *peer) error {
   255  	peer.Log().Debug("Requesting code data", "hash", r.Hash)
   256  	req := CodeReq{
   257  		BHash:  r.Id.BlockHash,
   258  		AccKey: r.Id.AccKey,
   259  	}
   260  	return peer.RequestCode(reqID, r.GetCost(peer), []CodeReq{req})
   261  }
   262  
   263  // Valid processes an ODR request reply message from the LES network
   264  // returns true and stores results in memory if the message was a valid reply
   265  // to the request (implementation of LesOdrRequest)
   266  func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error {
   267  	log.Debug("Validating code data", "hash", r.Hash)
   268  
   269  	// Ensure we have a correct message with a single code element
   270  	if msg.MsgType != MsgCode {
   271  		return errInvalidMessageType
   272  	}
   273  	reply := msg.Obj.([][]byte)
   274  	if len(reply) != 1 {
   275  		return errInvalidEntryCount
   276  	}
   277  	data := reply[0]
   278  
   279  	// Verify the data and store if checks out
   280  	if hash := crypto.Keccak256Hash(data); r.Hash != hash {
   281  		return errDataHashMismatch
   282  	}
   283  	r.Data = data
   284  	return nil
   285  }
   286  
   287  const (
   288  	// helper trie type constants
   289  	htCanonical = iota // Canonical hash trie
   290  	htBloomBits        // BloomBits trie
   291  
   292  	// applicable for all helper trie requests
   293  	auxRoot = 1
   294  	// applicable for htCanonical
   295  	auxHeader = 2
   296  )
   297  
   298  type HelperTrieReq struct {
   299  	Type              uint
   300  	TrieIdx           uint64
   301  	Key               []byte
   302  	FromLevel, AuxReq uint
   303  }
   304  
   305  type HelperTrieResps struct { // describes all responses, not just a single one
   306  	Proofs  light.NodeList
   307  	AuxData [][]byte
   308  }
   309  
   310  // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
   311  type ChtRequest light.ChtRequest
   312  
   313  // GetCost returns the cost of the given ODR request according to the serving
   314  // peer's cost table (implementation of LesOdrRequest)
   315  func (r *ChtRequest) GetCost(peer *peer) uint64 {
   316  	return peer.GetRequestCost(GetHelperTrieProofsMsg, 1)
   317  }
   318  
   319  // CanSend tells if a certain peer is suitable for serving the given request
   320  func (r *ChtRequest) CanSend(peer *peer) bool {
   321  	peer.lock.RLock()
   322  	defer peer.lock.RUnlock()
   323  
   324  	return peer.headInfo.Number >= r.Config.ChtConfirms && r.ChtNum <= (peer.headInfo.Number-r.Config.ChtConfirms)/r.Config.ChtSize
   325  }
   326  
   327  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   328  func (r *ChtRequest) Request(reqID uint64, peer *peer) error {
   329  	peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.BlockNum)
   330  	var encNum [8]byte
   331  	binary.BigEndian.PutUint64(encNum[:], r.BlockNum)
   332  	req := HelperTrieReq{
   333  		Type:    htCanonical,
   334  		TrieIdx: r.ChtNum,
   335  		Key:     encNum[:],
   336  		AuxReq:  auxHeader,
   337  	}
   338  	return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req})
   339  }
   340  
   341  // Valid processes an ODR request reply message from the LES network
   342  // returns true and stores results in memory if the message was a valid reply
   343  // to the request (implementation of LesOdrRequest)
   344  func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
   345  	log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum)
   346  
   347  	if msg.MsgType != MsgHelperTrieProofs {
   348  		return errInvalidMessageType
   349  	}
   350  	resp := msg.Obj.(HelperTrieResps)
   351  	if len(resp.AuxData) != 1 {
   352  		return errInvalidEntryCount
   353  	}
   354  	nodeSet := resp.Proofs.NodeSet()
   355  	headerEnc := resp.AuxData[0]
   356  	if len(headerEnc) == 0 {
   357  		return errHeaderUnavailable
   358  	}
   359  	header := new(types.Header)
   360  	if err := rlp.DecodeBytes(headerEnc, header); err != nil {
   361  		return errHeaderUnavailable
   362  	}
   363  
   364  	// Verify the CHT
   365  	var encNumber [8]byte
   366  	binary.BigEndian.PutUint64(encNumber[:], r.BlockNum)
   367  
   368  	reads := &readTraceDB{db: nodeSet}
   369  	value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], reads)
   370  	if err != nil {
   371  		return fmt.Errorf("merkle proof verification failed: %v", err)
   372  	}
   373  	if len(reads.reads) != nodeSet.KeyCount() {
   374  		return errUselessNodes
   375  	}
   376  
   377  	var node light.ChtNode
   378  	if err := rlp.DecodeBytes(value, &node); err != nil {
   379  		return err
   380  	}
   381  	if node.Hash != header.Hash() {
   382  		return errCHTHashMismatch
   383  	}
   384  	if r.BlockNum != header.Number.Uint64() {
   385  		return errCHTNumberMismatch
   386  	}
   387  	// Verifications passed, store and return
   388  	r.Header = header
   389  	r.Proof = nodeSet
   390  	r.Td = node.Td
   391  	return nil
   392  }
   393  
   394  type BloomReq struct {
   395  	BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64
   396  }
   397  
   398  // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
   399  type BloomRequest light.BloomRequest
   400  
   401  // GetCost returns the cost of the given ODR request according to the serving
   402  // peer's cost table (implementation of LesOdrRequest)
   403  func (r *BloomRequest) GetCost(peer *peer) uint64 {
   404  	return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList))
   405  }
   406  
   407  // CanSend tells if a certain peer is suitable for serving the given request
   408  func (r *BloomRequest) CanSend(peer *peer) bool {
   409  	peer.lock.RLock()
   410  	defer peer.lock.RUnlock()
   411  
   412  	if peer.version < lpv2 {
   413  		return false
   414  	}
   415  	return peer.headInfo.Number >= r.Config.BloomTrieConfirms && r.BloomTrieNum <= (peer.headInfo.Number-r.Config.BloomTrieConfirms)/r.Config.BloomTrieSize
   416  }
   417  
   418  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   419  func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
   420  	peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
   421  	reqs := make([]HelperTrieReq, len(r.SectionIndexList))
   422  
   423  	var encNumber [10]byte
   424  	binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
   425  
   426  	for i, sectionIdx := range r.SectionIndexList {
   427  		binary.BigEndian.PutUint64(encNumber[2:], sectionIdx)
   428  		reqs[i] = HelperTrieReq{
   429  			Type:    htBloomBits,
   430  			TrieIdx: r.BloomTrieNum,
   431  			Key:     common.CopyBytes(encNumber[:]),
   432  		}
   433  	}
   434  	return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), reqs)
   435  }
   436  
   437  // Valid processes an ODR request reply message from the LES network
   438  // returns true and stores results in memory if the message was a valid reply
   439  // to the request (implementation of LesOdrRequest)
   440  func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
   441  	log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
   442  
   443  	// Ensure we have a correct message with a single proof element
   444  	if msg.MsgType != MsgHelperTrieProofs {
   445  		return errInvalidMessageType
   446  	}
   447  	resps := msg.Obj.(HelperTrieResps)
   448  	proofs := resps.Proofs
   449  	nodeSet := proofs.NodeSet()
   450  	reads := &readTraceDB{db: nodeSet}
   451  
   452  	r.BloomBits = make([][]byte, len(r.SectionIndexList))
   453  
   454  	// Verify the proofs
   455  	var encNumber [10]byte
   456  	binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
   457  
   458  	for i, idx := range r.SectionIndexList {
   459  		binary.BigEndian.PutUint64(encNumber[2:], idx)
   460  		value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads)
   461  		if err != nil {
   462  			return err
   463  		}
   464  		r.BloomBits[i] = value
   465  	}
   466  
   467  	if len(reads.reads) != nodeSet.KeyCount() {
   468  		return errUselessNodes
   469  	}
   470  	r.Proofs = nodeSet
   471  	return nil
   472  }
   473  
   474  // readTraceDB stores the keys of database reads. We use this to check that received node
   475  // sets contain only the trie nodes necessary to make proofs pass.
   476  type readTraceDB struct {
   477  	db    ethdb.Reader
   478  	reads map[string]struct{}
   479  }
   480  
   481  // Get returns a stored node
   482  func (db *readTraceDB) Get(k []byte) ([]byte, error) {
   483  	if db.reads == nil {
   484  		db.reads = make(map[string]struct{})
   485  	}
   486  	db.reads[string(k)] = struct{}{}
   487  	return db.db.Get(k)
   488  }
   489  
   490  // Has returns true if the node set contains the given key
   491  func (db *readTraceDB) Has(key []byte) (bool, error) {
   492  	_, err := db.Get(key)
   493  	return err == nil, nil
   494  }