github.com/daethereum/go-dae@v2.2.3+incompatible/trie/secure_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 trie
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/daethereum/go-dae/common"
    23  	"github.com/daethereum/go-dae/core/types"
    24  	"github.com/daethereum/go-dae/log"
    25  	"github.com/daethereum/go-dae/rlp"
    26  )
    27  
    28  // SecureTrie wraps a trie with key hashing. In a secure trie, all
    29  // access operations hash the key using keccak256. This prevents
    30  // calling code from creating long chains of nodes that
    31  // increase the access time.
    32  //
    33  // Contrary to a regular trie, a SecureTrie can only be created with
    34  // New and must have an attached database. The database also stores
    35  // the preimage of each key.
    36  //
    37  // SecureTrie is not safe for concurrent use.
    38  type SecureTrie struct {
    39  	trie             Trie
    40  	hashKeyBuf       [common.HashLength]byte
    41  	secKeyCache      map[string][]byte
    42  	secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch
    43  }
    44  
    45  // NewSecure creates a trie with an existing root node from a backing database
    46  // and optional intermediate in-memory node pool.
    47  //
    48  // If root is the zero hash or the sha3 hash of an empty string, the
    49  // trie is initially empty. Otherwise, New will panic if db is nil
    50  // and returns MissingNodeError if the root node cannot be found.
    51  //
    52  // Accessing the trie loads nodes from the database or node pool on demand.
    53  // Loaded nodes are kept around until their 'cache generation' expires.
    54  // A new cache generation is created by each call to Commit.
    55  // cachelimit sets the number of past cache generations to keep.
    56  func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, error) {
    57  	if db == nil {
    58  		panic("trie.NewSecure called without a database")
    59  	}
    60  	trie, err := New(owner, root, db)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	return &SecureTrie{trie: *trie}, nil
    65  }
    66  
    67  // Get returns the value for key stored in the trie.
    68  // The value bytes must not be modified by the caller.
    69  func (t *SecureTrie) Get(key []byte) []byte {
    70  	res, err := t.TryGet(key)
    71  	if err != nil {
    72  		log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
    73  	}
    74  	return res
    75  }
    76  
    77  // TryGet returns the value for key stored in the trie.
    78  // The value bytes must not be modified by the caller.
    79  // If a node was not found in the database, a MissingNodeError is returned.
    80  func (t *SecureTrie) TryGet(key []byte) ([]byte, error) {
    81  	return t.trie.TryGet(t.hashKey(key))
    82  }
    83  
    84  // TryGetNode attempts to retrieve a trie node by compact-encoded path. It is not
    85  // possible to use keybyte-encoding as the path might contain odd nibbles.
    86  func (t *SecureTrie) TryGetNode(path []byte) ([]byte, int, error) {
    87  	return t.trie.TryGetNode(path)
    88  }
    89  
    90  // TryUpdateAccount account will abstract the write of an account to the
    91  // secure trie.
    92  func (t *SecureTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error {
    93  	hk := t.hashKey(key)
    94  	data, err := rlp.EncodeToBytes(acc)
    95  	if err != nil {
    96  		return err
    97  	}
    98  	if err := t.trie.TryUpdate(hk, data); err != nil {
    99  		return err
   100  	}
   101  	t.getSecKeyCache()[string(hk)] = common.CopyBytes(key)
   102  	return nil
   103  }
   104  
   105  // Update associates key with value in the trie. Subsequent calls to
   106  // Get will return value. If value has length zero, any existing value
   107  // is deleted from the trie and calls to Get will return nil.
   108  //
   109  // The value bytes must not be modified by the caller while they are
   110  // stored in the trie.
   111  func (t *SecureTrie) Update(key, value []byte) {
   112  	if err := t.TryUpdate(key, value); err != nil {
   113  		log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
   114  	}
   115  }
   116  
   117  // TryUpdate associates key with value in the trie. Subsequent calls to
   118  // Get will return value. If value has length zero, any existing value
   119  // is deleted from the trie and calls to Get will return nil.
   120  //
   121  // The value bytes must not be modified by the caller while they are
   122  // stored in the trie.
   123  //
   124  // If a node was not found in the database, a MissingNodeError is returned.
   125  func (t *SecureTrie) TryUpdate(key, value []byte) error {
   126  	hk := t.hashKey(key)
   127  	err := t.trie.TryUpdate(hk, value)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	t.getSecKeyCache()[string(hk)] = common.CopyBytes(key)
   132  	return nil
   133  }
   134  
   135  // Delete removes any existing value for key from the trie.
   136  func (t *SecureTrie) Delete(key []byte) {
   137  	if err := t.TryDelete(key); err != nil {
   138  		log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
   139  	}
   140  }
   141  
   142  // TryDelete removes any existing value for key from the trie.
   143  // If a node was not found in the database, a MissingNodeError is returned.
   144  func (t *SecureTrie) TryDelete(key []byte) error {
   145  	hk := t.hashKey(key)
   146  	delete(t.getSecKeyCache(), string(hk))
   147  	return t.trie.TryDelete(hk)
   148  }
   149  
   150  // GetKey returns the sha3 preimage of a hashed key that was
   151  // previously used to store a value.
   152  func (t *SecureTrie) GetKey(shaKey []byte) []byte {
   153  	if key, ok := t.getSecKeyCache()[string(shaKey)]; ok {
   154  		return key
   155  	}
   156  	return t.trie.db.preimage(common.BytesToHash(shaKey))
   157  }
   158  
   159  // Commit writes all nodes and the secure hash pre-images to the trie's database.
   160  // Nodes are stored with their sha3 hash as the key.
   161  //
   162  // Committing flushes nodes from memory. Subsequent Get calls will load nodes
   163  // from the database.
   164  func (t *SecureTrie) Commit(onleaf LeafCallback) (common.Hash, int, error) {
   165  	// Write all the pre-images to the actual disk database
   166  	if len(t.getSecKeyCache()) > 0 {
   167  		if t.trie.db.preimages != nil { // Ugly direct check but avoids the below write lock
   168  			t.trie.db.lock.Lock()
   169  			for hk, key := range t.secKeyCache {
   170  				t.trie.db.insertPreimage(common.BytesToHash([]byte(hk)), key)
   171  			}
   172  			t.trie.db.lock.Unlock()
   173  		}
   174  		t.secKeyCache = make(map[string][]byte)
   175  	}
   176  	// Commit the trie to its intermediate node database
   177  	return t.trie.Commit(onleaf)
   178  }
   179  
   180  // Hash returns the root hash of SecureTrie. It does not write to the
   181  // database and can be used even if the trie doesn't have one.
   182  func (t *SecureTrie) Hash() common.Hash {
   183  	return t.trie.Hash()
   184  }
   185  
   186  // Copy returns a copy of SecureTrie.
   187  func (t *SecureTrie) Copy() *SecureTrie {
   188  	return &SecureTrie{
   189  		trie:        *t.trie.Copy(),
   190  		secKeyCache: t.secKeyCache,
   191  	}
   192  }
   193  
   194  // NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration
   195  // starts at the key after the given start key.
   196  func (t *SecureTrie) NodeIterator(start []byte) NodeIterator {
   197  	return t.trie.NodeIterator(start)
   198  }
   199  
   200  // hashKey returns the hash of key as an ephemeral buffer.
   201  // The caller must not hold onto the return value because it will become
   202  // invalid on the next call to hashKey or secKey.
   203  func (t *SecureTrie) hashKey(key []byte) []byte {
   204  	h := newHasher(false)
   205  	h.sha.Reset()
   206  	h.sha.Write(key)
   207  	h.sha.Read(t.hashKeyBuf[:])
   208  	returnHasherToPool(h)
   209  	return t.hashKeyBuf[:]
   210  }
   211  
   212  // getSecKeyCache returns the current secure key cache, creating a new one if
   213  // ownership changed (i.e. the current secure trie is a copy of another owning
   214  // the actual cache).
   215  func (t *SecureTrie) getSecKeyCache() map[string][]byte {
   216  	if t != t.secKeyCacheOwner {
   217  		t.secKeyCacheOwner = t
   218  		t.secKeyCache = make(map[string][]byte)
   219  	}
   220  	return t.secKeyCache
   221  }