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  }