gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/core/state/snapshot/iterator_binary.go (about) 1 // Copyright 2019 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 snapshot 18 19 import ( 20 "bytes" 21 22 "github.com/ethereum/go-ethereum/common" 23 ) 24 25 // binaryAccountIterator is a simplistic iterator to step over the accounts in 26 // a snapshot, which may or may npt be composed of multiple layers. Performance 27 // wise this iterator is slow, it's meant for cross validating the fast one, 28 type binaryAccountIterator struct { 29 a *diffAccountIterator 30 b AccountIterator 31 aDone bool 32 bDone bool 33 k common.Hash 34 fail error 35 } 36 37 // newBinaryAccountIterator creates a simplistic account iterator to step over 38 // all the accounts in a slow, but eaily verifiable way. 39 func (dl *diffLayer) newBinaryAccountIterator() AccountIterator { 40 parent, ok := dl.parent.(*diffLayer) 41 if !ok { 42 // parent is the disk layer 43 return dl.AccountIterator(common.Hash{}) 44 } 45 l := &binaryAccountIterator{ 46 a: dl.AccountIterator(common.Hash{}).(*diffAccountIterator), 47 b: parent.newBinaryAccountIterator(), 48 } 49 l.aDone = !l.a.Next() 50 l.bDone = !l.b.Next() 51 return l 52 } 53 54 // Next steps the iterator forward one element, returning false if exhausted, 55 // or an error if iteration failed for some reason (e.g. root being iterated 56 // becomes stale and garbage collected). 57 func (it *binaryAccountIterator) Next() bool { 58 if it.aDone && it.bDone { 59 return false 60 } 61 nextB := it.b.Hash() 62 first: 63 nextA := it.a.Hash() 64 if it.aDone { 65 it.bDone = !it.b.Next() 66 it.k = nextB 67 return true 68 } 69 if it.bDone { 70 it.aDone = !it.a.Next() 71 it.k = nextA 72 return true 73 } 74 if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 { 75 it.aDone = !it.a.Next() 76 it.k = nextA 77 return true 78 } else if diff == 0 { 79 // Now we need to advance one of them 80 it.aDone = !it.a.Next() 81 goto first 82 } 83 it.bDone = !it.b.Next() 84 it.k = nextB 85 return true 86 } 87 88 // Error returns any failure that occurred during iteration, which might have 89 // caused a premature iteration exit (e.g. snapshot stack becoming stale). 90 func (it *binaryAccountIterator) Error() error { 91 return it.fail 92 } 93 94 // Hash returns the hash of the account the iterator is currently at. 95 func (it *binaryAccountIterator) Hash() common.Hash { 96 return it.k 97 } 98 99 // Account returns the RLP encoded slim account the iterator is currently at, or 100 // nil if the iterated snapshot stack became stale (you can check Error after 101 // to see if it failed or not). 102 func (it *binaryAccountIterator) Account() []byte { 103 blob, err := it.a.layer.AccountRLP(it.k) 104 if err != nil { 105 it.fail = err 106 return nil 107 } 108 return blob 109 } 110 111 // Release recursively releases all the iterators in the stack. 112 func (it *binaryAccountIterator) Release() { 113 it.a.Release() 114 it.b.Release() 115 }