github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/light/trie.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package light 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/SmartMeshFoundation/Spectrum/common" 24 "github.com/SmartMeshFoundation/Spectrum/core/state" 25 "github.com/SmartMeshFoundation/Spectrum/core/types" 26 "github.com/SmartMeshFoundation/Spectrum/crypto" 27 "github.com/SmartMeshFoundation/Spectrum/trie" 28 ) 29 30 func NewState(ctx context.Context, head *types.Header, odr OdrBackend) *state.StateDB { 31 state, _ := state.New(head.Root, NewStateDatabase(ctx, head, odr)) 32 return state 33 } 34 35 func NewStateDatabase(ctx context.Context, head *types.Header, odr OdrBackend) state.Database { 36 return &odrDatabase{ctx, StateTrieID(head), odr} 37 } 38 39 type odrDatabase struct { 40 ctx context.Context 41 id *TrieID 42 backend OdrBackend 43 } 44 45 func (db *odrDatabase) OpenTrie(root common.Hash) (state.Trie, error) { 46 return &odrTrie{db: db, id: db.id}, nil 47 } 48 49 func (db *odrDatabase) OpenStorageTrie(addrHash, root common.Hash) (state.Trie, error) { 50 return &odrTrie{db: db, id: StorageTrieID(db.id, addrHash, root)}, nil 51 } 52 53 func (db *odrDatabase) CopyTrie(t state.Trie) state.Trie { 54 switch t := t.(type) { 55 case *odrTrie: 56 cpy := &odrTrie{db: t.db, id: t.id} 57 if t.trie != nil { 58 cpytrie := *t.trie 59 cpy.trie = &cpytrie 60 } 61 return cpy 62 default: 63 panic(fmt.Errorf("unknown trie type %T", t)) 64 } 65 } 66 67 func (db *odrDatabase) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { 68 if codeHash == sha3_nil { 69 return nil, nil 70 } 71 if code, err := db.backend.Database().Get(codeHash[:]); err == nil { 72 return code, nil 73 } 74 id := *db.id 75 id.AccKey = addrHash[:] 76 req := &CodeRequest{Id: &id, Hash: codeHash} 77 err := db.backend.Retrieve(db.ctx, req) 78 return req.Data, err 79 } 80 81 func (db *odrDatabase) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) { 82 code, err := db.ContractCode(addrHash, codeHash) 83 return len(code), err 84 } 85 86 type odrTrie struct { 87 db *odrDatabase 88 id *TrieID 89 trie *trie.Trie 90 } 91 92 func (t *odrTrie) TryGet(key []byte) ([]byte, error) { 93 key = crypto.Keccak256(key) 94 var res []byte 95 err := t.do(key, func() (err error) { 96 res, err = t.trie.TryGet(key) 97 return err 98 }) 99 return res, err 100 } 101 102 func (t *odrTrie) TryUpdate(key, value []byte) error { 103 key = crypto.Keccak256(key) 104 return t.do(key, func() error { 105 return t.trie.TryDelete(key) 106 }) 107 } 108 109 func (t *odrTrie) TryDelete(key []byte) error { 110 key = crypto.Keccak256(key) 111 return t.do(key, func() error { 112 return t.trie.TryDelete(key) 113 }) 114 } 115 116 func (t *odrTrie) CommitTo(db trie.DatabaseWriter) (common.Hash, error) { 117 if t.trie == nil { 118 return t.id.Root, nil 119 } 120 return t.trie.CommitTo(db) 121 } 122 123 func (t *odrTrie) Hash() common.Hash { 124 if t.trie == nil { 125 return t.id.Root 126 } 127 return t.trie.Hash() 128 } 129 130 func (t *odrTrie) NodeIterator(startkey []byte) trie.NodeIterator { 131 return newNodeIterator(t, startkey) 132 } 133 134 func (t *odrTrie) GetKey(sha []byte) []byte { 135 return nil 136 } 137 138 // do tries and retries to execute a function until it returns with no error or 139 // an error type other than MissingNodeError 140 func (t *odrTrie) do(key []byte, fn func() error) error { 141 for { 142 var err error 143 if t.trie == nil { 144 t.trie, err = trie.New(t.id.Root, t.db.backend.Database()) 145 } 146 if err == nil { 147 err = fn() 148 } 149 if _, ok := err.(*trie.MissingNodeError); !ok { 150 return err 151 } 152 r := &TrieRequest{Id: t.id, Key: key} 153 if err := t.db.backend.Retrieve(t.db.ctx, r); err != nil { 154 return err 155 } 156 } 157 } 158 159 type nodeIterator struct { 160 trie.NodeIterator 161 t *odrTrie 162 err error 163 } 164 165 func newNodeIterator(t *odrTrie, startkey []byte) trie.NodeIterator { 166 it := &nodeIterator{t: t} 167 // Open the actual non-ODR trie if that hasn't happened yet. 168 if t.trie == nil { 169 it.do(func() error { 170 t, err := trie.New(t.id.Root, t.db.backend.Database()) 171 if err == nil { 172 it.t.trie = t 173 } 174 return err 175 }) 176 } 177 it.do(func() error { 178 it.NodeIterator = it.t.trie.NodeIterator(startkey) 179 return it.NodeIterator.Error() 180 }) 181 return it 182 } 183 184 func (it *nodeIterator) Next(descend bool) bool { 185 var ok bool 186 it.do(func() error { 187 ok = it.NodeIterator.Next(descend) 188 return it.NodeIterator.Error() 189 }) 190 return ok 191 } 192 193 // do runs fn and attempts to fill in missing nodes by retrieving. 194 func (it *nodeIterator) do(fn func() error) { 195 var lasthash common.Hash 196 for { 197 it.err = fn() 198 missing, ok := it.err.(*trie.MissingNodeError) 199 if !ok { 200 return 201 } 202 if missing.NodeHash == lasthash { 203 it.err = fmt.Errorf("retrieve loop for trie node %x", missing.NodeHash) 204 return 205 } 206 lasthash = missing.NodeHash 207 r := &TrieRequest{Id: it.t.id, Key: nibblesToKey(missing.Path)} 208 if it.err = it.t.db.backend.Retrieve(it.t.db.ctx, r); it.err != nil { 209 return 210 } 211 } 212 } 213 214 func (it *nodeIterator) Error() error { 215 if it.err != nil { 216 return it.err 217 } 218 return it.NodeIterator.Error() 219 } 220 221 func nibblesToKey(nib []byte) []byte { 222 if len(nib) > 0 && nib[len(nib)-1] == 0x10 { 223 nib = nib[:len(nib)-1] // drop terminator 224 } 225 if len(nib)&1 == 1 { 226 nib = append(nib, 0) // make even 227 } 228 key := make([]byte, len(nib)/2) 229 for bi, ni := 0, 0; ni < len(nib); bi, ni = bi+1, ni+2 { 230 key[bi] = nib[ni]<<4 | nib[ni+1] 231 } 232 return key 233 }