github.com/klaytn/klaytn@v1.12.1/snapshot/iterator_binary.go (about)

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