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