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