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