Skip to content

Commit 5130362

Browse files
authored
push missing verkle iterator files (#550)
1 parent dfb1158 commit 5130362

File tree

2 files changed

+288
-0
lines changed

2 files changed

+288
-0
lines changed

trie/verkle_iterator.go

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
// Copyright 2021 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 trie
18+
19+
import (
20+
"github.com/ethereum/go-ethereum/common"
21+
22+
"github.com/ethereum/go-verkle"
23+
)
24+
25+
type verkleNodeIteratorState struct {
26+
Node verkle.VerkleNode
27+
Index int // points to _next_ value
28+
}
29+
30+
type verkleNodeIterator struct {
31+
trie *VerkleTrie
32+
current verkle.VerkleNode
33+
lastErr error
34+
35+
stack []verkleNodeIteratorState
36+
}
37+
38+
func newVerkleNodeIterator(trie *VerkleTrie, _ []byte) (NodeIterator, error) {
39+
if trie.Hash() == (common.Hash{}) {
40+
return new(nodeIterator), nil
41+
}
42+
it := &verkleNodeIterator{trie: trie, current: trie.root}
43+
// it.err = it.seek(start)
44+
return it, nil
45+
}
46+
47+
// Next moves the iterator to the next node. If the parameter is false, any child
48+
// nodes will be skipped.
49+
func (it *verkleNodeIterator) Next(descend bool) bool {
50+
if it.lastErr == errIteratorEnd {
51+
it.lastErr = errIteratorEnd
52+
return false
53+
}
54+
55+
if len(it.stack) == 0 {
56+
it.stack = append(it.stack, verkleNodeIteratorState{Node: it.trie.root, Index: 0})
57+
it.current = it.trie.root
58+
59+
return true
60+
}
61+
62+
switch node := it.current.(type) {
63+
case *verkle.InternalNode:
64+
context := &it.stack[len(it.stack)-1]
65+
66+
// Look for the next non-empty child
67+
children := node.Children()
68+
for ; context.Index < len(children); context.Index++ {
69+
if _, ok := children[context.Index].(verkle.Empty); !ok {
70+
it.stack = append(it.stack, verkleNodeIteratorState{Node: children[context.Index], Index: 0})
71+
it.current = children[context.Index]
72+
return it.Next(descend)
73+
}
74+
}
75+
76+
// Reached the end of this node, go back to the parent, if
77+
// this isn't root.
78+
if len(it.stack) == 1 {
79+
it.lastErr = errIteratorEnd
80+
return false
81+
}
82+
it.stack = it.stack[:len(it.stack)-1]
83+
it.current = it.stack[len(it.stack)-1].Node
84+
it.stack[len(it.stack)-1].Index++
85+
return it.Next(descend)
86+
case *verkle.LeafNode:
87+
// Look for the next non-empty value
88+
for i := it.stack[len(it.stack)-1].Index; i < 256; i++ {
89+
if node.Value(i) != nil {
90+
it.stack[len(it.stack)-1].Index = i + 1
91+
return true
92+
}
93+
}
94+
95+
// go back to parent to get the next leaf
96+
it.stack = it.stack[:len(it.stack)-1]
97+
it.current = it.stack[len(it.stack)-1].Node
98+
it.stack[len(it.stack)-1].Index++
99+
return it.Next(descend)
100+
case verkle.HashedNode:
101+
// resolve the node
102+
data, err := it.trie.reader.node(it.Path(), common.Hash{})
103+
if err != nil {
104+
panic(err)
105+
}
106+
it.current, err = verkle.ParseNode(data, byte(len(it.stack)-1))
107+
if err != nil {
108+
panic(err)
109+
}
110+
111+
// update the stack and parent with the resolved node
112+
it.stack[len(it.stack)-1].Node = it.current
113+
parent := &it.stack[len(it.stack)-2]
114+
parent.Node.(*verkle.InternalNode).SetChild(parent.Index, it.current)
115+
return it.Next(true)
116+
default:
117+
panic("invalid node type")
118+
}
119+
}
120+
121+
// Error returns the error status of the iterator.
122+
func (it *verkleNodeIterator) Error() error {
123+
if it.lastErr == errIteratorEnd {
124+
return nil
125+
}
126+
return it.lastErr
127+
}
128+
129+
// Hash returns the hash of the current node.
130+
func (it *verkleNodeIterator) Hash() common.Hash {
131+
return it.current.Commit().Bytes()
132+
}
133+
134+
// Parent returns the hash of the parent of the current node. The hash may be the one
135+
// grandparent if the immediate parent is an internal node with no hash.
136+
func (it *verkleNodeIterator) Parent() common.Hash {
137+
return it.stack[len(it.stack)-1].Node.Commit().Bytes()
138+
}
139+
140+
// Path returns the hex-encoded path to the current node.
141+
// Callers must not retain references to the return value after calling Next.
142+
// For leaf nodes, the last element of the path is the 'terminator symbol' 0x10.
143+
func (it *verkleNodeIterator) Path() []byte {
144+
if it.Leaf() {
145+
return it.LeafKey()
146+
}
147+
var path []byte
148+
for i, state := range it.stack {
149+
// skip the last byte
150+
if i >= len(it.stack)-1 {
151+
break
152+
}
153+
path = append(path, byte(state.Index))
154+
}
155+
return path
156+
}
157+
158+
func (it *verkleNodeIterator) NodeBlob() []byte {
159+
panic("not completely implemented")
160+
}
161+
162+
// Leaf returns true iff the current node is a leaf node.
163+
func (it *verkleNodeIterator) Leaf() bool {
164+
_, ok := it.current.(*verkle.LeafNode)
165+
return ok
166+
}
167+
168+
// LeafKey returns the key of the leaf. The method panics if the iterator is not
169+
// positioned at a leaf. Callers must not retain references to the value after
170+
// calling Next.
171+
func (it *verkleNodeIterator) LeafKey() []byte {
172+
leaf, ok := it.current.(*verkle.LeafNode)
173+
if !ok {
174+
panic("Leaf() called on an verkle node iterator not at a leaf location")
175+
}
176+
177+
return leaf.Key(it.stack[len(it.stack)-1].Index - 1)
178+
}
179+
180+
// LeafBlob returns the content of the leaf. The method panics if the iterator
181+
// is not positioned at a leaf. Callers must not retain references to the value
182+
// after calling Next.
183+
func (it *verkleNodeIterator) LeafBlob() []byte {
184+
leaf, ok := it.current.(*verkle.LeafNode)
185+
if !ok {
186+
panic("LeafBlob() called on an verkle node iterator not at a leaf location")
187+
}
188+
189+
return leaf.Value(it.stack[len(it.stack)-1].Index - 1)
190+
}
191+
192+
// LeafProof returns the Merkle proof of the leaf. The method panics if the
193+
// iterator is not positioned at a leaf. Callers must not retain references
194+
// to the value after calling Next.
195+
func (it *verkleNodeIterator) LeafProof() [][]byte {
196+
_, ok := it.current.(*verkle.LeafNode)
197+
if !ok {
198+
panic("LeafProof() called on an verkle node iterator not at a leaf location")
199+
}
200+
201+
// return it.trie.Prove(leaf.Key())
202+
panic("not completely implemented")
203+
}
204+
205+
// AddResolver sets an intermediate database to use for looking up trie nodes
206+
// before reaching into the real persistent layer.
207+
//
208+
// This is not required for normal operation, rather is an optimization for
209+
// cases where trie nodes can be recovered from some external mechanism without
210+
// reading from disk. In those cases, this resolver allows short circuiting
211+
// accesses and returning them from memory.
212+
//
213+
// Before adding a similar mechanism to any other place in Geth, consider
214+
// making trie.Database an interface and wrapping at that level. It's a huge
215+
// refactor, but it could be worth it if another occurrence arises.
216+
func (it *verkleNodeIterator) AddResolver(NodeResolver) {
217+
// Not implemented, but should not panic
218+
}

trie/verkle_iterator_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2023 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 trie
18+
19+
import (
20+
"testing"
21+
22+
"github.com/ethereum/go-ethereum/common"
23+
"github.com/ethereum/go-ethereum/core/rawdb"
24+
"github.com/ethereum/go-ethereum/core/types"
25+
"github.com/ethereum/go-ethereum/trie/utils"
26+
"github.com/holiman/uint256"
27+
)
28+
29+
func TestVerkleIterator(t *testing.T) {
30+
trie, err := NewVerkleTrie(types.EmptyVerkleHash, newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme), utils.NewPointCache(1024))
31+
if err != nil {
32+
panic(err)
33+
}
34+
account0 := &types.StateAccount{
35+
Nonce: 1,
36+
Balance: new(uint256.Int).SetUint64(2),
37+
Root: types.EmptyRootHash,
38+
CodeHash: nil,
39+
}
40+
// NOTE: the code size isn't written to the trie via TryUpdateAccount
41+
// so it will be missing from the test nodes.
42+
trie.UpdateAccount(common.Address{}, account0, 0)
43+
account1 := &types.StateAccount{
44+
Nonce: 1337,
45+
Balance: new(uint256.Int).SetUint64(2000),
46+
Root: types.EmptyRootHash,
47+
CodeHash: nil,
48+
}
49+
// This address is meant to hash to a value that has the same first byte as 0xbf
50+
var clash = common.HexToAddress("69fd8034cdb20934dedffa7dccb4fb3b8062a8be")
51+
trie.UpdateAccount(clash, account1, 0)
52+
53+
// Manually go over every node to check that we get all
54+
// the correct nodes.
55+
it, err := trie.NodeIterator(nil)
56+
if err != nil {
57+
t.Fatal(err)
58+
}
59+
var leafcount int
60+
for it.Next(true) {
61+
t.Logf("Node: %x", it.Path())
62+
if it.Leaf() {
63+
leafcount++
64+
t.Logf("\tLeaf: %x", it.LeafKey())
65+
}
66+
}
67+
if leafcount != 2 {
68+
t.Fatalf("invalid leaf count: %d != 6", leafcount)
69+
}
70+
}

0 commit comments

Comments
 (0)