Skip to content

Commit b09eb07

Browse files
authored
feat(trie): decode all inlined node variants (#2611)
1 parent c6e9c80 commit b09eb07

File tree

3 files changed

+84
-81
lines changed

3 files changed

+84
-81
lines changed

internal/trie/node/decode.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,11 @@ func decodeBranch(reader io.Reader, variant byte, partialKeyLength uint16) (
110110
if len(hash) < hashLength {
111111
// Handle inlined nodes
112112
reader = bytes.NewReader(hash)
113-
variant, partialKeyLength, err := decodeHeader(reader)
114-
if err == nil && variant == leafVariant.bits {
115-
childNode, err = decodeLeaf(reader, partialKeyLength)
116-
if err != nil {
117-
return nil, fmt.Errorf("%w: at index %d: %s",
118-
ErrDecodeValue, i, err)
119-
}
113+
childNode, err = Decode(reader)
114+
if err != nil {
115+
return nil, fmt.Errorf("decoding inlined child at index %d: %w", i, err)
120116
}
117+
node.Descendants += childNode.Descendants
121118
}
122119

123120
node.Descendants++

internal/trie/node/decode_test.go

Lines changed: 79 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import (
1414
)
1515

1616
func scaleEncodeBytes(t *testing.T, b ...byte) (encoded []byte) {
17+
return scaleEncodeByteSlice(t, b)
18+
}
19+
20+
func scaleEncodeByteSlice(t *testing.T, b []byte) (encoded []byte) {
1721
encoded, err := scale.Marshal(b)
1822
require.NoError(t, err)
1923
return encoded
@@ -98,66 +102,6 @@ func Test_Decode(t *testing.T) {
98102
Dirty: true,
99103
},
100104
},
101-
"branch with two inlined children": {
102-
reader: bytes.NewReader(
103-
[]byte{
104-
branchVariant.bits | 30, // key length 30
105-
// Key data start
106-
195, 101, 195, 207, 89, 214,
107-
113, 235, 114, 218, 14, 122,
108-
65, 19, 196, 16, 2, 80, 95,
109-
14, 123, 144, 18, 9, 107,
110-
65, 196, 235, 58, 175,
111-
// Key data end
112-
148, 127, 110, 164, 41, 8, 0, 0, 104, 95, 15, 31, 5,
113-
21, 244, 98, 205, 207, 132, 224, 241, 214, 4, 93, 252,
114-
187, 32, 134, 92, 74, 43, 127, 1, 0, 0,
115-
},
116-
),
117-
n: &Node{
118-
Key: []byte{
119-
12, 3, 6, 5, 12, 3,
120-
12, 15, 5, 9, 13, 6,
121-
7, 1, 14, 11, 7, 2,
122-
13, 10, 0, 14, 7, 10,
123-
4, 1, 1, 3, 12, 4,
124-
},
125-
Descendants: 2,
126-
Children: []*Node{
127-
nil, nil, nil, nil,
128-
{
129-
Key: []byte{
130-
14, 7, 11, 9, 0, 1,
131-
2, 0, 9, 6, 11, 4,
132-
1, 12, 4, 14, 11,
133-
3, 10, 10, 15, 9,
134-
4, 7, 15, 6, 14,
135-
10, 4, 2, 9,
136-
},
137-
Value: []byte{0, 0},
138-
Dirty: true,
139-
},
140-
nil, nil, nil, nil,
141-
{
142-
Key: []byte{
143-
15, 1, 15, 0, 5, 1,
144-
5, 15, 4, 6, 2, 12,
145-
13, 12, 15, 8, 4,
146-
14, 0, 15, 1, 13,
147-
6, 0, 4, 5, 13,
148-
15, 12, 11, 11,
149-
},
150-
Value: []byte{
151-
134, 92, 74, 43,
152-
127, 1, 0, 0,
153-
},
154-
Dirty: true,
155-
},
156-
nil, nil, nil, nil, nil, nil,
157-
},
158-
Dirty: true,
159-
},
160-
},
161105
}
162106

163107
for name, testCase := range testCases {
@@ -179,6 +123,13 @@ func Test_Decode(t *testing.T) {
179123
func Test_decodeBranch(t *testing.T) {
180124
t.Parallel()
181125

126+
const childHashLength = 32
127+
childHash := make([]byte, childHashLength)
128+
for i := range childHash {
129+
childHash[i] = byte(i)
130+
}
131+
scaleEncodedChildHash := scaleEncodeByteSlice(t, childHash)
132+
182133
testCases := map[string]struct {
183134
reader io.Reader
184135
variant byte
@@ -220,9 +171,9 @@ func Test_decodeBranch(t *testing.T) {
220171
"success for branch variant": {
221172
reader: bytes.NewBuffer(
222173
concatByteSlices([][]byte{
223-
{9}, // key data
224-
{0, 4}, // children bitmap
225-
scaleEncodeBytes(t, 1, 2, 3, 4, 5), // child hash
174+
{9}, // key data
175+
{0, 4}, // children bitmap
176+
scaleEncodedChildHash,
226177
}),
227178
),
228179
variant: branchVariant.bits,
@@ -233,7 +184,7 @@ func Test_decodeBranch(t *testing.T) {
233184
nil, nil, nil, nil, nil,
234185
nil, nil, nil, nil, nil,
235186
{
236-
HashDigest: []byte{1, 2, 3, 4, 5},
187+
HashDigest: childHash,
237188
Dirty: true,
238189
},
239190
}),
@@ -255,14 +206,12 @@ func Test_decodeBranch(t *testing.T) {
255206
errMessage: "cannot decode value: EOF",
256207
},
257208
"success for branch with value": {
258-
reader: bytes.NewBuffer(
259-
concatByteSlices([][]byte{
260-
{9}, // key data
261-
{0, 4}, // children bitmap
262-
scaleEncodeBytes(t, 7, 8, 9), // branch value
263-
scaleEncodeBytes(t, 1, 2, 3, 4, 5), // child hash
264-
}),
265-
),
209+
reader: bytes.NewBuffer(concatByteSlices([][]byte{
210+
{9}, // key data
211+
{0, 4}, // children bitmap
212+
scaleEncodeBytes(t, 7, 8, 9), // branch value
213+
scaleEncodedChildHash,
214+
})),
266215
variant: branchWithValueVariant.bits,
267216
partialKeyLength: 1,
268217
branch: &Node{
@@ -272,14 +221,71 @@ func Test_decodeBranch(t *testing.T) {
272221
nil, nil, nil, nil, nil,
273222
nil, nil, nil, nil, nil,
274223
{
275-
HashDigest: []byte{1, 2, 3, 4, 5},
224+
HashDigest: childHash,
276225
Dirty: true,
277226
},
278227
}),
279228
Dirty: true,
280229
Descendants: 1,
281230
},
282231
},
232+
"branch with inlined node decoding error": {
233+
reader: bytes.NewBuffer(concatByteSlices([][]byte{
234+
{1}, // key data
235+
{0b0000_0001, 0b0000_0000}, // children bitmap
236+
scaleEncodeBytes(t, 1), // branch value
237+
{0}, // garbage inlined node
238+
})),
239+
variant: branchWithValueVariant.bits,
240+
partialKeyLength: 1,
241+
errWrapped: io.EOF,
242+
errMessage: "decoding inlined child at index 0: " +
243+
"decoding header: reading header byte: EOF",
244+
},
245+
"branch with inlined branch and leaf": {
246+
reader: bytes.NewBuffer(concatByteSlices([][]byte{
247+
{1}, // key data
248+
{0b0000_0011, 0b0000_0000}, // children bitmap
249+
// top level inlined leaf less than 32 bytes
250+
scaleEncodeByteSlice(t, concatByteSlices([][]byte{
251+
{leafVariant.bits | 1}, // partial key length of 1
252+
{2}, // key data
253+
scaleEncodeBytes(t, 2), // value data
254+
})),
255+
// top level inlined branch less than 32 bytes
256+
scaleEncodeByteSlice(t, concatByteSlices([][]byte{
257+
{branchWithValueVariant.bits | 1}, // partial key length of 1
258+
{3}, // key data
259+
{0b0000_0001, 0b0000_0000}, // children bitmap
260+
scaleEncodeBytes(t, 3), // branch value
261+
// bottom level leaf
262+
scaleEncodeByteSlice(t, concatByteSlices([][]byte{
263+
{leafVariant.bits | 1}, // partial key length of 1
264+
{4}, // key data
265+
scaleEncodeBytes(t, 4), // value data
266+
})),
267+
})),
268+
})),
269+
variant: branchVariant.bits,
270+
partialKeyLength: 1,
271+
branch: &Node{
272+
Key: []byte{1},
273+
Descendants: 3,
274+
Children: padRightChildren([]*Node{
275+
{Key: []byte{2}, Value: []byte{2}, Dirty: true},
276+
{
277+
Key: []byte{3},
278+
Value: []byte{3},
279+
Dirty: true,
280+
Descendants: 1,
281+
Children: padRightChildren([]*Node{
282+
{Key: []byte{4}, Value: []byte{4}, Dirty: true},
283+
}),
284+
},
285+
}),
286+
Dirty: true,
287+
},
288+
},
283289
}
284290

285291
for name, testCase := range testCases {

lib/trie/database.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ func (t *Trie) load(db chaindb.Database, n *Node) error {
182182

183183
hash := child.HashDigest
184184

185-
if len(hash) == 0 && child.Type() == node.Leaf {
185+
if len(hash) == 0 {
186186
// node has already been loaded inline
187187
// just set encoding + hash digest
188188
_, _, err := child.EncodeAndHash(false)

0 commit comments

Comments
 (0)