github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/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/tirogen/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() Iterator { 43 parent, ok := dl.parent.(*diffLayer) 44 if !ok { 45 l := &binaryIterator{ 46 a: dl.AccountIterator(common.Hash{}), 47 b: dl.Parent().AccountIterator(common.Hash{}), 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(common.Hash{}), 56 b: parent.initBinaryAccountIterator(), 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 common.Hash) Iterator { 68 parent, ok := dl.parent.(*diffLayer) 69 if !ok { 70 // If the storage in this layer is already destructed, discard all 71 // deeper layers but still return an valid single-branch iterator. 72 a, destructed := dl.StorageIterator(account, common.Hash{}) 73 if destructed { 74 l := &binaryIterator{ 75 a: a, 76 account: account, 77 } 78 l.aDone = !l.a.Next() 79 l.bDone = true 80 return l 81 } 82 // The parent is disk layer, don't need to take care "destructed" 83 // anymore. 84 b, _ := dl.Parent().StorageIterator(account, common.Hash{}) 85 l := &binaryIterator{ 86 a: a, 87 b: b, 88 account: account, 89 } 90 l.aDone = !l.a.Next() 91 l.bDone = !l.b.Next() 92 return l 93 } 94 // If the storage in this layer is already destructed, discard all 95 // deeper layers but still return an valid single-branch iterator. 96 a, destructed := dl.StorageIterator(account, common.Hash{}) 97 if destructed { 98 l := &binaryIterator{ 99 a: a, 100 account: account, 101 } 102 l.aDone = !l.a.Next() 103 l.bDone = true 104 return l 105 } 106 l := &binaryIterator{ 107 a: a, 108 b: parent.initBinaryStorageIterator(account), 109 account: account, 110 } 111 l.aDone = !l.a.Next() 112 l.bDone = !l.b.Next() 113 return l 114 } 115 116 // Next steps the iterator forward one element, returning false if exhausted, 117 // or an error if iteration failed for some reason (e.g. root being iterated 118 // becomes stale and garbage collected). 119 func (it *binaryIterator) Next() bool { 120 if it.aDone && it.bDone { 121 return false 122 } 123 first: 124 if it.aDone { 125 it.k = it.b.Hash() 126 it.bDone = !it.b.Next() 127 return true 128 } 129 if it.bDone { 130 it.k = it.a.Hash() 131 it.aDone = !it.a.Next() 132 return true 133 } 134 nextA, nextB := it.a.Hash(), it.b.Hash() 135 if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 { 136 it.aDone = !it.a.Next() 137 it.k = nextA 138 return true 139 } else if diff == 0 { 140 // Now we need to advance one of them 141 it.aDone = !it.a.Next() 142 goto first 143 } 144 it.bDone = !it.b.Next() 145 it.k = nextB 146 return true 147 } 148 149 // Error returns any failure that occurred during iteration, which might have 150 // caused a premature iteration exit (e.g. snapshot stack becoming stale). 151 func (it *binaryIterator) Error() error { 152 return it.fail 153 } 154 155 // Hash returns the hash of the account the iterator is currently at. 156 func (it *binaryIterator) Hash() common.Hash { 157 return it.k 158 } 159 160 // Account returns the RLP encoded slim account the iterator is currently at, or 161 // nil if the iterated snapshot stack became stale (you can check Error after 162 // to see if it failed or not). 163 // 164 // Note the returned account is not a copy, please don't modify it. 165 func (it *binaryIterator) Account() []byte { 166 if !it.accountIterator { 167 return nil 168 } 169 // The topmost iterator must be `diffAccountIterator` 170 blob, err := it.a.(*diffAccountIterator).layer.AccountRLP(it.k) 171 if err != nil { 172 it.fail = err 173 return nil 174 } 175 return blob 176 } 177 178 // Slot returns the raw storage slot data the iterator is currently at, or 179 // nil if the iterated snapshot stack became stale (you can check Error after 180 // to see if it failed or not). 181 // 182 // Note the returned slot is not a copy, please don't modify it. 183 func (it *binaryIterator) Slot() []byte { 184 if it.accountIterator { 185 return nil 186 } 187 blob, err := it.a.(*diffStorageIterator).layer.Storage(it.account, it.k) 188 if err != nil { 189 it.fail = err 190 return nil 191 } 192 return blob 193 } 194 195 // Release recursively releases all the iterators in the stack. 196 func (it *binaryIterator) Release() { 197 it.a.Release() 198 it.b.Release() 199 } 200 201 // newBinaryAccountIterator creates a simplistic account iterator to step over 202 // all the accounts in a slow, but easily verifiable way. 203 func (dl *diffLayer) newBinaryAccountIterator() AccountIterator { 204 iter := dl.initBinaryAccountIterator() 205 return iter.(AccountIterator) 206 } 207 208 // newBinaryStorageIterator creates a simplistic account iterator to step over 209 // all the storage slots in a slow, but easily verifiable way. 210 func (dl *diffLayer) newBinaryStorageIterator(account common.Hash) StorageIterator { 211 iter := dl.initBinaryStorageIterator(account) 212 return iter.(StorageIterator) 213 }