Skip to content

Commit f13dfc5

Browse files
parithoshgballet
authored andcommitted
Move BinaryTrie and iterator to the bintrie package and add more coverage (#547)
* refactor package * add tests
1 parent 2656abc commit f13dfc5

14 files changed

+1619
-102
lines changed

trie/bintrie/binary_node_test.go

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
// Copyright 2025 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 bintrie
18+
19+
import (
20+
"bytes"
21+
"errors"
22+
"testing"
23+
24+
"github.com/ethereum/go-ethereum/common"
25+
)
26+
27+
// TestSerializeDeserializeInternalNode tests serialization and deserialization of InternalNode
28+
func TestSerializeDeserializeInternalNode(t *testing.T) {
29+
// Create an internal node with two hashed children
30+
leftHash := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
31+
rightHash := common.HexToHash("0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321")
32+
33+
node := &InternalNode{
34+
depth: 5,
35+
Left: HashedNode(leftHash),
36+
Right: HashedNode(rightHash),
37+
}
38+
39+
// Serialize the node
40+
serialized := SerializeNode(node)
41+
42+
// Check the serialized format
43+
if serialized[0] != 1 {
44+
t.Errorf("Expected type byte to be 1, got %d", serialized[0])
45+
}
46+
47+
if len(serialized) != 65 {
48+
t.Errorf("Expected serialized length to be 65, got %d", len(serialized))
49+
}
50+
51+
// Deserialize the node
52+
deserialized, err := DeserializeNode(serialized, 5)
53+
if err != nil {
54+
t.Fatalf("Failed to deserialize node: %v", err)
55+
}
56+
57+
// Check that it's an internal node
58+
internalNode, ok := deserialized.(*InternalNode)
59+
if !ok {
60+
t.Fatalf("Expected InternalNode, got %T", deserialized)
61+
}
62+
63+
// Check the depth
64+
if internalNode.depth != 5 {
65+
t.Errorf("Expected depth 5, got %d", internalNode.depth)
66+
}
67+
68+
// Check the left and right hashes
69+
if internalNode.Left.Hash() != leftHash {
70+
t.Errorf("Left hash mismatch: expected %x, got %x", leftHash, internalNode.Left.Hash())
71+
}
72+
73+
if internalNode.Right.Hash() != rightHash {
74+
t.Errorf("Right hash mismatch: expected %x, got %x", rightHash, internalNode.Right.Hash())
75+
}
76+
}
77+
78+
// TestSerializeDeserializeStemNode tests serialization and deserialization of StemNode
79+
func TestSerializeDeserializeStemNode(t *testing.T) {
80+
// Create a stem node with some values
81+
stem := make([]byte, 31)
82+
for i := range stem {
83+
stem[i] = byte(i)
84+
}
85+
86+
var values [256][]byte
87+
// Add some values at different indices
88+
values[0] = common.HexToHash("0x0101010101010101010101010101010101010101010101010101010101010101").Bytes()
89+
values[10] = common.HexToHash("0x0202020202020202020202020202020202020202020202020202020202020202").Bytes()
90+
values[255] = common.HexToHash("0x0303030303030303030303030303030303030303030303030303030303030303").Bytes()
91+
92+
node := &StemNode{
93+
Stem: stem,
94+
Values: values[:],
95+
depth: 10,
96+
}
97+
98+
// Serialize the node
99+
serialized := SerializeNode(node)
100+
101+
// Check the serialized format
102+
if serialized[0] != 2 {
103+
t.Errorf("Expected type byte to be 2, got %d", serialized[0])
104+
}
105+
106+
// Check the stem is correctly serialized
107+
if !bytes.Equal(serialized[1:32], stem) {
108+
t.Errorf("Stem mismatch in serialized data")
109+
}
110+
111+
// Deserialize the node
112+
deserialized, err := DeserializeNode(serialized, 10)
113+
if err != nil {
114+
t.Fatalf("Failed to deserialize node: %v", err)
115+
}
116+
117+
// Check that it's a stem node
118+
stemNode, ok := deserialized.(*StemNode)
119+
if !ok {
120+
t.Fatalf("Expected StemNode, got %T", deserialized)
121+
}
122+
123+
// Check the stem
124+
if !bytes.Equal(stemNode.Stem, stem) {
125+
t.Errorf("Stem mismatch after deserialization")
126+
}
127+
128+
// Check the values
129+
if !bytes.Equal(stemNode.Values[0], values[0]) {
130+
t.Errorf("Value at index 0 mismatch")
131+
}
132+
if !bytes.Equal(stemNode.Values[10], values[10]) {
133+
t.Errorf("Value at index 10 mismatch")
134+
}
135+
if !bytes.Equal(stemNode.Values[255], values[255]) {
136+
t.Errorf("Value at index 255 mismatch")
137+
}
138+
139+
// Check that other values are nil
140+
if stemNode.Values[1] != nil {
141+
t.Errorf("Expected nil value at index 1, got %x", stemNode.Values[1])
142+
}
143+
}
144+
145+
// TestDeserializeEmptyNode tests deserialization of empty node
146+
func TestDeserializeEmptyNode(t *testing.T) {
147+
// Empty byte slice should deserialize to Empty node
148+
deserialized, err := DeserializeNode([]byte{}, 0)
149+
if err != nil {
150+
t.Fatalf("Failed to deserialize empty node: %v", err)
151+
}
152+
153+
_, ok := deserialized.(Empty)
154+
if !ok {
155+
t.Fatalf("Expected Empty node, got %T", deserialized)
156+
}
157+
}
158+
159+
// TestDeserializeInvalidType tests deserialization with invalid type byte
160+
func TestDeserializeInvalidType(t *testing.T) {
161+
// Create invalid serialized data with unknown type byte
162+
invalidData := []byte{99, 0, 0, 0} // Type byte 99 is invalid
163+
164+
_, err := DeserializeNode(invalidData, 0)
165+
if err == nil {
166+
t.Fatal("Expected error for invalid type byte, got nil")
167+
}
168+
}
169+
170+
// TestDeserializeInvalidLength tests deserialization with invalid data length
171+
func TestDeserializeInvalidLength(t *testing.T) {
172+
// InternalNode with type byte 1 but wrong length
173+
invalidData := []byte{1, 0, 0} // Too short for internal node
174+
175+
_, err := DeserializeNode(invalidData, 0)
176+
if err == nil {
177+
t.Fatal("Expected error for invalid data length, got nil")
178+
}
179+
180+
if err.Error() != "invalid serialized node length" {
181+
t.Errorf("Expected 'invalid serialized node length' error, got: %v", err)
182+
}
183+
}
184+
185+
// TestKeyToPath tests the keyToPath function
186+
func TestKeyToPath(t *testing.T) {
187+
tests := []struct {
188+
name string
189+
depth int
190+
key []byte
191+
expected []byte
192+
wantErr bool
193+
}{
194+
{
195+
name: "depth 0",
196+
depth: 0,
197+
key: []byte{0x80}, // 10000000 in binary
198+
expected: []byte{1},
199+
wantErr: false,
200+
},
201+
{
202+
name: "depth 7",
203+
depth: 7,
204+
key: []byte{0xFF}, // 11111111 in binary
205+
expected: []byte{1, 1, 1, 1, 1, 1, 1, 1},
206+
wantErr: false,
207+
},
208+
{
209+
name: "depth crossing byte boundary",
210+
depth: 10,
211+
key: []byte{0xFF, 0x00}, // 11111111 00000000 in binary
212+
expected: []byte{1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
213+
wantErr: false,
214+
},
215+
{
216+
name: "max valid depth",
217+
depth: 31 * 8,
218+
key: make([]byte, 32),
219+
expected: make([]byte, 31*8+1),
220+
wantErr: false,
221+
},
222+
{
223+
name: "depth too large",
224+
depth: 31*8 + 1,
225+
key: make([]byte, 32),
226+
wantErr: true,
227+
},
228+
}
229+
230+
for _, tt := range tests {
231+
t.Run(tt.name, func(t *testing.T) {
232+
path, err := keyToPath(tt.depth, tt.key)
233+
if tt.wantErr {
234+
if err == nil {
235+
t.Errorf("Expected error for depth %d, got nil", tt.depth)
236+
}
237+
return
238+
}
239+
if err != nil {
240+
t.Errorf("Unexpected error: %v", err)
241+
return
242+
}
243+
if !bytes.Equal(path, tt.expected) {
244+
t.Errorf("Path mismatch: expected %v, got %v", tt.expected, path)
245+
}
246+
})
247+
}
248+
}
249+
250+
// Mock resolver function for testing
251+
func mockResolver(path []byte, hash common.Hash) ([]byte, error) {
252+
// Return a simple stem node for testing
253+
if hash == common.HexToHash("0x1234") {
254+
stem := make([]byte, 31)
255+
var values [256][]byte
256+
values[0] = common.HexToHash("0xabcd").Bytes()
257+
node := &StemNode{
258+
Stem: stem,
259+
Values: values[:],
260+
}
261+
return SerializeNode(node), nil
262+
}
263+
return nil, errors.New("node not found")
264+
}
265+
266+
// Mock flush function for testing
267+
func mockFlushFn(path []byte, node BinaryNode) {
268+
// Just a stub for testing
269+
}

0 commit comments

Comments
 (0)