Skip to content

Commit 9efde47

Browse files
authored
fix(trie): decode inline child nodes (#2369)
1 parent ded3a0b commit 9efde47

File tree

4 files changed

+137
-5
lines changed

4 files changed

+137
-5
lines changed

internal/trie/node/decode.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,18 @@ func decodeBranch(reader io.Reader, header byte) (branch *Branch, err error) {
105105
ErrDecodeChildHash, i, err)
106106
}
107107

108+
// Handle inlined leaf nodes.
109+
const hashLength = 32
110+
if Type(hash[0]>>6) == LeafType && len(hash) < hashLength {
111+
leaf, err := decodeLeaf(bytes.NewReader(hash[1:]), hash[0])
112+
if err != nil {
113+
return nil, fmt.Errorf("%w: at index %d: %s",
114+
ErrDecodeValue, i, err)
115+
}
116+
branch.Children[i] = leaf
117+
continue
118+
}
119+
108120
branch.Children[i] = &Leaf{
109121
HashDigest: hash,
110122
}

internal/trie/node/decode_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,65 @@ func Test_Decode(t *testing.T) {
9595
Dirty: true,
9696
},
9797
},
98+
"branch with two inlined children": {
99+
reader: bytes.NewReader(
100+
[]byte{
101+
158, // node type 2 (branch w/o value) and key length 30
102+
// Key data start
103+
195, 101, 195, 207, 89, 214,
104+
113, 235, 114, 218, 14, 122,
105+
65, 19, 196, 16, 2, 80, 95,
106+
14, 123, 144, 18, 9, 107,
107+
65, 196, 235, 58, 175,
108+
// Key data end
109+
148, 127, 110, 164, 41, 8, 0, 0, 104, 95, 15, 31, 5,
110+
21, 244, 98, 205, 207, 132, 224, 241, 214, 4, 93, 252,
111+
187, 32, 134, 92, 74, 43, 127, 1, 0, 0,
112+
},
113+
),
114+
n: &Branch{
115+
Key: []byte{
116+
12, 3, 6, 5, 12, 3,
117+
12, 15, 5, 9, 13, 6,
118+
7, 1, 14, 11, 7, 2,
119+
13, 10, 0, 14, 7, 10,
120+
4, 1, 1, 3, 12, 4,
121+
},
122+
Children: [16]Node{
123+
nil, nil, nil, nil,
124+
&Leaf{
125+
Key: []byte{
126+
14, 7, 11, 9, 0, 1,
127+
2, 0, 9, 6, 11, 4,
128+
1, 12, 4, 14, 11,
129+
3, 10, 10, 15, 9,
130+
4, 7, 15, 6, 14,
131+
10, 4, 2, 9,
132+
},
133+
Value: []byte{0, 0},
134+
Dirty: true,
135+
},
136+
nil, nil, nil, nil,
137+
&Leaf{
138+
Key: []byte{
139+
15, 1, 15, 0, 5, 1,
140+
5, 15, 4, 6, 2, 12,
141+
13, 12, 15, 8, 4,
142+
14, 0, 15, 1, 13,
143+
6, 0, 4, 5, 13,
144+
15, 12, 11, 11,
145+
},
146+
Value: []byte{
147+
134, 92, 74, 43,
148+
127, 1, 0, 0,
149+
},
150+
Dirty: true,
151+
},
152+
nil, nil, nil, nil, nil, nil,
153+
},
154+
Dirty: true,
155+
},
156+
},
98157
}
99158

100159
for name, testCase := range testCases {

internal/trie/node/encode_decode_test.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func Test_Branch_Encode_Decode(t *testing.T) {
4343
Dirty: true,
4444
},
4545
},
46-
"branch with child": {
46+
"branch with child leaf inline": {
4747
branchToEncode: &Branch{
4848
Key: []byte{5},
4949
Children: [16]Node{
@@ -57,7 +57,50 @@ func Test_Branch_Encode_Decode(t *testing.T) {
5757
Key: []byte{5},
5858
Children: [16]Node{
5959
&Leaf{
60-
HashDigest: []byte{0x41, 0x9, 0x4, 0xa},
60+
Key: []byte{9},
61+
Value: []byte{10},
62+
Dirty: true,
63+
},
64+
},
65+
Dirty: true,
66+
},
67+
},
68+
"branch with child leaf hash": {
69+
branchToEncode: &Branch{
70+
Key: []byte{5},
71+
Children: [16]Node{
72+
&Leaf{
73+
Key: []byte{
74+
10, 11, 12, 13,
75+
14, 15, 16, 17,
76+
18, 19, 20, 21,
77+
14, 15, 16, 17,
78+
10, 11, 12, 13,
79+
14, 15, 16, 17,
80+
},
81+
Value: []byte{
82+
10, 11, 12, 13,
83+
14, 15, 16, 17,
84+
10, 11, 12, 13,
85+
14, 15, 16, 17,
86+
10, 11, 12, 13,
87+
},
88+
},
89+
},
90+
},
91+
branchDecoded: &Branch{
92+
Key: []byte{5},
93+
Children: [16]Node{
94+
&Leaf{
95+
HashDigest: []byte{
96+
2, 18, 48, 30, 98,
97+
133, 244, 78, 70,
98+
161, 196, 105, 228,
99+
190, 159, 228, 199, 29,
100+
254, 212, 160, 55, 199,
101+
21, 186, 226, 204, 145,
102+
132, 5, 39, 204,
103+
},
61104
},
62105
},
63106
Dirty: true,

lib/trie/database.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@ func (t *Trie) load(db chaindb.Database, n Node) error {
186186

187187
hash := child.GetHash()
188188

189+
_, isLeaf := child.(*node.Leaf)
190+
if len(hash) == 0 && isLeaf {
191+
// node has already been loaded inline
192+
// just set encoding + hash digest
193+
_, _, err := child.EncodeAndHash(false)
194+
if err != nil {
195+
return err
196+
}
197+
child.SetDirty(false)
198+
continue
199+
}
200+
189201
encodedNode, err := db.Get(hash)
190202
if err != nil {
191203
return fmt.Errorf("cannot find child node key 0x%x in database: %w", hash, err)
@@ -330,12 +342,18 @@ func getFromDB(db chaindb.Database, n Node, key []byte) (
330342

331343
// childIndex is the nibble after the common prefix length in the key being searched.
332344
childIndex := key[commonPrefixLength]
333-
childWithHashOnly := branch.Children[childIndex]
334-
if childWithHashOnly == nil {
345+
child := branch.Children[childIndex]
346+
if child == nil {
335347
return nil, nil
336348
}
337349

338-
childHash := childWithHashOnly.GetHash()
350+
// Child can be either inlined or a hash pointer.
351+
childHash := child.GetHash()
352+
_, isLeaf := child.(*node.Leaf)
353+
if len(childHash) == 0 && isLeaf {
354+
return getFromDB(db, child, key[commonPrefixLength+1:])
355+
}
356+
339357
encodedChild, err := db.Get(childHash)
340358
if err != nil {
341359
return nil, fmt.Errorf(

0 commit comments

Comments
 (0)