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