214 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2019 The go-ethereum Authors
 | 
						|
// This file is part of the go-ethereum library.
 | 
						|
//
 | 
						|
// The go-ethereum library is free software: you can redistribute it and/or modify
 | 
						|
// it under the terms of the GNU Lesser General Public License as published by
 | 
						|
// the Free Software Foundation, either version 3 of the License, or
 | 
						|
// (at your option) any later version.
 | 
						|
//
 | 
						|
// The go-ethereum library is distributed in the hope that it will be useful,
 | 
						|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
						|
// GNU Lesser General Public License for more details.
 | 
						|
//
 | 
						|
// You should have received a copy of the GNU Lesser General Public License
 | 
						|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
package snapshot
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
 | 
						|
	"github.com/ethereum/go-ethereum/common"
 | 
						|
)
 | 
						|
 | 
						|
// binaryIterator is a simplistic iterator to step over the accounts or storage
 | 
						|
// in a snapshot, which may or may not be composed of multiple layers. Performance
 | 
						|
// wise this iterator is slow, it's meant for cross validating the fast one,
 | 
						|
type binaryIterator struct {
 | 
						|
	a               Iterator
 | 
						|
	b               Iterator
 | 
						|
	aDone           bool
 | 
						|
	bDone           bool
 | 
						|
	accountIterator bool
 | 
						|
	k               common.Hash
 | 
						|
	account         common.Hash
 | 
						|
	fail            error
 | 
						|
}
 | 
						|
 | 
						|
// initBinaryAccountIterator creates a simplistic iterator to step over all the
 | 
						|
// accounts in a slow, but easily verifiable way. Note this function is used for
 | 
						|
// initialization, use `newBinaryAccountIterator` as the API.
 | 
						|
func (dl *diffLayer) initBinaryAccountIterator() Iterator {
 | 
						|
	parent, ok := dl.parent.(*diffLayer)
 | 
						|
	if !ok {
 | 
						|
		l := &binaryIterator{
 | 
						|
			a:               dl.AccountIterator(common.Hash{}),
 | 
						|
			b:               dl.Parent().AccountIterator(common.Hash{}),
 | 
						|
			accountIterator: true,
 | 
						|
		}
 | 
						|
		l.aDone = !l.a.Next()
 | 
						|
		l.bDone = !l.b.Next()
 | 
						|
		return l
 | 
						|
	}
 | 
						|
	l := &binaryIterator{
 | 
						|
		a:               dl.AccountIterator(common.Hash{}),
 | 
						|
		b:               parent.initBinaryAccountIterator(),
 | 
						|
		accountIterator: true,
 | 
						|
	}
 | 
						|
	l.aDone = !l.a.Next()
 | 
						|
	l.bDone = !l.b.Next()
 | 
						|
	return l
 | 
						|
}
 | 
						|
 | 
						|
// initBinaryStorageIterator creates a simplistic iterator to step over all the
 | 
						|
// storage slots in a slow, but easily verifiable way. Note this function is used
 | 
						|
// for initialization, use `newBinaryStorageIterator` as the API.
 | 
						|
func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator {
 | 
						|
	parent, ok := dl.parent.(*diffLayer)
 | 
						|
	if !ok {
 | 
						|
		// If the storage in this layer is already destructed, discard all
 | 
						|
		// deeper layers but still return an valid single-branch iterator.
 | 
						|
		a, destructed := dl.StorageIterator(account, common.Hash{})
 | 
						|
		if destructed {
 | 
						|
			l := &binaryIterator{
 | 
						|
				a:       a,
 | 
						|
				account: account,
 | 
						|
			}
 | 
						|
			l.aDone = !l.a.Next()
 | 
						|
			l.bDone = true
 | 
						|
			return l
 | 
						|
		}
 | 
						|
		// The parent is disk layer, don't need to take care "destructed"
 | 
						|
		// anymore.
 | 
						|
		b, _ := dl.Parent().StorageIterator(account, common.Hash{})
 | 
						|
		l := &binaryIterator{
 | 
						|
			a:       a,
 | 
						|
			b:       b,
 | 
						|
			account: account,
 | 
						|
		}
 | 
						|
		l.aDone = !l.a.Next()
 | 
						|
		l.bDone = !l.b.Next()
 | 
						|
		return l
 | 
						|
	}
 | 
						|
	// If the storage in this layer is already destructed, discard all
 | 
						|
	// deeper layers but still return an valid single-branch iterator.
 | 
						|
	a, destructed := dl.StorageIterator(account, common.Hash{})
 | 
						|
	if destructed {
 | 
						|
		l := &binaryIterator{
 | 
						|
			a:       a,
 | 
						|
			account: account,
 | 
						|
		}
 | 
						|
		l.aDone = !l.a.Next()
 | 
						|
		l.bDone = true
 | 
						|
		return l
 | 
						|
	}
 | 
						|
	l := &binaryIterator{
 | 
						|
		a:       a,
 | 
						|
		b:       parent.initBinaryStorageIterator(account),
 | 
						|
		account: account,
 | 
						|
	}
 | 
						|
	l.aDone = !l.a.Next()
 | 
						|
	l.bDone = !l.b.Next()
 | 
						|
	return l
 | 
						|
}
 | 
						|
 | 
						|
