github.com/ethereum/go-ethereum@v1.16.1/triedb/pathdb/iterator_binary.go (about) 1 // Copyright 2024 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 pathdb 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 // 29 // This iterator cannot be used on its own; it should be wrapped with an outer 30 // iterator, such as accountBinaryIterator or storageBinaryIterator. 31 // 32 // This iterator can only traverse the keys of the entries stored in the layers, 33 // but cannot obtain the corresponding values. Besides, the deleted entry will 34 // also be traversed, the outer iterator must check the emptiness before returning. 35 type binaryIterator struct { 36 a Iterator 37 b Iterator 38 aDone bool 39 bDone bool 40 k common.Hash 41 fail error 42 } 43 44 // initBinaryAccountIterator creates a simplistic iterator to step over all the 45 // accounts in a slow, but easily verifiable way. Note this function is used 46 // for initialization, use `newBinaryAccountIterator` as the API. 47 func (dl *diskLayer) initBinaryAccountIterator(seek common.Hash) *binaryIterator { 48 // Block until the frozen buffer flushing is completed. 49 if err := dl.waitFlush(); err != nil { 50 panic(err) 51 } 52 // The state set in the disk layer is mutable, hold the lock before obtaining 53 // the account list to prevent concurrent map iteration and write. 54 dl.lock.RLock() 55 accountList := dl.buffer.states.accountList() 56 dl.lock.RUnlock() 57 58 // Create two iterators for state buffer and the persistent state in disk 59 // respectively and combine them as a binary iterator. 60 l := &binaryIterator{ 61 // The account loader function is unnecessary; the account key list 62 // produced by the supplied buffer alone is sufficient for iteration. 63 // 64 // The account key list for iteration is deterministic once the iterator 65 // is constructed, no matter the referenced disk layer is stale or not 66 // later. 67 a: newDiffAccountIterator(seek, accountList, nil), 68 b: newDiskAccountIterator(dl.db.diskdb, seek), 69 } 70 l.aDone = !l.a.Next() 71 l.bDone = !l.b.Next() 72 return l 73 } 74 75 // initBinaryAccountIterator creates a simplistic iterator to step over all the 76 // accounts in a slow, but easily verifiable way. Note this function is used 77 // for initialization, use `newBinaryAccountIterator` as the API. 78 func (dl *diffLayer) initBinaryAccountIterator(seek common.Hash) *binaryIterator { 79 parent, ok := dl.parent.(*diffLayer) 80 if !ok { 81 // The state set in diff layer is immutable and will never be stale, 82 // so the read lock protection is unnecessary. 83 accountList := dl.states.stateSet.accountList() 84 l := &binaryIterator{ 85 // The account loader function is unnecessary; the account key list 86 // produced by the supplied state set alone is sufficient for iteration. 87 // 88 // The account key list for iteration is deterministic once the iterator 89 // is constructed, no matter the referenced disk layer is stale or not 90 // later. 91 a: newDiffAccountIterator(seek, accountList, nil), 92 b: dl.parent.(*diskLayer).initBinaryAccountIterator(seek), 93 } 94 l.aDone = !l.a.Next() 95 l.bDone = !l.b.Next() 96 return l 97 } 98 // The state set in diff layer is immutable and will never be stale, 99 // so the read lock protection is unnecessary. 100 accountList := dl.states.stateSet.accountList() 101 l := &binaryIterator{ 102 // The account loader function is unnecessary; the account key list 103 // produced by the supplied state set alone is sufficient for iteration. 104 // 105 // The account key list for iteration is deterministic once the iterator 106 // is constructed, no matter the referenced disk layer is stale or not 107 // later. 108 a: newDiffAccountIterator(seek, accountList, nil), 109 b: parent.initBinaryAccountIterator(seek), 110 } 111 l.aDone = !l.a.Next() 112 l.bDone = !l.b.Next() 113 return l 114 } 115 116 // initBinaryStorageIterator creates a simplistic iterator to step over all the 117 // storage slots in a slow, but easily verifiable way. Note this function is used 118 // for initialization, use `newBinaryStorageIterator` as the API. 119 func (dl *diskLayer) initBinaryStorageIterator(account common.Hash, seek common.Hash) *binaryIterator { 120 // Block until the frozen buffer flushing is completed. 121 if err := dl.waitFlush(); err != nil { 122 panic(err) 123 } 124 // The state set in the disk layer is mutable, hold the lock before obtaining 125 // the storage list to prevent concurrent map iteration and write. 126 dl.lock.RLock() 127 storageList := dl.buffer.states.storageList(account) 128 dl.lock.RUnlock() 129 130 // Create two iterators for state buffer and the persistent state in disk 131 // respectively and combine them as a binary iterator. 132 l := &binaryIterator{ 133 // The storage loader function is unnecessary; the storage key list 134 // produced by the supplied buffer alone is sufficient for iteration. 135 // 136 // The storage key list for iteration is deterministic once the iterator 137 // is constructed, no matter the referenced disk layer is stale or not 138 // later. 139 a: newDiffStorageIterator(account, seek, storageList, nil), 140 b: newDiskStorageIterator(dl.db.diskdb, account, seek), 141 } 142 l.aDone = !l.a.Next() 143 l.bDone = !l.b.Next() 144 return l 145 } 146 147 // initBinaryStorageIterator creates a simplistic iterator to step over all the 148 // storage slots in a slow, but easily verifiable way. Note this function is used 149 // for initialization, use `newBinaryStorageIterator` as the API. 150 func (dl *diffLayer) initBinaryStorageIterator(account common.Hash, seek common.Hash) *binaryIterator { 151 parent, ok := dl.parent.(*diffLayer) 152 if !ok { 153 // The state set in diff layer is immutable and will never be stale, 154 // so the read lock protection is unnecessary. 155 storageList := dl.states.stateSet.storageList(account) 156 l := &binaryIterator{ 157 // The storage loader function is unnecessary; the storage key list 158 // produced by the supplied state set alone is sufficient for iteration. 159 // 160 // The storage key list for iteration is deterministic once the iterator 161 // is constructed, no matter the referenced disk layer is stale or not 162 // later. 163 a: newDiffStorageIterator(account, seek, storageList, nil), 164 b: dl.parent.(*diskLayer).initBinaryStorageIterator(account, seek), 165 } 166 l.aDone = !l.a.Next() 167 l.bDone = !l.b.Next() 168 return l 169 } 170 // The state set in diff layer is immutable and will never be stale, 171 // so the read lock protection is unnecessary. 172 storageList := dl.states.stateSet.storageList(account) 173 l := &binaryIterator{ 174 // The storage loader function is unnecessary; the storage key list 175 // produced by the supplied state set alone is sufficient for iteration. 176 // 177 // The storage key list for iteration is deterministic once the iterator 178 // is constructed, no matter the referenced disk layer is stale or not 179 // later. 180 a: newDiffStorageIterator(account, seek, storageList, nil), 181 b: parent.initBinaryStorageIterator(account, seek), 182 } 183 l.aDone = !l.a.Next() 184 l.bDone = !l.b.Next() 185 return l 186 } 187 188 // Next advances the iterator by one element, returning false if both iterators 189 // are exhausted. Note that the entry pointed to by the iterator may be null 190 // (e.g., when an account is deleted but still accessible for iteration). 191 // The outer iterator must verify emptiness before terminating the iteration. 192 // 193 // There’s no need to check for errors in the two iterators, as we only iterate 194 // through the entries without retrieving their values. 195 func (it *binaryIterator) Next() bool { 196 if it.aDone && it.bDone { 197 return false 198 } 199 for { 200 if it.aDone { 201 it.k = it.b.Hash() 202 it.bDone = !it.b.Next() 203 return true 204 } 205 if it.bDone { 206 it.k = it.a.Hash() 207 it.aDone = !it.a.Next() 208 return true 209 } 210 nextA, nextB := it.a.Hash(), it.b.Hash() 211 if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 { 212 it.aDone = !it.a.Next() 213 it.k = nextA 214 return true 215 } else if diff == 0 { 216 // Now we need to advance one of them 217 it.aDone = !it.a.Next() 218 continue 219 } 220 it.bDone = !it.b.Next() 221 it.k = nextB 222 return true 223 } 224 } 225 226 // Error returns any failure that occurred during iteration, which might have 227 // caused a premature iteration exit (e.g. snapshot stack becoming stale). 228 func (it *binaryIterator) Error() error { 229 return it.fail 230 } 231 232 // Hash returns the hash of the account the iterator is currently at. 233 func (it *binaryIterator) Hash() common.Hash { 234 return it.k 235 } 236 237 // Release recursively releases all the iterators in the stack. 238 func (it *binaryIterator) Release() { 239 it.a.Release() 240 it.b.Release() 241 } 242 243 // accountBinaryIterator is a wrapper around a binary iterator that adds functionality 244 // to retrieve account data from the associated layer at the current position. 245 type accountBinaryIterator struct { 246 *binaryIterator 247 layer layer 248 } 249 250 // newBinaryAccountIterator creates a simplistic account iterator to step over 251 // all the accounts in a slow, but easily verifiable way. 252 // 253 // nolint:all 254 func (dl *diskLayer) newBinaryAccountIterator(seek common.Hash) AccountIterator { 255 return &accountBinaryIterator{ 256 binaryIterator: dl.initBinaryAccountIterator(seek), 257 layer: dl, 258 } 259 } 260 261 // newBinaryAccountIterator creates a simplistic account iterator to step over 262 // all the accounts in a slow, but easily verifiable way. 263 func (dl *diffLayer) newBinaryAccountIterator(seek common.Hash) AccountIterator { 264 return &accountBinaryIterator{ 265 binaryIterator: dl.initBinaryAccountIterator(seek), 266 layer: dl, 267 } 268 } 269 270 // Next steps the iterator forward one element, returning false if exhausted, 271 // or an error if iteration failed for some reason (e.g. the linked layer is 272 // stale during the iteration). 273 func (it *accountBinaryIterator) Next() bool { 274 for { 275 if !it.binaryIterator.Next() { 276 return false 277 } 278 // Retrieve the account data referenced by the current iterator, the 279 // associated layers might be outdated due to chain progressing, 280 // the relative error will be set to it.fail just in case. 281 // 282 // Skip the null account which was deleted before and move to the 283 // next account. 284 if len(it.Account()) != 0 { 285 return true 286 } 287 // it.fail might be set if error occurs by calling it.Account(). 288 // Stop iteration if so. 289 if it.fail != nil { 290 return false 291 } 292 } 293 } 294 295 // Account returns the RLP encoded slim account the iterator is currently at, or 296 // nil if the iterated snapshot stack became stale (you can check Error after 297 // to see if it failed or not). 298 // 299 // Note the returned account is not a copy, please don't modify it. 300 func (it *accountBinaryIterator) Account() []byte { 301 blob, err := it.layer.account(it.k, 0) 302 if err != nil { 303 it.fail = err 304 return nil 305 } 306 return blob 307 } 308 309 // storageBinaryIterator is a wrapper around a binary iterator that adds functionality 310 // to retrieve storage slot data from the associated layer at the current position. 311 type storageBinaryIterator struct { 312 *binaryIterator 313 account common.Hash 314 layer layer 315 } 316 317 // newBinaryStorageIterator creates a simplistic account iterator to step over 318 // all the storage slots in a slow, but easily verifiable way. 319 // 320 // nolint:all 321 func (dl *diskLayer) newBinaryStorageIterator(account common.Hash, seek common.Hash) StorageIterator { 322 return &storageBinaryIterator{ 323 binaryIterator: dl.initBinaryStorageIterator(account, seek), 324 account: account, 325 layer: dl, 326 } 327 } 328 329 // newBinaryStorageIterator creates a simplistic account iterator to step over 330 // all the storage slots in a slow, but easily verifiable way. 331 func (dl *diffLayer) newBinaryStorageIterator(account common.Hash, seek common.Hash) StorageIterator { 332 return &storageBinaryIterator{ 333 binaryIterator: dl.initBinaryStorageIterator(account, seek), 334 account: account, 335 layer: dl, 336 } 337 } 338 339 // Next steps the iterator forward one element, returning false if exhausted, 340 // or an error if iteration failed for some reason (e.g. the linked layer is 341 // stale during the iteration). 342 func (it *storageBinaryIterator) Next() bool { 343 for { 344 if !it.binaryIterator.Next() { 345 return false 346 } 347 // Retrieve the storage data referenced by the current iterator, the 348 // associated layers might be outdated due to chain progressing, 349 // the relative error will be set to it.fail just in case. 350 // 351 // Skip the null storage which was deleted before and move to the 352 // next account. 353 if len(it.Slot()) != 0 { 354 return true 355 } 356 // it.fail might be set if error occurs by calling it.Slot(). 357 // Stop iteration if so. 358 if it.fail != nil { 359 return false 360 } 361 } 362 } 363 364 // Slot returns the raw storage slot data the iterator is currently at, or 365 // nil if the iterated snapshot stack became stale (you can check Error after 366 // to see if it failed or not). 367 // 368 // Note the returned slot is not a copy, please don't modify it. 369 func (it *storageBinaryIterator) Slot() []byte { 370 blob, err := it.layer.storage(it.account, it.k, 0) 371 if err != nil { 372 it.fail = err 373 return nil 374 } 375 return blob 376 }