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