github.com/alexdevranger/node-1.8.27@v0.0.0-20221128213301-aa5841e41d2d/les/odr_requests.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-dubxcoin library.
     3  //
     4  // The go-dubxcoin 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-dubxcoin 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-dubxcoin 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/alexdevranger/node-1.8.27/common"
    27  	"github.com/alexdevranger/node-1.8.27/core/rawdb"
    28  	"github.com/alexdevranger/node-1.8.27/core/types"
    29  	"github.com/alexdevranger/node-1.8.27/crypto"
    30  	"github.com/alexdevranger/node-1.8.27/ethdb"
    31  	"github.com/alexdevranger/node-1.8.27/light"
    32  	"github.com/alexdevranger/node-1.8.27/log"
    33  	"github.com/alexdevranger/node-1.8.27/rlp"
    34  	"github.com/alexdevranger/node-1.8.27/trie"
    35  )
    36  
    37  var (
    38  	errInvalidMessageType  = errors.New("invalid message type")
    39  	errInvalidEntryCount   = errors.New("invalid number of response entries")
    40  	errHeaderUnavailable   = errors.New("header unavailable")
    41  	errTxHashMismatch      = errors.New("transaction hash mismatch")
    42  	errUncleHashMismatch   = errors.New("uncle hash mismatch")
    43  	errReceiptHashMismatch = errors.New("receipt hash mismatch")
    44  	errDataHashMismatch    = errors.New("data hash mismatch")
    45  	errCHTHashMismatch     = errors.New("cht hash mismatch")
    46  	errCHTNumberMismatch   = errors.New("cht number mismatch")
    47  	errUselessNodes        = errors.New("useless nodes in merkle proof nodeset")
    48  )
    49  
    50  type LesOdrRequest interface {
    51  	GetCost(*peer) uint64
    52  	CanSend(*peer) bool
    53  	Request(uint64, *peer) error
    54  	Validate(ethdb.Database, *Msg) error
    55  }
    56  
    57  func LesRequest(req light.OdrRequest) LesOdrRequest {
    58  	switch r := req.(type) {
    59  	case *light.BlockRequest:
    60  		return (*BlockRequest)(r)
    61  	case *light.ReceiptsRequest:
    62  		return (*ReceiptsRequest)(r)
    63  	case *light.TrieRequest:
    64  		return (*TrieRequest)(r)
    65  	case *light.CodeRequest:
    66  		return (*CodeRequest)(r)
    67  	case *light.ChtRequest:
    68  		return (*ChtRequest)(r)
    69  	case *light.BloomRequest:
    70  		return (*BloomRequest)(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  	header := rawdb.ReadHeader(db, r.Hash, r.Number)
   170  	if header == nil {
   171  		return errHeaderUnavailable
   172  	}
   173  	if header.ReceiptHash != types.DeriveSha(receipt) {
   174  		return errReceiptHashMismatch
   175  	}
   176  	// Validations passed, store and return
   177  	r.Receipts = receipt
   178  	return nil
   179  }
   180  
   181  type ProofReq struct {
   182  	BHash       common.Hash
   183  	AccKey, Key []byte
   184  	FromLevel   uint
   185  }
   186  
   187  // ODR request type for state/storage trie entries, see LesOdrRequest interface
   188  type TrieRequest light.TrieRequest
   189  
   190  // GetCost returns the cost of the given ODR request according to the serving
   191  // peer's cost table (implementation of LesOdrRequest)
   192  func (r *TrieRequest) GetCost(peer *peer) uint64 {
   193  	switch peer.version {
   194  	case lpv1:
   195  		return peer.GetRequestCost(GetProofsV1Msg, 1)
   196  	case lpv2:
   197  		return peer.GetRequestCost(GetProofsV2Msg, 1)
   198  	default:
   199  		panic(nil)
   200  	}
   201  }
   202  
   203  // CanSend tells if a certain peer is suitable for serving the given request
   204  func (r *TrieRequest) CanSend(peer *peer) bool {
   205  	return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true)
   206  }
   207  
   208  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   209  func (r *TrieRequest) Request(reqID uint64, peer *peer) error {
   210  	peer.Log().Debug("Requesting trie proof", "root", r.Id.Root, "key", r.Key)
   211  	req := ProofReq{
   212  		BHash:  r.Id.BlockHash,
   213  		AccKey: r.Id.AccKey,
   214  		Key:    r.Key,
   215  	}
   216  	return peer.RequestProofs(reqID, r.GetCost(peer), []ProofReq{req})
   217  }
   218  
   219  // Valid processes an ODR request reply message from the LES network
   220  // returns true and stores results in memory if the message was a valid reply
   221  // to the request (implementation of LesOdrRequest)
   222  func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
   223  	log.Debug("Validating trie proof", "root", r.Id.Root, "key", r.Key)
   224  
   225  	switch msg.MsgType {
   226  	case MsgProofsV1:
   227  		proofs := msg.Obj.([]light.NodeList)
   228  		if len(proofs) != 1 {
   229  			return errInvalidEntryCount
   230  		}
   231  		nodeSet := proofs[0].NodeSet()
   232  		// Verify the proof and store if checks out
   233  		if _, _, err := trie.VerifyProof(r.Id.Root, r.Key, nodeSet); err != nil {
   234  			return fmt.Errorf("merkle proof verification failed: %v", err)
   235  		}
   236  		r.Proof = nodeSet
   237  		return nil
   238  
   239  	case MsgProofsV2:
   240  		proofs := msg.Obj.(light.NodeList)
   241  		// Verify the proof and store if checks out
   242  		nodeSet := proofs.NodeSet()
   243  		reads := &readTraceDB{db: nodeSet}
   244  		if _, _, err := trie.VerifyProof(r.Id.Root, r.Key, reads); err != nil {
   245  			return fmt.Errorf("merkle proof verification failed: %v", err)
   246  		}
   247  		// check if all nodes have been read by VerifyProof
   248  		if len(reads.reads) != nodeSet.KeyCount() {
   249  			return errUselessNodes
   250  		}
   251  		r.Proof = nodeSet
   252  		return nil
   253  
   254  	default:
   255  		return errInvalidMessageType
   256  	}
   257  }
   258  
   259  type CodeReq struct {
   260  	BHash  common.Hash
   261  	AccKey []byte
   262  }
   263  
   264  // ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface
   265  type CodeRequest light.CodeRequest
   266  
   267  // GetCost returns the cost of the given ODR request according to the serving
   268  // peer's cost table (implementation of LesOdrRequest)
   269  func (r *CodeRequest) GetCost(peer *peer) uint64 {
   270  	return peer.GetRequestCost(GetCodeMsg, 1)
   271  }
   272  
   273  // CanSend tells if a certain peer is suitable for serving the given request
   274  func (r *CodeRequest) CanSend(peer *peer) bool {
   275  	return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true)
   276  }
   277  
   278  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   279  func (r *CodeRequest) Request(reqID uint64, peer *peer) error {
   280  	peer.Log().Debug("Requesting code data", "hash", r.Hash)
   281  	req := CodeReq{
   282  		BHash:  r.Id.BlockHash,
   283  		AccKey: r.Id.AccKey,
   284  	}
   285  	return peer.RequestCode(reqID, r.GetCost(peer), []CodeReq{req})
   286  }
   287  
   288  // Valid processes an ODR request reply message from the LES network
   289  // returns true and stores results in memory if the message was a valid reply
   290  // to the request (implementation of LesOdrRequest)
   291  func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error {
   292  	log.Debug("Validating code data", "hash", r.Hash)
   293  
   294  	// Ensure we have a correct message with a single code element
   295  	if msg.MsgType != MsgCode {
   296  		return errInvalidMessageType
   297  	}
   298  	reply := msg.Obj.([][]byte)
   299  	if len(reply) != 1 {
   300  		return errInvalidEntryCount
   301  	}
   302  	data := reply[0]
   303  
   304  	// Verify the data and store if checks out
   305  	if hash := crypto.Keccak256Hash(data); r.Hash != hash {
   306  		return errDataHashMismatch
   307  	}
   308  	r.Data = data
   309  	return nil
   310  }
   311  
   312  const (
   313  	// helper trie type constants
   314  	htCanonical = iota // Canonical hash trie
   315  	htBloomBits        // BloomBits trie
   316  
   317  	// applicable for all helper trie requests
   318  	auxRoot = 1
   319  	// applicable for htCanonical
   320  	auxHeader = 2
   321  )
   322  
   323  type HelperTrieReq struct {
   324  	Type              uint
   325  	TrieIdx           uint64
   326  	Key               []byte
   327  	FromLevel, AuxReq uint
   328  }
   329  
   330  type HelperTrieResps struct { // describes all responses, not just a single one
   331  	Proofs  light.NodeList
   332  	AuxData [][]byte
   333  }
   334  
   335  // legacy LES/1
   336  type ChtReq struct {
   337  	ChtNum, BlockNum uint64
   338  	FromLevel        uint
   339  }
   340  
   341  // legacy LES/1
   342  type ChtResp struct {
   343  	Header *types.Header
   344  	Proof  []rlp.RawValue
   345  }
   346  
   347  // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
   348  type ChtRequest light.ChtRequest
   349  
   350  // GetCost returns the cost of the given ODR request according to the serving
   351  // peer's cost table (implementation of LesOdrRequest)
   352  func (r *ChtRequest) GetCost(peer *peer) uint64 {
   353  	switch peer.version {
   354  	case lpv1:
   355  		return peer.GetRequestCost(GetHeaderProofsMsg, 1)
   356  	case lpv2:
   357  		return peer.GetRequestCost(GetHelperTrieProofsMsg, 1)
   358  	default:
   359  		panic(nil)
   360  	}
   361  }
   362  
   363  // CanSend tells if a certain peer is suitable for serving the given request
   364  func (r *ChtRequest) CanSend(peer *peer) bool {
   365  	peer.lock.RLock()
   366  	defer peer.lock.RUnlock()
   367  
   368  	return peer.headInfo.Number >= r.Config.ChtConfirms && r.ChtNum <= (peer.headInfo.Number-r.Config.ChtConfirms)/r.Config.ChtSize
   369  }
   370  
   371  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   372  func (r *ChtRequest) Request(reqID uint64, peer *peer) error {
   373  	peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.BlockNum)
   374  	var encNum [8]byte
   375  	binary.BigEndian.PutUint64(encNum[:], r.BlockNum)
   376  	req := HelperTrieReq{
   377  		Type:    htCanonical,
   378  		TrieIdx: r.ChtNum,
   379  		Key:     encNum[:],
   380  		AuxReq:  auxHeader,
   381  	}
   382  	switch peer.version {
   383  	case lpv1:
   384  		var reqsV1 ChtReq
   385  		if req.Type != htCanonical || req.AuxReq != auxHeader || len(req.Key) != 8 {
   386  			return fmt.Errorf("Request invalid in LES/1 mode")
   387  		}
   388  		blockNum := binary.BigEndian.Uint64(req.Key)
   389  		// convert HelperTrie request to old CHT request
   390  		reqsV1 = ChtReq{ChtNum: (req.TrieIdx + 1) * (r.Config.ChtSize / r.Config.PairChtSize), BlockNum: blockNum, FromLevel: req.FromLevel}
   391  		return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []ChtReq{reqsV1})
   392  	case lpv2:
   393  		return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req})
   394  	default:
   395  		panic(nil)
   396  	}
   397  }
   398  
   399  // Valid processes an ODR request reply message from the LES network
   400  // returns true and stores results in memory if the message was a valid reply
   401  // to the request (implementation of LesOdrRequest)
   402  func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
   403  	log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum)
   404  
   405  	switch msg.MsgType {
   406  	case MsgHeaderProofs: // LES/1 backwards compatibility
   407  		proofs := msg.Obj.([]ChtResp)
   408  		if len(proofs) != 1 {
   409  			return errInvalidEntryCount
   410  		}
   411  		proof := proofs[0]
   412  
   413  		// Verify the CHT
   414  		var encNumber [8]byte
   415  		binary.BigEndian.PutUint64(encNumber[:], r.BlockNum)
   416  
   417  		value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], light.NodeList(proof.Proof).NodeSet())
   418  		if err != nil {
   419  			return err
   420  		}
   421  		var node light.ChtNode
   422  		if err := rlp.DecodeBytes(value, &node); err != nil {
   423  			return err
   424  		}
   425  		if node.Hash != proof.Header.Hash() {
   426  			return errCHTHashMismatch
   427  		}
   428  		// Verifications passed, store and return
   429  		r.Header = proof.Header
   430  		r.Proof = light.NodeList(proof.Proof).NodeSet()
   431  		r.Td = node.Td
   432  	case MsgHelperTrieProofs:
   433  		resp := msg.Obj.(HelperTrieResps)
   434  		if len(resp.AuxData) != 1 {
   435  			return errInvalidEntryCount
   436  		}
   437  		nodeSet := resp.Proofs.NodeSet()
   438  		headerEnc := resp.AuxData[0]
   439  		if len(headerEnc) == 0 {
   440  			return errHeaderUnavailable
   441  		}
   442  		header := new(types.Header)
   443  		if err := rlp.DecodeBytes(headerEnc, header); err != nil {
   444  			return errHeaderUnavailable
   445  		}
   446  
   447  		// Verify the CHT
   448  		var encNumber [8]byte
   449  		binary.BigEndian.PutUint64(encNumber[:], r.BlockNum)
   450  
   451  		reads := &readTraceDB{db: nodeSet}
   452  		value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], reads)
   453  		if err != nil {
   454  			return fmt.Errorf("merkle proof verification failed: %v", err)
   455  		}
   456  		if len(reads.reads) != nodeSet.KeyCount() {
   457  			return errUselessNodes
   458  		}
   459  
   460  		var node light.ChtNode
   461  		if err := rlp.DecodeBytes(value, &node); err != nil {
   462  			return err
   463  		}
   464  		if node.Hash != header.Hash() {
   465  			return errCHTHashMismatch
   466  		}
   467  		if r.BlockNum != header.Number.Uint64() {
   468  			return errCHTNumberMismatch
   469  		}
   470  		// Verifications passed, store and return
   471  		r.Header = header
   472  		r.Proof = nodeSet
   473  		r.Td = node.Td
   474  	default:
   475  		return errInvalidMessageType
   476  	}
   477  	return nil
   478  }
   479  
   480  type BloomReq struct {
   481  	BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64
   482  }
   483  
   484  // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
   485  type BloomRequest light.BloomRequest
   486  
   487  // GetCost returns the cost of the given ODR request according to the serving
   488  // peer's cost table (implementation of LesOdrRequest)
   489  func (r *BloomRequest) GetCost(peer *peer) uint64 {
   490  	return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList))
   491  }
   492  
   493  // CanSend tells if a certain peer is suitable for serving the given request
   494  func (r *BloomRequest) CanSend(peer *peer) bool {
   495  	peer.lock.RLock()
   496  	defer peer.lock.RUnlock()
   497  
   498  	if peer.version < lpv2 {
   499  		return false
   500  	}
   501  	return peer.headInfo.Number >= r.Config.BloomTrieConfirms && r.BloomTrieNum <= (peer.headInfo.Number-r.Config.BloomTrieConfirms)/r.Config.BloomTrieSize
   502  }
   503  
   504  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   505  func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
   506  	peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
   507  	reqs := make([]HelperTrieReq, len(r.SectionIndexList))
   508  
   509  	var encNumber [10]byte
   510  	binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
   511  
   512  	for i, sectionIdx := range r.SectionIndexList {
   513  		binary.BigEndian.PutUint64(encNumber[2:], sectionIdx)
   514  		reqs[i] = HelperTrieReq{
   515  			Type:    htBloomBits,
   516  			TrieIdx: r.BloomTrieNum,
   517  			Key:     common.CopyBytes(encNumber[:]),
   518  		}
   519  	}
   520  	return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), reqs)
   521  }
   522  
   523  // Valid processes an ODR request reply message from the LES network
   524  // returns true and stores results in memory if the message was a valid reply
   525  // to the request (implementation of LesOdrRequest)
   526  func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
   527  	log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
   528  
   529  	// Ensure we have a correct message with a single proof element
   530  	if msg.MsgType != MsgHelperTrieProofs {
   531  		return errInvalidMessageType
   532  	}
   533  	resps := msg.Obj.(HelperTrieResps)
   534  	proofs := resps.Proofs
   535  	nodeSet := proofs.NodeSet()
   536  	reads := &readTraceDB{db: nodeSet}
   537  
   538  	r.BloomBits = make([][]byte, len(r.SectionIndexList))
   539  
   540  	// Verify the proofs
   541  	var encNumber [10]byte
   542  	binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
   543  
   544  	for i, idx := range r.SectionIndexList {
   545  		binary.BigEndian.PutUint64(encNumber[2:], idx)
   546  		value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads)
   547  		if err != nil {
   548  			return err
   549  		}
   550  		r.BloomBits[i] = value
   551  	}
   552  
   553  	if len(reads.reads) != nodeSet.KeyCount() {
   554  		return errUselessNodes
   555  	}
   556  	r.Proofs = nodeSet
   557  	return nil
   558  }
   559  
   560  // readTraceDB stores the keys of database reads. We use this to check that received node
   561  // sets contain only the trie nodes necessary to make proofs pass.
   562  type readTraceDB struct {
   563  	db    trie.DatabaseReader
   564  	reads map[string]struct{}
   565  }
   566  
   567  // Get returns a stored node
   568  func (db *readTraceDB) Get(k []byte) ([]byte, error) {
   569  	if db.reads == nil {
   570  		db.reads = make(map[string]struct{})
   571  	}
   572  	db.reads[string(k)] = struct{}{}
   573  	return db.db.Get(k)
   574  }
   575  
   576  // Has returns true if the node set contains the given key
   577  func (db *readTraceDB) Has(key []byte) (bool, error) {
   578  	_, err := db.Get(key)
   579  	return err == nil, nil
   580  }