| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | // Copyright 2019 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package snapshot | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | // weightedIterator is a iterator with an assigned weight. It is used to prioritise | 
					
						
							|  |  |  | // which account or storage slot is the correct one if multiple iterators find the | 
					
						
							|  |  |  | // same one (modified in multiple consecutive blocks). | 
					
						
							|  |  |  | type weightedIterator struct { | 
					
						
							|  |  |  | 	it       Iterator | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 	priority int | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | // weightedIterators is a set of iterators implementing the sort.Interface. | 
					
						
							|  |  |  | type weightedIterators []*weightedIterator | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Len implements sort.Interface, returning the number of active iterators. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (its weightedIterators) Len() int { return len(its) } | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Less implements sort.Interface, returning which of two iterators in the stack | 
					
						
							|  |  |  | // is before the other. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (its weightedIterators) Less(i, j int) bool { | 
					
						
							| 
									
										
										
										
											2020-02-24 13:26:34 +02:00
										 |  |  | 	// Order the iterators primarily by the account hashes | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	hashI := its[i].it.Hash() | 
					
						
							|  |  |  | 	hashJ := its[j].it.Hash() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch bytes.Compare(hashI[:], hashJ[:]) { | 
					
						
							|  |  |  | 	case -1: | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 	// Same account/storage-slot in multiple layers, split by priority | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	return its[i].priority < its[j].priority | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Swap implements sort.Interface, swapping two entries in the iterator stack. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (its weightedIterators) Swap(i, j int) { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	its[i], its[j] = its[j], its[i] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | // fastIterator is a more optimized multi-layer iterator which maintains a | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // direct mapping of all iterators leading down to the bottom layer. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | type fastIterator struct { | 
					
						
							|  |  |  | 	tree *Tree       // Snapshot tree to reinitialize stale sub-iterators with | 
					
						
							|  |  |  | 	root common.Hash // Root hash to reinitialize stale sub-iterators through | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 20:57:56 +01:00
										 |  |  | 	curAccount []byte | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 	curSlot    []byte | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 	iterators weightedIterators | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	initiated bool | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 	account   bool | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	fail      error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:36:21 +09:00
										 |  |  | // newFastIterator creates a new hierarchical account or storage iterator with one | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // element per diff layer. The returned combo iterator can be used to walk over | 
					
						
							|  |  |  | // the entire snapshot diff stack simultaneously. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func newFastIterator(tree *Tree, root common.Hash, account common.Hash, seek common.Hash, accountIterator bool) (*fastIterator, error) { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	snap := tree.Snapshot(root) | 
					
						
							|  |  |  | 	if snap == nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("unknown snapshot: %x", root) | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 	fi := &fastIterator{ | 
					
						
							|  |  |  | 		tree:    tree, | 
					
						
							|  |  |  | 		root:    root, | 
					
						
							|  |  |  | 		account: accountIterator, | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	current := snap.(snapshot) | 
					
						
							|  |  |  | 	for depth := 0; current != nil; depth++ { | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 		if accountIterator { | 
					
						
							|  |  |  | 			fi.iterators = append(fi.iterators, &weightedIterator{ | 
					
						
							|  |  |  | 				it:       current.AccountIterator(seek), | 
					
						
							|  |  |  | 				priority: depth, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// If the whole storage is destructed in this layer, don't | 
					
						
							|  |  |  | 			// bother deeper layer anymore. But we should still keep | 
					
						
							|  |  |  | 			// the iterator for this layer, since the iterator can contain | 
					
						
							|  |  |  | 			// some valid slots which belongs to the re-created account. | 
					
						
							|  |  |  | 			it, destructed := current.StorageIterator(account, seek) | 
					
						
							|  |  |  | 			fi.iterators = append(fi.iterators, &weightedIterator{ | 
					
						
							|  |  |  | 				it:       it, | 
					
						
							|  |  |  | 				priority: depth, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			if destructed { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 		current = current.Parent() | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	fi.init() | 
					
						
							|  |  |  | 	return fi, nil | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // init walks over all the iterators and resolves any clashes between them, after | 
					
						
							|  |  |  | // which it prepares the stack for step-by-step iteration. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (fi *fastIterator) init() { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	// Track which account hashes are iterators positioned on | 
					
						
							|  |  |  | 	var positioned = make(map[common.Hash]int) | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	// Position all iterators and track how many remain live | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 	for i := 0; i < len(fi.iterators); i++ { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 		// Retrieve the first element and if it clashes with a previous iterator, | 
					
						
							|  |  |  | 		// advance either the current one or the old one. Repeat until nothing is | 
					
						
							|  |  |  | 		// clashing any more. | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 		it := fi.iterators[i] | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 		for { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 			// If the iterator is exhausted, drop it off the end | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 			if !it.it.Next() { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 				it.it.Release() | 
					
						
							|  |  |  | 				last := len(fi.iterators) - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				fi.iterators[i] = fi.iterators[last] | 
					
						
							|  |  |  | 				fi.iterators[last] = nil | 
					
						
							|  |  |  | 				fi.iterators = fi.iterators[:last] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				i-- | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 			// The iterator is still alive, check for collisions with previous ones | 
					
						
							|  |  |  | 			hash := it.it.Hash() | 
					
						
							|  |  |  | 			if other, exist := positioned[hash]; !exist { | 
					
						
							|  |  |  | 				positioned[hash] = i | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 				break | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 				// Iterators collide, one needs to be progressed, use priority to | 
					
						
							|  |  |  | 				// determine which. | 
					
						
							|  |  |  | 				// | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 				// This whole else-block can be avoided, if we instead | 
					
						
							| 
									
										
										
										
											2020-02-24 13:26:34 +02:00
										 |  |  | 				// do an initial priority-sort of the iterators. If we do that, | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 				// then we'll only wind up here if a lower-priority (preferred) iterator | 
					
						
							|  |  |  | 				// has the same value, and then we will always just continue. | 
					
						
							|  |  |  | 				// However, it costs an extra sort, so it's probably not better | 
					
						
							|  |  |  | 				if fi.iterators[other].priority < it.priority { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 					// The 'it' should be progressed | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 					continue | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 					// The 'other' should be progressed, swap them | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 					it = fi.iterators[other] | 
					
						
							|  |  |  | 					fi.iterators[other], fi.iterators[i] = fi.iterators[i], fi.iterators[other] | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	// Re-sort the entire list | 
					
						
							|  |  |  | 	sort.Sort(fi.iterators) | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	fi.initiated = false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // Next steps the iterator forward one element, returning false if exhausted. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (fi *fastIterator) Next() bool { | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	if len(fi.iterators) == 0 { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !fi.initiated { | 
					
						
							|  |  |  | 		// Don't forward first time -- we had to 'Next' once in order to | 
					
						
							|  |  |  | 		// do the sorting already | 
					
						
							|  |  |  | 		fi.initiated = true | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 		if fi.account { | 
					
						
							|  |  |  | 			fi.curAccount = fi.iterators[0].it.(AccountIterator).Account() | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			fi.curSlot = fi.iterators[0].it.(StorageIterator).Slot() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-19 20:57:56 +01:00
										 |  |  | 		if innerErr := fi.iterators[0].it.Error(); innerErr != nil { | 
					
						
							|  |  |  | 			fi.fail = innerErr | 
					
						
							| 
									
										
										
										
											2020-03-04 13:38:55 +01:00
										 |  |  | 			return false | 
					
						
							| 
									
										
										
										
											2020-01-19 20:57:56 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 		if fi.curAccount != nil || fi.curSlot != nil { | 
					
						
							| 
									
										
										
										
											2020-03-04 13:38:55 +01:00
										 |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 		// Implicit else: we've hit a nil-account or nil-slot, and need to | 
					
						
							|  |  |  | 		// fall through to the loop below to land on something non-nil | 
					
						
							| 
									
										
										
										
											2020-01-19 20:57:56 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 	// If an account or a slot is deleted in one of the layers, the key will | 
					
						
							|  |  |  | 	// still be there, but the actual value will be nil. However, the iterator | 
					
						
							|  |  |  | 	// should not export nil-values (but instead simply omit the key), so we | 
					
						
							|  |  |  | 	// need to loop here until we either | 
					
						
							| 
									
										
										
										
											2020-03-04 13:38:55 +01:00
										 |  |  | 	//  - get a non-nil value, | 
					
						
							|  |  |  | 	//  - hit an error, | 
					
						
							|  |  |  | 	//  - or exhaust the iterator | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		if !fi.next(0) { | 
					
						
							|  |  |  | 			return false // exhausted | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 		if fi.account { | 
					
						
							|  |  |  | 			fi.curAccount = fi.iterators[0].it.(AccountIterator).Account() | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			fi.curSlot = fi.iterators[0].it.(StorageIterator).Slot() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-03-04 13:38:55 +01:00
										 |  |  | 		if innerErr := fi.iterators[0].it.Error(); innerErr != nil { | 
					
						
							|  |  |  | 			fi.fail = innerErr | 
					
						
							|  |  |  | 			return false // error | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 		if fi.curAccount != nil || fi.curSlot != nil { | 
					
						
							| 
									
										
										
										
											2020-03-04 13:38:55 +01:00
										 |  |  | 			break // non-nil value found | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-04 13:38:55 +01:00
										 |  |  | 	return true | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // next handles the next operation internally and should be invoked when we know | 
					
						
							|  |  |  | // that two elements in the list may have the same value. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // For example, if the iterated hashes become [2,3,5,5,8,9,10], then we should | 
					
						
							|  |  |  | // invoke next(3), which will call Next on elem 3 (the second '5') and will | 
					
						
							|  |  |  | // cascade along the list, applying the same operation if needed. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (fi *fastIterator) next(idx int) bool { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	// If this particular iterator got exhausted, remove it and return true (the | 
					
						
							|  |  |  | 	// next one is surely not exhausted yet, otherwise it would have been removed | 
					
						
							|  |  |  | 	// already). | 
					
						
							|  |  |  | 	if it := fi.iterators[idx].it; !it.Next() { | 
					
						
							|  |  |  | 		it.Release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		fi.iterators = append(fi.iterators[:idx], fi.iterators[idx+1:]...) | 
					
						
							|  |  |  | 		return len(fi.iterators) > 0 | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-25 16:21:28 +08:00
										 |  |  | 	// If there's no one left to cascade into, return | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	if idx == len(fi.iterators)-1 { | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	// We next-ed the iterator at 'idx', now we may have to re-sort that element | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 		cur, next         = fi.iterators[idx], fi.iterators[idx+1] | 
					
						
							|  |  |  | 		curHash, nextHash = cur.it.Hash(), next.it.Hash() | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	if diff := bytes.Compare(curHash[:], nextHash[:]); diff < 0 { | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 		// It is still in correct place | 
					
						
							|  |  |  | 		return true | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	} else if diff == 0 && cur.priority < next.priority { | 
					
						
							|  |  |  | 		// So still in correct place, but we need to iterate on the next | 
					
						
							|  |  |  | 		fi.next(idx + 1) | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	// At this point, the iterator is in the wrong location, but the remaining | 
					
						
							|  |  |  | 	// list is sorted. Find out where to move the item. | 
					
						
							|  |  |  | 	clash := -1 | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	index := sort.Search(len(fi.iterators), func(n int) bool { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 		// The iterator always advances forward, so anything before the old slot | 
					
						
							|  |  |  | 		// is known to be behind us, so just skip them altogether. This actually | 
					
						
							|  |  |  | 		// is an important clause since the sort order got invalidated. | 
					
						
							|  |  |  | 		if n < idx { | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if n == len(fi.iterators)-1 { | 
					
						
							|  |  |  | 			// Can always place an elem last | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 		nextHash := fi.iterators[n+1].it.Hash() | 
					
						
							|  |  |  | 		if diff := bytes.Compare(curHash[:], nextHash[:]); diff < 0 { | 
					
						
							| 
									
										
										
										
											2019-12-06 23:27:18 +01:00
										 |  |  | 			return true | 
					
						
							|  |  |  | 		} else if diff > 0 { | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// The elem we're placing it next to has the same value, | 
					
						
							|  |  |  | 		// so whichever winds up on n+1 will need further iteraton | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 		clash = n + 1 | 
					
						
							| 
									
										
										
										
											2020-02-24 13:26:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return cur.priority < fi.iterators[n+1].priority | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	fi.move(idx, index) | 
					
						
							|  |  |  | 	if clash != -1 { | 
					
						
							|  |  |  | 		fi.next(clash) | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // move advances an iterator to another position in the list. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (fi *fastIterator) move(index, newpos int) { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	elem := fi.iterators[index] | 
					
						
							|  |  |  | 	copy(fi.iterators[index:], fi.iterators[index+1:newpos+1]) | 
					
						
							|  |  |  | 	fi.iterators[newpos] = elem | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Error returns any failure that occurred during iteration, which might have | 
					
						
							|  |  |  | // caused a premature iteration exit (e.g. snapshot stack becoming stale). | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (fi *fastIterator) Error() error { | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	return fi.fail | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // Hash returns the current key | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (fi *fastIterator) Hash() common.Hash { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	return fi.iterators[0].it.Hash() | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | // Account returns the current account blob. | 
					
						
							|  |  |  | // Note the returned account is not a copy, please don't modify it. | 
					
						
							|  |  |  | func (fi *fastIterator) Account() []byte { | 
					
						
							| 
									
										
										
										
											2020-01-19 20:57:56 +01:00
										 |  |  | 	return fi.curAccount | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | // Slot returns the current storage slot. | 
					
						
							|  |  |  | // Note the returned slot is not a copy, please don't modify it. | 
					
						
							|  |  |  | func (fi *fastIterator) Slot() []byte { | 
					
						
							|  |  |  | 	return fi.curSlot | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // Release iterates over all the remaining live layer iterators and releases each | 
					
						
							|  |  |  | // of thme individually. | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (fi *fastIterator) Release() { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 	for _, it := range fi.iterators { | 
					
						
							|  |  |  | 		it.it.Release() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fi.iterators = nil | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Debug is a convencience helper during testing | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | func (fi *fastIterator) Debug() { | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	for _, it := range fi.iterators { | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | 		fmt.Printf("[p=%v v=%v] ", it.priority, it.it.Hash()[0]) | 
					
						
							| 
									
										
										
										
											2019-12-05 15:37:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println() | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:36:21 +09:00
										 |  |  | // newFastAccountIterator creates a new hierarchical account iterator with one | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | // element per diff layer. The returned combo iterator can be used to walk over | 
					
						
							|  |  |  | // the entire snapshot diff stack simultaneously. | 
					
						
							|  |  |  | func newFastAccountIterator(tree *Tree, root common.Hash, seek common.Hash) (AccountIterator, error) { | 
					
						
							|  |  |  | 	return newFastIterator(tree, root, common.Hash{}, seek, true) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:36:21 +09:00
										 |  |  | // newFastStorageIterator creates a new hierarchical storage iterator with one | 
					
						
							| 
									
										
										
										
											2020-04-29 17:53:08 +08:00
										 |  |  | // element per diff layer. The returned combo iterator can be used to walk over | 
					
						
							|  |  |  | // the entire snapshot diff stack simultaneously. | 
					
						
							|  |  |  | func newFastStorageIterator(tree *Tree, root common.Hash, account common.Hash, seek common.Hash) (StorageIterator, error) { | 
					
						
							|  |  |  | 	return newFastIterator(tree, root, account, seek, false) | 
					
						
							|  |  |  | } |