Skip to content

Commit 5552734

Browse files
Arachnidfjl
authored andcommitted
trie: add difference iterator (ethereum#3637)
This PR implements a differenceIterator, which allows iterating over trie nodes that exist in one trie but not in another. This is a prerequisite for most GC strategies, in order to find obsolete nodes.
1 parent 024d41d commit 5552734

File tree

5 files changed

+327
-130
lines changed

5 files changed

+327
-130
lines changed

core/state/iterator.go

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,14 @@ import (
3131
type NodeIterator struct {
3232
state *StateDB // State being iterated
3333

34-
stateIt *trie.NodeIterator // Primary iterator for the global state trie
35-
dataIt *trie.NodeIterator // Secondary iterator for the data trie of a contract
34+
stateIt trie.NodeIterator // Primary iterator for the global state trie
35+
dataIt trie.NodeIterator // Secondary iterator for the data trie of a contract
3636

3737
accountHash common.Hash // Hash of the node containing the account
3838
codeHash common.Hash // Hash of the contract source code
3939
code []byte // Source code associated with a contract
4040

4141
Hash common.Hash // Hash of the current entry being iterated (nil if not standalone)
42-
Entry interface{} // Current state entry being iterated (internal representation)
4342
Parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
4443

4544
Error error // Failure set in case of an internal error in the iterator
@@ -80,9 +79,9 @@ func (it *NodeIterator) step() error {
8079
}
8180
// If we had data nodes previously, we surely have at least state nodes
8281
if it.dataIt != nil {
83-
if cont := it.dataIt.Next(); !cont {
84-
if it.dataIt.Error != nil {
85-
return it.dataIt.Error
82+
if cont := it.dataIt.Next(true); !cont {
83+
if it.dataIt.Error() != nil {
84+
return it.dataIt.Error()
8685
}
8786
it.dataIt = nil
8887
}
@@ -94,15 +93,15 @@ func (it *NodeIterator) step() error {
9493
return nil
9594
}
9695
// Step to the next state trie node, terminating if we're out of nodes
97-
if cont := it.stateIt.Next(); !cont {
98-
if it.stateIt.Error != nil {
99-
return it.stateIt.Error
96+
if cont := it.stateIt.Next(true); !cont {
97+
if it.stateIt.Error() != nil {
98+
return it.stateIt.Error()
10099
}
101100
it.state, it.stateIt = nil, nil
102101
return nil
103102
}
104103
// If the state trie node is an internal entry, leave as is
105-
if !it.stateIt.Leaf {
104+
if !it.stateIt.Leaf() {
106105
return nil
107106
}
108107
// Otherwise we've reached an account node, initiate data iteration
@@ -112,15 +111,15 @@ func (it *NodeIterator) step() error {
112111
Root common.Hash
113112
CodeHash []byte
114113
}
115-
if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob), &account); err != nil {
114+
if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob()), &account); err != nil {
116115
return err
117116
}
118117
dataTrie, err := trie.New(account.Root, it.state.db)
119118
if err != nil {
120119
return err
121120
}
122121
it.dataIt = trie.NewNodeIterator(dataTrie)
123-
if !it.dataIt.Next() {
122+
if !it.dataIt.Next(true) {
124123
it.dataIt = nil
125124
}
126125
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
@@ -130,15 +129,15 @@ func (it *NodeIterator) step() error {
130129
return fmt.Errorf("code %x: %v", account.CodeHash, err)
131130
}
132131
}
133-
it.accountHash = it.stateIt.Parent
132+
it.accountHash = it.stateIt.Parent()
134133
return nil
135134
}
136135

137136
// retrieve pulls and caches the current state entry the iterator is traversing.
138137
// The method returns whether there are any more data left for inspection.
139138
func (it *NodeIterator) retrieve() bool {
140139
// Clear out any previously set values
141-
it.Hash, it.Entry = common.Hash{}, nil
140+
it.Hash = common.Hash{}
142141

143142
// If the iteration's done, return no available data
144143
if it.state == nil {
@@ -147,14 +146,14 @@ func (it *NodeIterator) retrieve() bool {
147146
// Otherwise retrieve the current entry
148147
switch {
149148
case it.dataIt != nil:
150-
it.Hash, it.Entry, it.Parent = it.dataIt.Hash, it.dataIt.Node, it.dataIt.Parent
149+
it.Hash, it.Parent = it.dataIt.Hash(), it.dataIt.Parent()
151150
if it.Parent == (common.Hash{}) {
152151
it.Parent = it.accountHash
153152
}
154153
case it.code != nil:
155-
it.Hash, it.Entry, it.Parent = it.codeHash, it.code, it.accountHash
154+
it.Hash, it.Parent = it.codeHash, it.accountHash
156155
case it.stateIt != nil:
157-
it.Hash, it.Entry, it.Parent = it.stateIt.Hash, it.stateIt.Node, it.stateIt.Parent
156+
it.Hash, it.Parent = it.stateIt.Hash(), it.stateIt.Parent()
158157
}
159158
return true
160159
}

0 commit comments

Comments
 (0)