gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/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  // binaryAccountIterator is a simplistic iterator to step over the accounts in
    26  // a snapshot, which may or may npt be composed of multiple layers. Performance
    27  // wise this iterator is slow, it's meant for cross validating the fast one,
    28  type binaryAccountIterator struct {
    29  	a     *diffAccountIterator
    30  	b     AccountIterator
    31  	aDone bool
    32  	bDone bool
    33  	k     common.Hash
    34  	fail  error
    35  }
    36  
    37  // newBinaryAccountIterator creates a simplistic account iterator to step over
    38  // all the accounts in a slow, but eaily verifiable way.
    39  func (dl *diffLayer) newBinaryAccountIterator() AccountIterator {
    40  	parent, ok := dl.parent.(*diffLayer)
    41  	if !ok {
    42  		// parent is the disk layer
    43  		return dl.AccountIterator(common.Hash{})
    44  	}
    45  	l := &binaryAccountIterator{
    46  		a: dl.AccountIterator(common.Hash{}).(*diffAccountIterator),
    47  		b: parent.newBinaryAccountIterator(),
    48  	}
    49  	l.aDone = !l.a.Next()
    50  	l.bDone = !l.b.Next()
    51  	return l
    52  }
    53  
    54  // Next steps the iterator forward one element, returning false if exhausted,
    55  // or an error if iteration failed for some reason (e.g. root being iterated
    56  // becomes stale and garbage collected).
    57  func (it *binaryAccountIterator) Next() bool {
    58  	if it.aDone && it.bDone {
    59  		return false
    60  	}
    61  	nextB := it.b.Hash()
    62  first:
    63  	nextA := it.a.Hash()
    64  	if it.aDone {
    65  		it.bDone = !it.b.Next()
    66  		it.k = nextB
    67  		return true
    68  	}
    69  	if it.bDone {
    70  		it.aDone = !it.a.Next()
    71  		it.k = nextA
    72  		return true
    73  	}
    74  	if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 {
    75  		it.aDone = !it.a.Next()
    76  		it.k = nextA
    77  		return true
    78  	} else if diff == 0 {
    79  		// Now we need to advance one of them
    80  		it.aDone = !it.a.Next()
    81  		goto first
    82  	}
    83  	it.bDone = !it.b.Next()
    84  	it.k = nextB
    85  	return true
    86  }
    87  
    88  // Error returns any failure that occurred during iteration, which might have
    89  // caused a premature iteration exit (e.g. snapshot stack becoming stale).
    90  func (it *binaryAccountIterator) Error() error {
    91  	return it.fail
    92  }
    93  
    94  // Hash returns the hash of the account the iterator is currently at.
    95  func (it *binaryAccountIterator) Hash() common.Hash {
    96  	return it.k
    97  }
    98  
    99  // Account returns the RLP encoded slim account the iterator is currently at, or
   100  // nil if the iterated snapshot stack became stale (you can check Error after
   101  // to see if it failed or not).
   102  func (it *binaryAccountIterator) Account() []byte {
   103  	blob, err := it.a.layer.AccountRLP(it.k)
   104  	if err != nil {
   105  		it.fail = err
   106  		return nil
   107  	}
   108  	return blob
   109  }
   110  
   111  // Release recursively releases all the iterators in the stack.
   112  func (it *binaryAccountIterator) Release() {
   113  	it.a.Release()
   114  	it.b.Release()
   115  }