Skip to content

Commit 99bcdb3

Browse files
authored
fix(trie): differentiate []byte(nil) and []byte{} for storage values (#2964)
1 parent 9598892 commit 99bcdb3

File tree

8 files changed

+29
-32
lines changed

8 files changed

+29
-32
lines changed

dot/state/storage_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ func TestStorage_LoadFromDB(t *testing.T) {
113113
trieKV := []struct {
114114
key []byte
115115
value []byte
116-
}{{},
116+
}{
117+
{value: []byte{}},
117118
{[]byte("key1"), []byte("value1")},
118119
{[]byte("key2"), []byte("value2")},
119120
{[]byte("xyzKey1"), []byte("xyzValue1")},
@@ -147,7 +148,7 @@ func TestStorage_LoadFromDB(t *testing.T) {
147148

148149
entries, err := storage.Entries(&root)
149150
require.NoError(t, err)
150-
require.Equal(t, 3, len(entries))
151+
require.Equal(t, 4, len(entries))
151152
}
152153

153154
func TestStorage_StoreTrie_NotSyncing(t *testing.T) {

internal/trie/node/decode.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,10 @@ func decodeLeaf(reader io.Reader, partialKeyLength uint16) (node *Node, err erro
132132
}
133133

134134
sd := scale.NewDecoder(reader)
135-
var storageValue []byte
136-
err = sd.Decode(&storageValue)
137-
if err != nil && !errors.Is(err, io.EOF) {
135+
err = sd.Decode(&node.StorageValue)
136+
if err != nil {
138137
return nil, fmt.Errorf("%w: %s", ErrDecodeStorageValue, err)
139138
}
140139

141-
if len(storageValue) > 0 {
142-
node.StorageValue = storageValue
143-
}
144-
145140
return node, nil
146141
}

internal/trie/node/decode_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -334,19 +334,19 @@ func Test_decodeLeaf(t *testing.T) {
334334
}),
335335
variant: leafVariant.bits,
336336
partialKeyLength: 1,
337-
leaf: &Node{
338-
PartialKey: []byte{9},
339-
},
337+
errWrapped: ErrDecodeStorageValue,
338+
errMessage: "cannot decode storage value: reading byte: EOF",
340339
},
341340
"empty storage value data": {
342341
reader: bytes.NewBuffer(concatByteSlices([][]byte{
343-
{9}, // key data
344-
scaleEncodeByteSlice(t, nil),
342+
{9}, // key data
343+
scaleEncodeByteSlice(t, []byte{}), // results to []byte{0}
345344
})),
346345
variant: leafVariant.bits,
347346
partialKeyLength: 1,
348347
leaf: &Node{
349-
PartialKey: []byte{9},
348+
PartialKey: []byte{9},
349+
StorageValue: []byte{},
350350
},
351351
},
352352
"success": {

internal/trie/node/encode.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ func (n *Node) Encode(buffer Buffer) (err error) {
3737
}
3838
}
3939

40-
// Only encode node storage value if the node is a leaf or
41-
// the node is a branch with a non empty storage value.
42-
if !nodeIsBranch || (nodeIsBranch && n.StorageValue != nil) {
40+
// Only encode node storage value if the node has a storage value,
41+
// even if it is empty. Do not encode if the branch is without value.
42+
// Note leaves and branches with value cannot have a `nil` storage value.
43+
if n.StorageValue != nil {
4344
encoder := scale.NewEncoder(buffer)
4445
err = encoder.Encode(n.StorageValue)
4546
if err != nil {

internal/trie/node/encode_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,14 @@ func Test_Node_Encode(t *testing.T) {
9797
},
9898
"leaf with empty storage value success": {
9999
node: &Node{
100-
PartialKey: []byte{1, 2, 3},
100+
PartialKey: []byte{1, 2, 3},
101+
StorageValue: []byte{},
101102
},
102103
writes: []writeCall{
103104
{written: []byte{leafVariant.bits | 3}}, // partial key length 3
104105
{written: []byte{0x01, 0x23}}, // partial key
105106
{written: []byte{0}}, // node storage value encoded length
106-
{written: nil}, // node storage value
107+
{written: []byte{}}, // node storage value
107108
},
108109
expectedEncoding: []byte{1, 2, 3},
109110
},

lib/trie/trie.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,10 @@ func (t *Trie) Put(keyLE, value []byte) {
333333

334334
func (t *Trie) insertKeyLE(keyLE, value []byte, deletedMerkleValues map[string]struct{}) {
335335
nibblesKey := codec.KeyLEToNibbles(keyLE)
336-
if len(value) == 0 {
337-
// Force value to be inserted to nil since we don't
338-
// differentiate between nil and empty values.
339-
value = nil
336+
if value == nil {
337+
// Force nil value to be inserted to []byte{} since `nil` means there
338+
// is no value.
339+
value = []byte{}
340340
}
341341
t.root, _, _ = t.insert(t.root, nibblesKey, value, deletedMerkleValues)
342342
}

lib/trie/trie_endtoend_test.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,7 @@ func Fuzz_Trie_PutAndGet_Single(f *testing.F) {
106106
trie := NewEmptyTrie()
107107
trie.Put(key, value)
108108
retrievedValue := trie.Get(key)
109-
if retrievedValue == nil {
110-
assert.Empty(t, value)
111-
} else {
112-
assert.Equal(t, value, retrievedValue)
113-
}
109+
assert.Equal(t, value, retrievedValue)
114110
})
115111
}
116112

pkg/scale/decode.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -592,9 +592,12 @@ func (ds *decodeState) decodeBytes(dstv reflect.Value) (err error) {
592592
}
593593

594594
b := make([]byte, length)
595-
_, err = ds.Read(b)
596-
if err != nil {
597-
return
595+
596+
if length > 0 {
597+
_, err = ds.Read(b)
598+
if err != nil {
599+
return
600+
}
598601
}
599602

600603
in := dstv.Interface()

0 commit comments

Comments
 (0)