// Next steps the iterator forward one element, returning false if exhausted,
 | 
						|
// or an error if iteration failed for some reason (e.g. root being iterated
 | 
						|
// becomes stale and garbage collected).
 | 
						|
func (it *binaryIterator) Next() bool {
 | 
						|
	if it.aDone && it.bDone {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
first:
 | 
						|
	if it.aDone {
 | 
						|
		it.k = it.b.Hash()
 | 
						|
		it.bDone = !it.b.Next()
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	if it.bDone {
 | 
						|
		it.k = it.a.Hash()
 | 
						|
		it.aDone = !it.a.Next()
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	nextA, nextB := it.a.Hash(), it.b.Hash()
 | 
						|
	if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 {
 | 
						|
		it.aDone = !it.a.Next()
 | 
						|
		it.k = nextA
 | 
						|
		return true
 | 
						|
	} else if diff == 0 {
 | 
						|
		// Now we need to advance one of them
 | 
						|
		it.aDone = !it.a.Next()
 | 
						|
		goto first
 | 
						|
	}
 | 
						|
	it.bDone = !it.b.Next()
 | 
						|
	it.k = nextB
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
// Error returns any failure that occurred during iteration, which might have
 | 
						|
// caused a premature iteration exit (e.g. snapshot stack becoming stale).
 | 
						|
func (it *binaryIterator) Error() error {
 | 
						|
	return it.fail
 | 
						|
}
 | 
						|
 | 
						|
// Hash returns the hash of the account the iterator is currently at.
 | 
						|
func (it *binaryIterator) Hash() common.Hash {
 | 
						|
	return it.k
 | 
						|
}
 | 
						|
 | 
						|
// Account returns the RLP encoded slim account the iterator is currently at, or
 | 
						|
// nil if the iterated snapshot stack became stale (you can check Error after
 | 
						|
// to see if it failed or not).
 | 
						|
//
 | 
						|
// Note the returned account is not a copy, please don't modify it.
 | 
						|
func (it *binaryIterator) Account() []byte {
 | 
						|
	if !it.accountIterator {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	// The topmost iterator must be `diffAccountIterator`
 | 
						|
	blob, err := it.a.(*diffAccountIterator).layer.AccountRLP(it.k)
 | 
						|
	if err != nil {
 | 
						|
		it.fail = err
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	return blob
 | 
						|
}
 | 
						|
 | 
						|
// Slot returns the raw storage slot data the iterator is currently at, or
 | 
						|
// nil if the iterated snapshot stack became stale (you can check Error after
 | 
						|
// to see if it failed or not).
 | 
						|
//
 | 
						|
// Note the returned slot is not a copy, please don't modify it.
 | 
						|
func (it *binaryIterator) Slot() []byte {
 | 
						|
	if it.accountIterator {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	blob, err := it.a.(*diffStorageIterator).layer.Storage(it.account, it.k)
 | 
						|
	if err != nil {
 | 
						|
		it.fail = err
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	return blob
 | 
						|
}
 | 
						|
 | 
						|
// Release recursively releases all the iterators in the stack.
 | 
						|
func (it *binaryIterator) Release() {
 | 
						|
	it.a.Release()
 | 
						|
	it.b.Release()
 | 
						|
}
 | 
						|
 | 
						|
// newBinaryAccountIterator creates a simplistic account iterator to step over
 | 
						|
// all the accounts in a slow, but easily verifiable way.
 | 
						|
func (dl *diffLayer) newBinaryAccountIterator() AccountIterator {
 | 
						|
	iter := dl.initBinaryAccountIterator()
 | 
						|
	return iter.(AccountIterator)
 | 
						|
}
 | 
						|
 | 
						|
// newBinaryStorageIterator creates a simplistic account iterator to step over
 | 
						|
// all the storage slots in a slow, but easily verifiable way.
 | 
						|
func (dl *diffLayer) newBinaryStorageIterator(account common.Hash) StorageIterator {
 | 
						|
	iter := dl.initBinaryStorageIterator(account)
 | 
						|
	return iter.(StorageIterator)
 | 
						|
}
 |