github.com/annchain/OG@v0.0.9/trie/sync.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 "errors" 21 "fmt" 22 "github.com/annchain/OG/arefactor/og/types" 23 "github.com/annchain/OG/ogdb" 24 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 25 ) 26 27 // ErrNotRequested is returned by the trie sync when it's requested to process a 28 // node it did not request. 29 var ErrNotRequested = errors.New("not requested") 30 31 // ErrAlreadyProcessed is returned by the trie sync when it's requested to process a 32 // node it already processed previously. 33 var ErrAlreadyProcessed = errors.New("already processed") 34 35 // request represents a scheduled or already in-flight state retrieval request. 36 type request struct { 37 hash types.Hash // Hash of the node data content to retrieve 38 data []byte // Data content of the node, cached until all subtrees complete 39 raw bool // Whether this is a raw entry (code) or a trie node 40 41 parents []*request // Parent state nodes referencing this entry (notify all upon completion) 42 depth int // Depth level within the trie the node is located to prioritise DFS 43 deps int // Number of dependencies before allowed to commit this node 44 45 callback LeafCallback // Callback to invoke if a leaf node it reached on this branch 46 } 47 48 // SyncResult is a simple list to return missing nodes along with their request 49 // hashes. 50 type SyncResult struct { 51 Hash types.Hash // Hash of the originally unknown trie node 52 Data []byte // Data content of the retrieved node 53 } 54 55 // syncMemBatch is an in-memory buffer of successfully downloaded but not yet 56 // persisted data items. 57 type syncMemBatch struct { 58 batch map[types.Hash][]byte // In-memory membatch of recently completed items 59 order types.Hashes // Order of completion to prevent out-of-order data loss 60 } 61 62 // newSyncMemBatch allocates a new memory-buffer for not-yet persisted trie nodes. 63 func newSyncMemBatch() *syncMemBatch { 64 return &syncMemBatch{ 65 batch: make(map[types.Hash][]byte), 66 order: make(types.Hashes, 0, 256), 67 } 68 } 69 70 // Sync is the main state trie synchronisation scheduler, which provides yet 71 // unknown trie hashes to retrieve, accepts node data associated with said hashes 72 // and reconstructs the trie step by step until all is done. 73 type Sync struct { 74 database DatabaseReader // Persistent database to check for existing entries 75 membatch *syncMemBatch // Memory buffer to avoid frequest database writes 76 requests map[types.Hash]*request // Pending requests pertaining to a key hash 77 queue *prque.Prque // Priority queue with the pending requests 78 } 79 80 // NewSync creates a new trie data download scheduler. 81 func NewSync(root types.Hash, database DatabaseReader, callback LeafCallback) *Sync { 82 ts := &Sync{ 83 database: database, 84 membatch: newSyncMemBatch(), 85 requests: make(map[types.Hash]*request), 86 queue: prque.New(), 87 } 88 ts.AddSubTrie(root, 0, types.Hash{}, callback) 89 return ts 90 } 91 92 // AddSubTrie registers a new trie to the sync code, rooted at the designated parent. 93 func (s *Sync) AddSubTrie(root types.Hash, depth int, parent types.Hash, callback LeafCallback) { 94 // Short circuit if the trie is empty or already known 95 if root == emptyRoot { 96 return 97 } 98 if _, ok := s.membatch.batch[root]; ok { 99 return 100 } 101 key := root.ToBytes() 102 blob, _ := s.database.Get(key) 103 if local, err := decodeNode(key, blob, 0); local != nil && err == nil { 104 return 105 } 106 // Assemble the new sub-trie sync request 107 req := &request{ 108 hash: root, 109 depth: depth, 110 callback: callback, 111 } 112 // If this sub-trie has a designated parent, link them together 113 if parent != (types.Hash{}) { 114 ancestor := s.requests[parent] 115 if ancestor == nil { 116 panic(fmt.Sprintf("sub-trie ancestor not found: %x", parent)) 117 } 118 ancestor.deps++ 119 req.parents = append(req.parents, ancestor) 120 } 121 s.schedule(req) 122 } 123 124 // AddRawEntry schedules the direct retrieval of a state entry that should not be 125 // interpreted as a trie node, but rather accepted and stored into the database 126 // as is. This method's goal is to support misc state metadata retrievals (e.g. 127 // contract code). 128 func (s *Sync) AddRawEntry(hash types.Hash, depth int, parent types.Hash) { 129 // Short circuit if the entry is empty or already known 130 if hash == emptyState { 131 return 132 } 133 if _, ok := s.membatch.batch[hash]; ok { 134 return 135 } 136 if ok, _ := s.database.Has(hash.ToBytes()); ok { 137 return 138 } 139 // Assemble the new sub-trie sync request 140 req := &request{ 141 hash: hash, 142 raw: true, 143 depth: depth, 144 } 145 // If this sub-trie has a designated parent, link them together 146 if parent != (types.Hash{}) { 147 ancestor := s.requests[parent] 148 if ancestor == nil { 149 panic(fmt.Sprintf("raw-entry ancestor not found: %x", parent)) 150 } 151 ancestor.deps++ 152 req.parents = append(req.parents, ancestor) 153 } 154 s.schedule(req) 155 } 156 157 // Missing retrieves the known missing nodes from the trie for retrieval. 158 func (s *Sync) Missing(max int) types.Hashes { 159 requests := types.Hashes{} 160 for !s.queue.Empty() && (max == 0 || len(requests) < max) { 161 requests = append(requests, s.queue.PopItem().(types.Hash)) 162 } 163 return requests 164 } 165 166 // Process injects a batch of retrieved trie nodes data, returning if something 167 // was committed to the database and also the index of an entry if processing of 168 // it failed. 169 func (s *Sync) Process(results []SyncResult) (bool, int, error) { 170 committed := false 171 172 for i, item := range results { 173 // If the item was not requested, bail out 174 request := s.requests[item.Hash] 175 if request == nil { 176 return committed, i, ErrNotRequested 177 } 178 if request.data != nil { 179 return committed, i, ErrAlreadyProcessed 180 } 181 // If the item is a raw entry request, commit directly 182 if request.raw { 183 request.data = item.Data 184 s.commit(request) 185 committed = true 186 continue 187 } 188 // Decode the node data content and update the request 189 node, err := decodeNode(item.Hash.ToBytes(), item.Data, 0) 190 if err != nil { 191 return committed, i, err 192 } 193 request.data = item.Data 194 195 // Create and schedule a request for all the children nodes 196 requests, err := s.children(request, node) 197 if err != nil { 198 return committed, i, err 199 } 200 if len(requests) == 0 && request.deps == 0 { 201 s.commit(request) 202 committed = true 203 continue 204 } 205 request.deps += len(requests) 206 for _, child := range requests { 207 s.schedule(child) 208 } 209 } 210 return committed, 0, nil 211 } 212 213 // Commit flushes the data stored in the internal membatch out to persistent 214 // storage, returning the number of items written and any occurred error. 215 func (s *Sync) Commit(dbw ogdb.Putter) (int, error) { 216 // Dump the membatch into a database dbw 217 for i, key := range s.membatch.order { 218 if err := dbw.Put(key.ToBytes(), s.membatch.batch[key]); err != nil { 219 return i, err 220 } 221 } 222 written := len(s.membatch.order) 223 224 // Drop the membatch data and return 225 s.membatch = newSyncMemBatch() 226 return written, nil 227 } 228 229 // Pending returns the number of state entries currently pending for download. 230 func (s *Sync) Pending() int { 231 return len(s.requests) 232 } 233 234 // schedule inserts a new state retrieval request into the fetch queue. If there 235 // is already a pending request for this node, the new request will be discarded 236 // and only a parent reference added to the old one. 237 func (s *Sync) schedule(req *request) { 238 // If we're already requesting this node, add a new reference and stop 239 if old, ok := s.requests[req.hash]; ok { 240 old.parents = append(old.parents, req.parents...) 241 return 242 } 243 // Schedule the request for future retrieval 244 s.queue.Push(req.hash, float32(req.depth)) 245 s.requests[req.hash] = req 246 } 247 248 // children retrieves all the missing children of a state trie entry for future 249 // retrieval scheduling. 250 func (s *Sync) children(req *request, object Node) ([]*request, error) { 251 // Gather all the children of the node, irrelevant whether known or not 252 type child struct { 253 node Node 254 depth int 255 } 256 children := []child{} 257 258 switch node := (object).(type) { 259 case *ShortNode: 260 children = []child{{ 261 node: node.Val, 262 depth: req.depth + len(node.Key), 263 }} 264 case *FullNode: 265 for i := 0; i < 17; i++ { 266 if node.Children[i] != nil { 267 children = append(children, child{ 268 node: node.Children[i], 269 depth: req.depth + 1, 270 }) 271 } 272 } 273 default: 274 panic(fmt.Sprintf("unknown node: %+v", node)) 275 } 276 // Iterate over the children, and request all unknown ones 277 requests := make([]*request, 0, len(children)) 278 for _, child := range children { 279 // Notify any external watcher of a new key/value node 280 if req.callback != nil { 281 if node, ok := (child.node).(ValueNode); ok { 282 if err := req.callback(node, req.hash); err != nil { 283 return nil, err 284 } 285 } 286 } 287 // If the child references another node, resolve or schedule 288 if node, ok := (child.node).(HashNode); ok { 289 // Try to resolve the node from the local database 290 hash := types.BytesToHash(node) 291 if _, ok := s.membatch.batch[hash]; ok { 292 continue 293 } 294 if ok, _ := s.database.Has(node); ok { 295 continue 296 } 297 // Locally unknown node, schedule for retrieval 298 requests = append(requests, &request{ 299 hash: hash, 300 parents: []*request{req}, 301 depth: child.depth, 302 callback: req.callback, 303 }) 304 } 305 } 306 return requests, nil 307 } 308 309 // commit finalizes a retrieval request and stores it into the membatch. If any 310 // of the referencing parent requests complete due to this commit, they are also 311 // committed themselves. 312 func (s *Sync) commit(req *request) (err error) { 313 // Write the node content to the membatch 314 s.membatch.batch[req.hash] = req.data 315 s.membatch.order = append(s.membatch.order, req.hash) 316 317 delete(s.requests, req.hash) 318 319 // Check all parents for completion 320 for _, parent := range req.parents { 321 parent.deps-- 322 if parent.deps == 0 { 323 if err := s.commit(parent); err != nil { 324 return err 325 } 326 } 327 } 328 return nil 329 }