github.com/klaytn/klaytn@v1.12.1/snapshot/iterator_binary.go (about) 1 // Modifications Copyright 2021 The klaytn Authors 2 // Copyright 2019 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/state/snapshot/iterator_binary.go (2021/10/21). 19 // Modified and improved for the klaytn development. 20 21 package snapshot 22 23 import ( 24 "bytes" 25 26 "github.com/klaytn/klaytn/common" 27 ) 28 29 // binaryIterator is a simplistic iterator to step over the accounts or storage 30 // in a snapshot, which may or may not be composed of multiple layers. Performance 31 // wise this iterator is slow, it's meant for cross validating the fast one, 32 type binaryIterator struct { 33 a Iterator 34 b Iterator 35 aDone bool 36 bDone bool 37 accountIterator bool 38 k common.Hash 39 account common.Hash 40 fail error 41 } 42 43 // initBinaryAccountIterator creates a simplistic iterator to step over all the 44 // accounts in a slow, but easily verifiable way. Note this function is used for 45 // initialization, use `newBinaryAccountIterator` as the API. 46 func (dl *diffLayer) initBinaryAccountIterator() Iterator { 47 parent, ok := dl.parent.(*diffLayer) 48 if !ok { 49 l := &binaryIterator{ 50 a: dl.AccountIterator(common.Hash{}), 51 b: dl.Parent().AccountIterator(common.Hash{}), 52 accountIterator: true, 53 } 54 l.aDone = !l.a.Next() 55 l.bDone = !l.b.Next() 56 return l 57 } 58 l := &binaryIterator{ 59 a: dl.AccountIterator(common.Hash{}), 60 b: parent.initBinaryAccountIterator(), 61 accountIterator: true, 62 } 63 l.aDone = !l.a.Next() 64 l.bDone = !l.b.Next() 65 return l 66 } 67 68 // initBinaryStorageIterator creates a simplistic iterator to step over all the 69 // storage slots in a slow, but easily verifiable way. Note this function is used 70 // for initialization, use `newBinaryStorageIterator` as the API. 71 func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator { 72 parent, ok := dl.parent.(*diffLayer) 73 if !ok { 74 // If the storage in this layer is already destructed, discard all 75 // deeper layers but still return an valid single-branch iterator. 76 a, destructed := dl.StorageIterator(account, common.Hash{}) 77 if destructed { 78 l := &binaryIterator{ 79 a: a, 80 account: account, 81 } 82 l.aDone = !l.a.Next() 83 l.bDone = true 84 return l 85 } 86 // The parent is disk layer, don't need to take care "destructed" 87 // anymore. 88 b, _ := dl.Parent().StorageIterator(account, common.Hash{}) 89 l := &binaryIterator{ 90 a: a, 91 b: b, 92 account: account, 93 } 94 l.aDone = !l.a.Next() 95 l.bDone = !l.b.Next() 96 return l 97 } 98 // If the storage in this layer is already destructed, discard all 99 // deeper layers but still return an valid single-branch iterator. 100 a, destructed := dl.StorageIterator(account, common.Hash{}) 101 if destructed { 102 l := &binaryIterator{ 103 a: a, 104 account: account, 105 } 106 l.aDone = !l.a.Next() 107 l.bDone = true 108 return l 109 } 110 l := &binaryIterator{ 111 a: a, 112 b: parent.initBinaryStorageIterator(account), 113 account: account, 114 } 115 l.aDone = !l.a.Next() 116 l.bDone = !l.b.Next() 117 return l 118 } 119 120 // Next steps the iterator forward one element, returning false if exhausted, 121 // or an error if iteration failed for some reason (e.g. root being iterated 122 // becomes stale and garbage collected). 123 func (it *binaryIterator) Next() bool { 124 if it.aDone && it.bDone { 125 return false 126 } 127 first: 128 if it.aDone { 129 it.k = it.b.Hash() 130 it.bDone = !it.b.Next() 131 return true 132 } 133 if it.bDone { 134 it.k = it.a.Hash() 135 it.aDone = !it.a.Next() 136 return true 137 } 138 nextA, nextB := it.a.Hash(), it.b.Hash() 139 if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 { 140 it.aDone = !it.a.Next() 141 it.k = nextA 142 return true 143 } else if diff == 0 { 144 // Now we need to advance one of them 145 it.aDone = !it.a.Next() 146 goto first 147 } 148 it.bDone = !it.b.Next() 149 it.k = nextB 150 return true 151 } 152 153 // Error returns any failure that occurred during iteration, which might have 154 // caused a premature iteration exit (e.g. snapshot stack becoming stale). 155 func (it *binaryIterator) Error() error { 156 return it.fail 157 } 158 159 // Hash returns the hash of the account the iterator is currently at. 160 func (it *binaryIterator) Hash() common.Hash { 161 return it.k 162 } 163 164 // Account returns the RLP encoded slim account the iterator is currently at, or 165 // nil if the iterated snapshot stack became stale (you can check Error after 166 // to see if it failed or not). 167 // 168 // Note the returned account is not a copy, please don't modify it. 169 func (it *binaryIterator) Account() []byte { 170 if !it.accountIterator { 171 return nil 172 } 173 // The topmost iterator must be `diffAccountIterator` 174 blob, err := it.a.(*diffAccountIterator).layer.AccountRLP(it.k) 175 if err != nil { 176 it.fail = err 177 return nil 178 } 179 return blob 180 } 181 182 // Slot returns the raw storage slot data the iterator is currently at, or 183 // nil if the iterated snapshot stack became stale (you can check Error after 184 // to see if it failed or not). 185 // 186 // Note the returned slot is not a copy, please don't modify it. 187 func (it *binaryIterator) Slot() []byte { 188 if it.accountIterator { 189 return nil 190 } 191 blob, err := it.a.(*diffStorageIterator).layer.Storage(it.account, it.k) 192 if err != nil { 193 it.fail = err 194 return nil 195 } 196 return blob 197 } 198 199 // Release recursively releases all the iterators in the stack. 200 func (it *binaryIterator) Release() { 201 it.a.Release() 202 it.b.Release() 203 } 204 205 // newBinaryAccountIterator creates a simplistic account iterator to step over 206 // all the accounts in a slow, but easily verifiable way. 207 func (dl *diffLayer) newBinaryAccountIterator() AccountIterator { 208 iter := dl.initBinaryAccountIterator() 209 return iter.(AccountIterator) 210 } 211 212 // newBinaryStorageIterator creates a simplistic account iterator to step over 213 // all the storage slots in a slow, but easily verifiable way. 214 func (dl *diffLayer) newBinaryStorageIterator(account common.Hash) StorageIterator { 215 iter := dl.initBinaryStorageIterator(account) 216 return iter.(StorageIterator) 217 }