github.com/r8d8/go-ethereum@v5.5.2+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 "github.com/ethereumproject/go-ethereum/common" 22 "github.com/ethereumproject/go-ethereum/logger/glog" 23 ) 24 25 var secureKeyPrefix = []byte("secure-key-") 26 27 const secureKeyLength = 11 + 32 // Length of the above prefix + 32byte hash 28 29 // SecureTrie wraps a trie with key hashing. In a secure trie, all 30 // access operations hash the key using keccak256. This prevents 31 // calling code from creating long chains of nodes that 32 // increase the access time. 33 // 34 // Contrary to a regular trie, a SecureTrie can only be created with 35 // New and must have an attached database. The database also stores 36 // the preimage of each key. 37 // 38 // SecureTrie is not safe for concurrent use. 39 type SecureTrie struct { 40 trie Trie 41 hashKeyBuf [secureKeyLength]byte 42 secKeyBuf [200]byte 43 secKeyCache map[string][]byte 44 secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch 45 } 46 47 // NewSecure creates a trie with an existing root node from db. 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 db 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(root common.Hash, db Database, cachelimit uint16) (*SecureTrie, error) { 58 if db == nil { 59 panic("NewSecure called with nil database") 60 } 61 trie, err := New(root, db) 62 if err != nil { 63 return nil, err 64 } 65 trie.SetCacheLimit(cachelimit) 66 return &SecureTrie{trie: *trie}, nil 67 } 68 69 // Get returns the value for key stored in the trie. 70 // The value bytes must not be modified by the caller. 71 func (t *SecureTrie) Get(key []byte) []byte { 72 res, err := t.TryGet(key) 73 if err != nil { 74 glog.Errorln(fmt.Sprintf("Unhandled trie error: %v", err)) 75 } 76 return res 77 } 78 79 // TryGet returns the value for key stored in the trie. 80 // The value bytes must not be modified by the caller. 81 // If a node was not found in the database, a MissingNodeError is returned. 82 func (t *SecureTrie) TryGet(key []byte) ([]byte, error) { 83 return t.trie.TryGet(t.hashKey(key)) 84 } 85 86 // Update associates key with value in the trie. Subsequent calls to 87 // Get will return value. If value has length zero, any existing value 88 // is deleted from the trie and calls to Get will return nil. 89 // 90 // The value bytes must not be modified by the caller while they are 91 // stored in the trie. 92 func (t *SecureTrie) Update(key, value []byte) { 93 if err := t.TryUpdate(key, value); err != nil { 94 glog.Errorln(fmt.Sprintf("Unhandled trie error: %v", err)) 95 } 96 } 97 98 // TryUpdate associates key with value in the trie. Subsequent calls to 99 // Get will return value. If value has length zero, any existing value 100 // is deleted from the trie and calls to Get will return nil. 101 // 102 // The value bytes must not be modified by the caller while they are 103 // stored in the trie. 104 // 105 // If a node was not found in the database, a MissingNodeError is returned. 106 func (t *SecureTrie) TryUpdate(key, value []byte) error { 107 hk := t.hashKey(key) 108 err := t.trie.TryUpdate(hk, value) 109 if err != nil { 110 return err 111 } 112 t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) 113 return nil 114 } 115 116 // Delete removes any existing value for key from the trie. 117 func (t *SecureTrie) Delete(key []byte) { 118 if err := t.TryDelete(key); err != nil { 119 glog.Errorln(fmt.Sprintf("Unhandled trie error: %v", err)) 120 } 121 } 122 123 // TryDelete removes any existing value for key from the trie. 124 // If a node was not found in the database, a MissingNodeError is returned. 125 func (t *SecureTrie) TryDelete(key []byte) error { 126 hk := t.hashKey(key) 127 delete(t.getSecKeyCache(), string(hk)) 128 return t.trie.TryDelete(hk) 129 } 130 131 // GetKey returns the sha3 preimage of a hashed key that was 132 // previously used to store a value. 133 func (t *SecureTrie) GetKey(shaKey []byte) []byte { 134 if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { 135 return key 136 } 137 key, _ := t.trie.db.Get(t.secKey(shaKey)) 138 return key 139 } 140 141 // Commit writes all nodes and the secure hash pre-images to the trie's database. 142 // Nodes are stored with their sha3 hash as the key. 143 // 144 // Committing flushes nodes from memory. Subsequent Get calls will load nodes 145 // from the database. 146 func (t *SecureTrie) Commit() (root common.Hash, err error) { 147 return t.CommitTo(t.trie.db) 148 } 149 150 func (t *SecureTrie) Hash() common.Hash { 151 return t.trie.Hash() 152 } 153 154 func (t *SecureTrie) Root() []byte { 155 return t.trie.Root() 156 } 157 158 func (t *SecureTrie) Copy() *SecureTrie { 159 cpy := *t 160 return &cpy 161 } 162 163 // NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration 164 // starts at the key after the given start key. 165 func (t *SecureTrie) NodeIterator(start []byte) NodeIterator { 166 return t.trie.NodeIterator(start) 167 } 168 169 // CommitTo writes all nodes and the secure hash pre-images to the given database. 170 // Nodes are stored with their sha3 hash as the key. 171 // 172 // Committing flushes nodes from memory. Subsequent Get calls will load nodes from 173 // the trie's database. Calling code must ensure that the changes made to db are 174 // written back to the trie's attached database before using the trie. 175 func (t *SecureTrie) CommitTo(db DatabaseWriter) (root common.Hash, err error) { 176 if len(t.getSecKeyCache()) > 0 { 177 for hk, key := range t.secKeyCache { 178 if err := db.Put(t.secKey([]byte(hk)), key); err != nil { 179 return common.Hash{}, err 180 } 181 } 182 t.secKeyCache = make(map[string][]byte) 183 } 184 return t.trie.CommitTo(db) 185 } 186 187 // secKey returns the database key for the preimage of key, as an ephemeral buffer. 188 // The caller must not hold onto the return value because it will become 189 // invalid on the next call to hashKey or secKey. 190 func (t *SecureTrie) secKey(key []byte) []byte { 191 buf := append(t.secKeyBuf[:0], secureKeyPrefix...) 192 buf = append(buf, key...) 193 return buf 194 } 195 196 // hashKey returns the hash of key as an ephemeral buffer. 197 // The caller must not hold onto the return value because it will become 198 // invalid on the next call to hashKey or secKey. 199 func (t *SecureTrie) hashKey(key []byte) []byte { 200 h := newHasher(0, 0) 201 calculator := h.newCalculator() 202 calculator.sha.Write(key) 203 buf := calculator.sha.Sum(t.hashKeyBuf[:0]) 204 h.returnCalculator(calculator) 205 return buf 206 } 207 208 // getSecKeyCache returns the current secure key cache, creating a new one if 209 // ownership changed (i.e. the current secure trie is a copy of another owning 210 // the actual cache). 211 func (t *SecureTrie) getSecKeyCache() map[string][]byte { 212 if t != t.secKeyCacheOwner { 213 t.secKeyCacheOwner = t 214 t.secKeyCache = make(map[string][]byte) 215 } 216 return t.secKeyCache 217 }