github.com/dim4egster/coreth@v0.10.2/core/state/snapshot/iterator_binary.go (about)

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