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