github.com/devfans/go-ethereum@v1.5.10-0.20170326212234-7419d0c38291/light/trie.go (about)

     1  // Copyright 2015 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
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/ethereum/go-ethereum/ethdb"
    23  	"github.com/ethereum/go-ethereum/trie"
    24  )
    25  
    26  // LightTrie is an ODR-capable wrapper around trie.SecureTrie
    27  type LightTrie struct {
    28  	trie *trie.SecureTrie
    29  	id   *TrieID
    30  	odr  OdrBackend
    31  	db   ethdb.Database
    32  }
    33  
    34  // NewLightTrie creates a new LightTrie instance. It doesn't instantly try to
    35  // access the db or network and retrieve the root node, it only initializes its
    36  // encapsulated SecureTrie at the first actual operation.
    37  func NewLightTrie(id *TrieID, odr OdrBackend, useFakeMap bool) *LightTrie {
    38  	return &LightTrie{
    39  		// SecureTrie is initialized before first request
    40  		id:  id,
    41  		odr: odr,
    42  		db:  odr.Database(),
    43  	}
    44  }
    45  
    46  // retrieveKey retrieves a single key, returns true and stores nodes in local
    47  // database if successful
    48  func (t *LightTrie) retrieveKey(ctx context.Context, key []byte) bool {
    49  	r := &TrieRequest{Id: t.id, Key: key}
    50  	return t.odr.Retrieve(ctx, r) == nil
    51  }
    52  
    53  // do tries and retries to execute a function until it returns with no error or
    54  // an error type other than MissingNodeError
    55  func (t *LightTrie) do(ctx context.Context, fallbackKey []byte, fn func() error) error {
    56  	err := fn()
    57  	for err != nil {
    58  		mn, ok := err.(*trie.MissingNodeError)
    59  		if !ok {
    60  			return err
    61  		}
    62  
    63  		var key []byte
    64  		if mn.PrefixLen+mn.SuffixLen > 0 {
    65  			key = mn.Key
    66  		} else {
    67  			key = fallbackKey
    68  		}
    69  		if !t.retrieveKey(ctx, key) {
    70  			break
    71  		}
    72  		err = fn()
    73  	}
    74  	return err
    75  }
    76  
    77  // Get returns the value for key stored in the trie.
    78  // The value bytes must not be modified by the caller.
    79  func (t *LightTrie) Get(ctx context.Context, key []byte) (res []byte, err error) {
    80  	err = t.do(ctx, key, func() (err error) {
    81  		if t.trie == nil {
    82  			t.trie, err = trie.NewSecure(t.id.Root, t.db, 0)
    83  		}
    84  		if err == nil {
    85  			res, err = t.trie.TryGet(key)
    86  		}
    87  		return
    88  	})
    89  	return
    90  }
    91  
    92  // Update associates key with value in the trie. Subsequent calls to
    93  // Get will return value. If value has length zero, any existing value
    94  // is deleted from the trie and calls to Get will return nil.
    95  //
    96  // The value bytes must not be modified by the caller while they are
    97  // stored in the trie.
    98  func (t *LightTrie) Update(ctx context.Context, key, value []byte) (err error) {
    99  	err = t.do(ctx, key, func() (err error) {
   100  		if t.trie == nil {
   101  			t.trie, err = trie.NewSecure(t.id.Root, t.db, 0)
   102  		}
   103  		if err == nil {
   104  			err = t.trie.TryUpdate(key, value)
   105  		}
   106  		return
   107  	})
   108  	return
   109  }
   110  
   111  // Delete removes any existing value for key from the trie.
   112  func (t *LightTrie) Delete(ctx context.Context, key []byte) (err error) {
   113  	err = t.do(ctx, key, func() (err error) {
   114  		if t.trie == nil {
   115  			t.trie, err = trie.NewSecure(t.id.Root, t.db, 0)
   116  		}
   117  		if err == nil {
   118  			err = t.trie.TryDelete(key)
   119  		}
   120  		return
   121  	})
   122  	return
   123  }