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