iterator.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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. package snapshot
  17. import (
  18. "bytes"
  19. "fmt"
  20. "sort"
  21. "github.com/ethereum/go-ethereum/common"
  22. "github.com/ethereum/go-ethereum/core/rawdb"
  23. "github.com/ethereum/go-ethereum/ethdb"
  24. )
  25. // Iterator is an iterator to step over all the accounts or the specific
  26. // storage in a snapshot which may or may not be composed of multiple layers.
  27. type Iterator interface {
  28. // Next steps the iterator forward one element, returning false if exhausted,
  29. // or an error if iteration failed for some reason (e.g. root being iterated
  30. // becomes stale and garbage collected).
  31. Next() bool
  32. // Error returns any failure that occurred during iteration, which might have
  33. // caused a premature iteration exit (e.g. snapshot stack becoming stale).
  34. Error() error
  35. // Hash returns the hash of the account or storage slot the iterator is
  36. // currently at.
  37. Hash() common.Hash
  38. // Release releases associated resources. Release should always succeed and
  39. // can be called multiple times without causing error.
  40. Release()
  41. }
  42. // AccountIterator is an iterator to step over all the accounts in a snapshot,
  43. // which may or may not be composed of multiple layers.
  44. type AccountIterator interface {
  45. Iterator
  46. // Account returns the RLP encoded slim account the iterator is currently at.
  47. // An error will be returned if the iterator becomes invalid
  48. Account() []byte
  49. }
  50. // StorageIterator is an iterator to step over the specific storage in a snapshot,
  51. // which may or may not be composed of multiple layers.
  52. type StorageIterator interface {
  53. Iterator
  54. // Slot returns the storage slot the iterator is currently at. An error will
  55. // be returned if the iterator becomes invalid
  56. Slot() []byte
  57. }
  58. // diffAccountIterator is an account iterator that steps over the accounts (both
  59. // live and deleted) contained within a single diff layer. Higher order iterators
  60. // will use the deleted accounts to skip deeper iterators.
  61. type diffAccountIterator struct {
  62. // curHash is the current hash the iterator is positioned on. The field is
  63. // explicitly tracked since the referenced diff layer might go stale after
  64. // the iterator was positioned and we don't want to fail accessing the old
  65. // hash as long as the iterator is not touched any more.
  66. curHash common.Hash
  67. layer *diffLayer // Live layer to retrieve values from
  68. keys []common.Hash // Keys left in the layer to iterate
  69. fail error // Any failures encountered (stale)
  70. }
  71. // AccountIterator creates an account iterator over a single diff layer.
  72. func (dl *diffLayer) AccountIterator(seek common.Hash) AccountIterator {
  73. // Seek out the requested starting account
  74. hashes := dl.AccountList()
  75. index := sort.Search(len(hashes), func(i int) bool {
  76. return bytes.Compare(seek[:], hashes[i][:]) <= 0
  77. })
  78. // Assemble and returned the already seeked iterator
  79. return &diffAccountIterator{
  80. layer: dl,
  81. keys: hashes[index:],
  82. }
  83. }
  84. // Next steps the iterator forward one element, returning false if exhausted.
  85. func (it *diffAccountIterator) Next() bool {
  86. // If the iterator was already stale, consider it a programmer error. Although
  87. // we could just return false here, triggering this path would probably mean
  88. // somebody forgot to check for Error, so lets blow up instead of undefined
  89. // behavior that's hard to debug.
  90. if it.fail != nil {
  91. panic(fmt.Sprintf("called Next of failed iterator: %v", it.fail))
  92. }
  93. // Stop iterating if all keys were exhausted
  94. if len(it.keys) == 0 {
  95. return false
  96. }
  97. if it.layer.Stale() {
  98. it.fail, it.keys = ErrSnapshotStale, nil
  99. return false
  100. }
  101. // Iterator seems to be still alive, retrieve and cache the live hash
  102. it.curHash = it.keys[0]
  103. // key cached, shift the iterator and notify the user of success
  104. it.keys = it.keys[1:]
  105. return true
  106. }
  107. // Error returns any failure that occurred during iteration, which might have
  108. // caused a premature iteration exit (e.g. snapshot stack becoming stale).
  109. func (it *diffAccountIterator) Error() error {
  110. return it.fail
  111. }
  112. // Hash returns the hash of the account the iterator is currently at.
  113. func (it *diffAccountIterator) Hash() common.Hash {
  114. return it.curHash
  115. }
  116. // Account returns the RLP encoded slim account the iterator is currently at.
  117. // This method may _fail_, if the underlying layer has been flattened between
  118. // the call to Next and Account. That type of error will set it.Err.
  119. // This method assumes that flattening does not delete elements from
  120. // the accountdata mapping (writing nil into it is fine though), and will panic
  121. // if elements have been deleted.
  122. //
  123. // Note the returned account is not a copy, please don't modify it.
  124. func (it *diffAccountIterator) Account() []byte {
  125. it.layer.lock.RLock()
  126. blob, ok := it.layer.accountData[it.curHash]
  127. if !ok {
  128. if _, ok := it.layer.destructSet[it.curHash]; ok {
  129. it.layer.lock.RUnlock()
  130. return nil
  131. }
  132. panic(fmt.Sprintf("iterator referenced non-existent account: %x", it.curHash))
  133. }
  134. it.layer.lock.RUnlock()
  135. if it.layer.Stale() {
  136. it.fail, it.keys = ErrSnapshotStale, nil
  137. }
  138. return blob
  139. }
  140. // Release is a noop for diff account iterators as there are no held resources.
  141. func (it *diffAccountIterator) Release() {}
  142. // diskAccountIterator is an account iterator that steps over the live accounts
  143. // contained within a disk layer.
  144. type diskAccountIterator struct {
  145. layer *diskLayer
  146. it ethdb.Iterator
  147. }
  148. // AccountIterator creates an account iterator over a disk layer.
  149. func (dl *diskLayer) AccountIterator(seek common.Hash) AccountIterator {
  150. pos := common.TrimRightZeroes(seek[:])
  151. return &diskAccountIterator{
  152. layer: dl,
  153. it: dl.diskdb.NewIterator(rawdb.SnapshotAccountPrefix, pos),
  154. }
  155. }
  156. // Next steps the iterator forward one element, returning false if exhausted.
  157. func (it *diskAccountIterator) Next() bool {
  158. // If the iterator was already exhausted, don't bother
  159. if it.it == nil {
  160. return false
  161. }
  162. // Try to advance the iterator and release it if we reached the end
  163. for {
  164. if !it.it.Next() {
  165. it.it.Release()
  166. it.it = nil
  167. return false
  168. }
  169. if len(it.it.Key()) == len(rawdb.SnapshotAccountPrefix)+common.HashLength {
  170. break
  171. }
  172. }
  173. return true
  174. }
  175. // Error returns any failure that occurred during iteration, which might have
  176. // caused a premature iteration exit (e.g. snapshot stack becoming stale).
  177. //
  178. // A diff layer is immutable after creation content wise and can always be fully
  179. // iterated without error, so this method always returns nil.
  180. func (it *diskAccountIterator) Error() error {
  181. if it.it == nil {
  182. return nil // Iterator is exhausted and released
  183. }
  184. return it.it.Error()
  185. }
  186. // Hash returns the hash of the account the iterator is currently at.
  187. func (it *diskAccountIterator) Hash() common.Hash {
  188. return common.BytesToHash(it.it.Key()) // The prefix will be truncated
  189. }
  190. // Account returns the RLP encoded slim account the iterator is currently at.
  191. func (it *diskAccountIterator) Account() []byte {
  192. return it.it.Value()
  193. }
  194. // Release releases the database snapshot held during iteration.
  195. func (it *diskAccountIterator) Release() {
  196. // The iterator is auto-released on exhaustion, so make sure it's still alive
  197. if it.it != nil {
  198. it.it.Release()
  199. it.it = nil
  200. }
  201. }
  202. // diffStorageIterator is a storage iterator that steps over the specific storage
  203. // (both live and deleted) contained within a single diff layer. Higher order
  204. // iterators will use the deleted slot to skip deeper iterators.
  205. type diffStorageIterator struct {
  206. // curHash is the current hash the iterator is positioned on. The field is
  207. // explicitly tracked since the referenced diff layer might go stale after
  208. // the iterator was positioned and we don't want to fail accessing the old
  209. // hash as long as the iterator is not touched any more.
  210. curHash common.Hash
  211. account common.Hash
  212. layer *diffLayer // Live layer to retrieve values from
  213. keys []common.Hash // Keys left in the layer to iterate
  214. fail error // Any failures encountered (stale)
  215. }
  216. // StorageIterator creates a storage iterator over a single diff layer.
  217. // Except the storage iterator is returned, there is an additional flag
  218. // "destructed" returned. If it's true then it means the whole storage is
  219. // destructed in this layer(maybe recreated too), don't bother deeper layer
  220. // for storage retrieval.
  221. func (dl *diffLayer) StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) {
  222. // Create the storage for this account even it's marked
  223. // as destructed. The iterator is for the new one which
  224. // just has the same address as the deleted one.
  225. hashes, destructed := dl.StorageList(account)
  226. index := sort.Search(len(hashes), func(i int) bool {
  227. return bytes.Compare(seek[:], hashes[i][:]) <= 0
  228. })
  229. // Assemble and returned the already seeked iterator
  230. return &diffStorageIterator{
  231. layer: dl,
  232. account: account,
  233. keys: hashes[index:],
  234. }, destructed
  235. }
  236. // Next steps the iterator forward one element, returning false if exhausted.
  237. func (it *diffStorageIterator) Next() bool {
  238. // If the iterator was already stale, consider it a programmer error. Although
  239. // we could just return false here, triggering this path would probably mean
  240. // somebody forgot to check for Error, so lets blow up instead of undefined
  241. // behavior that's hard to debug.
  242. if it.fail != nil {
  243. panic(fmt.Sprintf("called Next of failed iterator: %v", it.fail))
  244. }
  245. // Stop iterating if all keys were exhausted
  246. if len(it.keys) == 0 {
  247. return false
  248. }
  249. if it.layer.Stale() {
  250. it.fail, it.keys = ErrSnapshotStale, nil
  251. return false
  252. }
  253. // Iterator seems to be still alive, retrieve and cache the live hash
  254. it.curHash = it.keys[0]
  255. // key cached, shift the iterator and notify the user of success
  256. it.keys = it.keys[1:]
  257. return true
  258. }
  259. // Error returns any failure that occurred during iteration, which might have
  260. // caused a premature iteration exit (e.g. snapshot stack becoming stale).
  261. func (it *diffStorageIterator) Error() error {
  262. return it.fail
  263. }
  264. // Hash returns the hash of the storage slot the iterator is currently at.
  265. func (it *diffStorageIterator) Hash() common.Hash {
  266. return it.curHash
  267. }
  268. // Slot returns the raw storage slot value the iterator is currently at.
  269. // This method may _fail_, if the underlying layer has been flattened between
  270. // the call to Next and Value. That type of error will set it.Err.
  271. // This method assumes that flattening does not delete elements from
  272. // the storage mapping (writing nil into it is fine though), and will panic
  273. // if elements have been deleted.
  274. //
  275. // Note the returned slot is not a copy, please don't modify it.
  276. func (it *diffStorageIterator) Slot() []byte {
  277. it.layer.lock.RLock()
  278. storage, ok := it.layer.storageData[it.account]
  279. if !ok {
  280. panic(fmt.Sprintf("iterator referenced non-existent account storage: %x", it.account))
  281. }
  282. // Storage slot might be nil(deleted), but it must exist
  283. blob, ok := storage[it.curHash]
  284. if !ok {
  285. panic(fmt.Sprintf("iterator referenced non-existent storage slot: %x", it.curHash))
  286. }
  287. it.layer.lock.RUnlock()
  288. if it.layer.Stale() {
  289. it.fail, it.keys = ErrSnapshotStale, nil
  290. }
  291. return blob
  292. }
  293. // Release is a noop for diff account iterators as there are no held resources.
  294. func (it *diffStorageIterator) Release() {}
  295. // diskStorageIterator is a storage iterator that steps over the live storage
  296. // contained within a disk layer.
  297. type diskStorageIterator struct {
  298. layer *diskLayer
  299. account common.Hash
  300. it ethdb.Iterator
  301. }
  302. // StorageIterator creates a storage iterator over a disk layer.
  303. // If the whole storage is destructed, then all entries in the disk
  304. // layer are deleted already. So the "destructed" flag returned here
  305. // is always false.
  306. func (dl *diskLayer) StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) {
  307. pos := common.TrimRightZeroes(seek[:])
  308. return &diskStorageIterator{
  309. layer: dl,
  310. account: account,
  311. it: dl.diskdb.NewIterator(append(rawdb.SnapshotStoragePrefix, account.Bytes()...), pos),
  312. }, false
  313. }
  314. // Next steps the iterator forward one element, returning false if exhausted.
  315. func (it *diskStorageIterator) Next() bool {
  316. // If the iterator was already exhausted, don't bother
  317. if it.it == nil {
  318. return false
  319. }
  320. // Try to advance the iterator and release it if we reached the end
  321. for {
  322. if !it.it.Next() {
  323. it.it.Release()
  324. it.it = nil
  325. return false
  326. }
  327. if len(it.it.Key()) == len(rawdb.SnapshotStoragePrefix)+common.HashLength+common.HashLength {
  328. break
  329. }
  330. }
  331. return true
  332. }
  333. // Error returns any failure that occurred during iteration, which might have
  334. // caused a premature iteration exit (e.g. snapshot stack becoming stale).
  335. //
  336. // A diff layer is immutable after creation content wise and can always be fully
  337. // iterated without error, so this method always returns nil.
  338. func (it *diskStorageIterator) Error() error {
  339. if it.it == nil {
  340. return nil // Iterator is exhausted and released
  341. }
  342. return it.it.Error()
  343. }
  344. // Hash returns the hash of the storage slot the iterator is currently at.
  345. func (it *diskStorageIterator) Hash() common.Hash {
  346. return common.BytesToHash(it.it.Key()) // The prefix will be truncated
  347. }
  348. // Slot returns the raw strorage slot content the iterator is currently at.
  349. func (it *diskStorageIterator) Slot() []byte {
  350. return it.it.Value()
  351. }
  352. // Release releases the database snapshot held during iteration.
  353. func (it *diskStorageIterator) Release() {
  354. // The iterator is auto-released on exhaustion, so make sure it's still alive
  355. if it.it != nil {
  356. it.it.Release()
  357. it.it = nil
  358. }
  359. }