iterator_binary.go 6.31 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// 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"
)

25 26
// 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
27
// wise this iterator is slow, it's meant for cross validating the fast one,
28 29 30 31 32 33 34 35 36
type binaryIterator struct {
	a               Iterator
	b               Iterator
	aDone           bool
	bDone           bool
	accountIterator bool
	k               common.Hash
	account         common.Hash
	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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
// 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
65
// storage slots in a slow, but easily verifiable way. Note this function is used
66 67
// for initialization, use `newBinaryStorageIterator` as the API.
func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator {
68 69
	parent, ok := dl.parent.(*diffLayer)
	if !ok {
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
		// 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,
89 90 91 92
		}
		l.aDone = !l.a.Next()
		l.bDone = !l.b.Next()
		return l
93
	}
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
	// 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,
110 111 112 113 114 115 116 117 118
	}
	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).
119
func (it *binaryIterator) Next() bool {
120 121 122 123 124
	if it.aDone && it.bDone {
		return false
	}
first:
	if it.aDone {
125
		it.k = it.b.Hash()
126 127 128 129
		it.bDone = !it.b.Next()
		return true
	}
	if it.bDone {
130
		it.k = it.a.Hash()
131 132 133
		it.aDone = !it.a.Next()
		return true
	}
134
	nextA, nextB := it.a.Hash(), it.b.Hash()
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
	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).
151
func (it *binaryIterator) Error() error {
152 153 154
	return it.fail
}

155
// Hash returns the hash of the account the iterator is currently at.
156
func (it *binaryIterator) Hash() common.Hash {
157 158 159
	return it.k
}

160
// Account returns the RLP encoded slim account the iterator is currently at, or
161 162
// nil if the iterated snapshot stack became stale (you can check Error after
// to see if it failed or not).
163 164 165 166 167 168
//
// Note the returned account is not a copy, please don't modify it.
func (it *binaryIterator) Account() []byte {
	if !it.accountIterator {
		return nil
	}
169 170
	// The topmost iterator must be `diffAccountIterator`
	blob, err := it.a.(*diffAccountIterator).layer.AccountRLP(it.k)
171 172 173 174 175 176
	if err != nil {
		it.fail = err
		return nil
	}
	return blob
}
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
// 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
}

195
// Release recursively releases all the iterators in the stack.
196
func (it *binaryIterator) Release() {
197 198 199
	it.a.Release()
	it.b.Release()
}
200 201

// newBinaryAccountIterator creates a simplistic account iterator to step over
202
// all the accounts in a slow, but easily verifiable way.
203 204 205 206 207 208
func (dl *diffLayer) newBinaryAccountIterator() AccountIterator {
	iter := dl.initBinaryAccountIterator()
	return iter.(AccountIterator)
}

// newBinaryStorageIterator creates a simplistic account iterator to step over
209
// all the storage slots in a slow, but easily verifiable way.
210 211 212 213
func (dl *diffLayer) newBinaryStorageIterator(account common.Hash) StorageIterator {
	iter := dl.initBinaryStorageIterator(account)
	return iter.(StorageIterator)
}