github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/les/odr_requests.go (about)

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