github.com/ethereum/go-ethereum@v1.16.1/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 // binaryIterator is a simplistic iterator to step over the accounts or storage 26 // in a snapshot, which may or may not be composed of multiple layers. Performance 27 // wise this iterator is slow, it's meant for cross validating the fast one, 28 type binaryIterator struct { 29 a Iterator 30 b Iterator 31 aDone bool 32 bDone bool 33 accountIterator bool 34 k common.Hash 35 account common.Hash 36 fail error 37 } 38 39 // initBinaryAccountIterator creates a simplistic iterator to step over all the 40 // accounts in a slow, but easily verifiable way. Note this function is used for 41 // initialization, use `newBinaryAccountIterator` as the API. 42 func (dl *diffLayer) initBinaryAccountIterator(seek common.Hash) Iterator { 43 parent, ok := dl.parent.(*diffLayer) 44 if !ok { 45 l := &binaryIterator{ 46 a: dl.AccountIterator(seek), 47 b: dl.Parent().AccountIterator(seek), 48 accountIterator: true, 49 } 50 l.aDone = !l.a.Next() 51 l.bDone = !l.b.Next() 52 return l 53 } 54 l := &binaryIterator{ 55 a: dl.AccountIterator(seek), 56 b: parent.initBinaryAccountIterator(seek), 57 accountIterator: true, 58 } 59 l.aDone = !l.a.Next() 60 l.bDone = !l.b.Next() 61 return l 62 } 63 64 // initBinaryStorageIterator creates a simplistic iterator to step over all the 65 // storage slots in a slow, but easily verifiable way. Note this function is used 66 // for initialization, use `newBinaryStorageIterator` as the API. 67 func (dl *diffLayer) initBinaryStorageIterator(account, seek common.Hash) Iterator { 68 parent, ok := dl.parent.(*diffLayer) 69 if !ok { 70 l := &binaryIterator{ 71 a: dl.StorageIterator(account, seek), 72 b: dl.Parent().StorageIterator(account, seek), 73 account: account, 74 } 75 l.aDone = !l.a.Next() 76 l.bDone = !l.b.Next() 77 return l 78 } 79 l := &binaryIterator{ 80 a: dl.StorageIterator(account, seek), 81 b: parent.initBinaryStorageIterator(account, seek), 82 account: account, 83 } 84 l.aDone = !l.a.Next() 85 l.bDone = !l.b.Next() 86 return l 87 } 88 89 // Next steps the iterator forward one element, returning false if exhausted, 90 // or an error if iteration failed for some reason (e.g. root being iterated 91 // becomes stale and garbage collected). 92 func (it *binaryIterator) Next() bool { 93 for { 94 if !it.next() { 95 return false 96 } 97 if len(it.Account()) != 0 || len(it.Slot()) != 0 { 98 return true 99 } 100 // it.fail might be set if error occurs by calling 101 // it.Account() or it.Slot(), stop iteration if so. 102 if it.fail != nil { 103 return false 104 } 105 } 106 } 107 108 func (it *binaryIterator) next() bool { 109 if it.aDone && it.bDone { 110 return false 111 } 112 for { 113 if it.aDone { 114 it.k = it.b.Hash() 115 it.bDone = !it.b.Next() 116 return true 117 } 118 if it.bDone { 119 it.k = it.a.Hash() 120 it.aDone = !it.a.Next() 121 return true 122 } 123 nextA, nextB := it.a.Hash(), it.b.Hash() 124 if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 { 125 it.aDone = !it.a.Next() 126 it.k = nextA 127 return true 128 } else if diff == 0 { 129 // Now we need to advance one of them 130 it.aDone = !it.a.Next() 131 continue 132 } 133 it.bDone = !it.b.Next() 134 it.k = nextB 135 return true 136 } 137 } 138 139 // Error returns any failure that occurred during iteration, which might have 140 // caused a premature iteration exit (e.g. snapshot stack becoming stale). 141 func (it *binaryIterator) Error() error { 142 return it.fail 143 } 144 145 // Hash returns the hash of the account the iterator is currently at. 146 func (it *binaryIterator) Hash() common.Hash { 147 return it.k 148 } 149 150 // Account returns the RLP encoded slim account the iterator is currently at, or 151 // nil if the iterated snapshot stack became stale (you can check Error after 152 // to see if it failed or not). 153 // 154 // Note the returned account is not a copy, please don't modify it. 155 func (it *binaryIterator) Account() []byte { 156 if !it.accountIterator { 157 return nil 158 } 159 // The topmost iterator must be `diffAccountIterator` 160 blob, err := it.a.(*diffAccountIterator).layer.AccountRLP(it.k) 161 if err != nil { 162 it.fail = err 163 return nil 164 } 165 return blob 166 } 167 168 // Slot returns the raw storage slot data the iterator is currently at, or 169 // nil if the iterated snapshot stack became stale (you can check Error after 170 // to see if it failed or not). 171 // 172 // Note the returned slot is not a copy, please don't modify it. 173 func (it *binaryIterator) Slot() []byte { 174 if it.accountIterator { 175 return nil 176 } 177 blob, err := it.a.(*diffStorageIterator).layer.Storage(it.account, it.k) 178 if err != nil { 179 it.fail = err 180 return nil 181 } 182 return blob 183 } 184 185 // Release recursively releases all the iterators in the stack. 186 func (it *binaryIterator) Release() { 187 it.a.Release() 188 if it.b != nil { 189 it.b.Release() 190 } 191 } 192 193 // newBinaryAccountIterator creates a simplistic account iterator to step over 194 // all the accounts in a slow, but easily verifiable way. 195 func (dl *diffLayer) newBinaryAccountIterator(seek common.Hash) AccountIterator { 196 iter := dl.initBinaryAccountIterator(seek) 197 return iter.(AccountIterator) 198 } 199 200 // newBinaryStorageIterator creates a simplistic account iterator to step over 201 // all the storage slots in a slow, but easily verifiable way. 202 func (dl *diffLayer) newBinaryStorageIterator(account, seek common.Hash) StorageIterator { 203 iter := dl.initBinaryStorageIterator(account, seek) 204 return iter.(StorageIterator) 205 }