Skip to content

Commit db7f2af

Browse files
authored
CreateStorageKey improvements + Comprehensive tests (#169)
1 parent 00abec4 commit db7f2af

3 files changed

Lines changed: 221 additions & 63 deletions

File tree

types/metadataV13.go

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -291,45 +291,14 @@ func (s StorageFunctionMetadataV13) Hashers() ([]hash.Hash, error) {
291291
return nil, fmt.Errorf("only NMaps have Hashers")
292292
}
293293

294-
var hashers []hash.Hash
295-
if s.Type.IsMap {
296-
hashers = make([]hash.Hash, 1)
297-
mapHasher, err := s.Type.AsMap.Hasher.HashFunc()
294+
hashers := make([]hash.Hash, len(s.Type.AsNMap.Hashers))
295+
for i, hasher := range s.Type.AsNMap.Hashers {
296+
hasherFn, err := hasher.HashFunc()
298297
if err != nil {
299298
return nil, err
300299
}
301-
hashers[0] = mapHasher
302-
return hashers, nil
300+
hashers[i] = hasherFn
303301
}
304-
if s.Type.IsDoubleMap {
305-
hashers = make([]hash.Hash, 2)
306-
firstDoubleMapHasher, err := s.Type.AsDoubleMap.Hasher.HashFunc()
307-
if err != nil {
308-
return nil, err
309-
}
310-
hashers[0] = firstDoubleMapHasher
311-
secondDoubleMapHasher, err := s.Type.AsDoubleMap.Key2Hasher.HashFunc()
312-
if err != nil {
313-
return nil, err
314-
}
315-
hashers[1] = secondDoubleMapHasher
316-
return hashers, nil
317-
}
318-
if s.Type.IsNMap {
319-
hashers = make([]hash.Hash, len(s.Type.AsNMap.Hashers))
320-
for i, hasher := range s.Type.AsNMap.Hashers {
321-
hasherFn, err := hasher.HashFunc()
322-
if err != nil {
323-
return nil, err
324-
}
325-
hashers[i] = hasherFn
326-
}
327-
return hashers, nil
328-
}
329-
330-
hashers = make([]hash.Hash, 1)
331-
hashers[0] = xxhash.New128(nil)
332-
333302
return hashers, nil
334303
}
335304

types/storage_key.go

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -79,28 +79,37 @@ func CreateStorageKey(meta *Metadata, prefix, method string, args ...[]byte) (St
7979
}
8080

8181
if entryMeta.IsNMap() {
82-
return createKeyNMap(meta, method, prefix, validatedArgs, entryMeta)
82+
hashers, err := entryMeta.Hashers()
83+
if err != nil {
84+
return nil, fmt.Errorf("unable to get hashers for %s nmap", method)
85+
}
86+
if len(hashers) != len(validatedArgs) {
87+
return nil, fmt.Errorf("%s:%s is a nmap, therefore requires that number of arguments should "+
88+
"exactly match number of hashers in metadata. "+
89+
"Expected: %d, received: %d", prefix, method, len(hashers), len(validatedArgs))
90+
}
91+
return createKeyNMap(method, prefix, validatedArgs, entryMeta)
8392
}
8493

8594
if entryMeta.IsDoubleMap() {
8695
if len(validatedArgs) != 2 {
87-
return nil, fmt.Errorf("%v is a double map, therefore requires precisely two arguments. "+
88-
"received: %d", method, len(validatedArgs))
96+
return nil, fmt.Errorf("%s:%s is a double map, therefore requires precisely two arguments. "+
97+
"received: %d", prefix, method, len(validatedArgs))
8998
}
9099
return createKeyDoubleMap(meta, method, prefix, stringKey, validatedArgs[0], validatedArgs[1], entryMeta)
91100
}
92101

93102
if entryMeta.IsMap() {
94103
if len(validatedArgs) != 1 {
95-
return nil, fmt.Errorf("%v is a map, therefore requires precisely one argument. "+
96-
"received: %d", method, len(validatedArgs))
104+
return nil, fmt.Errorf("%s:%s is a map, therefore requires precisely one argument. "+
105+
"received: %d", prefix, method, len(validatedArgs))
97106
}
98107
return createKey(meta, method, prefix, stringKey, validatedArgs[0], entryMeta)
99108
}
100109

101110
if entryMeta.IsPlain() && len(validatedArgs) != 0 {
102-
return nil, fmt.Errorf("%v is a plain key, therefore requires no argument. "+
103-
"received: %d", method, len(validatedArgs))
111+
return nil, fmt.Errorf("%s:%s is a plain key, therefore requires no argument. "+
112+
"received: %d", prefix, method, len(validatedArgs))
104113
}
105114

106115
return createKey(meta, method, prefix, stringKey, nil, entryMeta)
@@ -131,22 +140,12 @@ func (s StorageKey) Hex() string {
131140
return fmt.Sprintf("%#x", s)
132141
}
133142

134-
func createKeyNMap(meta *Metadata, method, prefix string, args [][]byte,
135-
entryMeta StorageEntryMetadata) (StorageKey, error) {
136-
if !meta.IsMetadataV13 {
137-
return nil, fmt.Errorf("storage n map is only supported in metadata version 13 or up")
138-
}
139-
143+
func createKeyNMap(method, prefix string, args [][]byte, entryMeta StorageEntryMetadata) (StorageKey, error) {
140144
hashers, err := entryMeta.Hashers()
141145
if err != nil {
142146
return nil, err
143147
}
144148

145-
if len(hashers) != len(args) {
146-
return nil, fmt.Errorf("number of arguments should exactly match number of hashers in metadata. "+
147-
"Expected: %d, received: %d", len(hashers), len(args))
148-
}
149-
150149
key := createPrefixedKey(method, prefix)
151150

152151
for i, arg := range args {
@@ -163,9 +162,6 @@ func createKeyNMap(meta *Metadata, method, prefix string, args [][]byte,
163162
// createKeyDoubleMap creates a key for a DoubleMap type
164163
func createKeyDoubleMap(meta *Metadata, method, prefix string, stringKey, arg, arg2 []byte,
165164
entryMeta StorageEntryMetadata) (StorageKey, error) {
166-
if arg == nil || arg2 == nil {
167-
return nil, fmt.Errorf("%v is a DoubleMap and requires two arguments", method)
168-
}
169165

170166
hasher, err := entryMeta.Hasher()
171167
if err != nil {
@@ -208,9 +204,6 @@ func createKeyDoubleMap(meta *Metadata, method, prefix string, stringKey, arg, a
208204
// createKey creates a key for either a map or a plain value
209205
func createKey(meta *Metadata, method, prefix string, stringKey, arg []byte, entryMeta StorageEntryMetadata) (
210206
StorageKey, error) {
211-
if entryMeta.IsMap() && arg == nil {
212-
return nil, fmt.Errorf("%v is a Map and requires one argument", method)
213-
}
214207

215208
hasher, err := entryMeta.Hasher()
216209
if err != nil {

types/storage_key_test.go

Lines changed: 200 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
package types_test
1818

1919
import (
20+
"encoding/binary"
21+
"github.com/centrifuge/go-substrate-rpc-client/v3/hash"
22+
"github.com/centrifuge/go-substrate-rpc-client/v3/xxhash"
23+
"strings"
2024
"testing"
2125

2226
. "github.com/centrifuge/go-substrate-rpc-client/v3/types"
@@ -27,10 +31,202 @@ const (
2731
AlicePubKey = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
2832
)
2933

34+
func TestCreateStorageKeyArgValidationForPlainKey(t *testing.T) {
35+
m := ExamplaryMetadataV13
36+
37+
_, err := CreateStorageKey(m, "Timestamp", "Now")
38+
assert.NoError(t, err)
39+
40+
_, err = CreateStorageKey(m, "Timestamp", "Now", nil)
41+
assert.NoError(t, err)
42+
43+
_, err = CreateStorageKey(m, "Timestamp", "Now", nil, []byte{})
44+
assert.NoError(t, err)
45+
46+
_, err = CreateStorageKey(m, "Timestamp", "Now", nil, []byte{0x01})
47+
assert.EqualError(t, err, "non-nil arguments cannot be preceded by nil arguments")
48+
49+
_, err = CreateStorageKey(m, "Timestamp", "Now", []byte{0x01})
50+
assert.EqualError(t, err, "Timestamp:Now is a plain key, therefore requires no argument. received: 1")
51+
52+
expectedKeyBuilder := strings.Builder{}
53+
hexStr, err := Hex(xxhash.New128([]byte("Timestamp")).Sum(nil))
54+
assert.NoError(t, err)
55+
expectedKeyBuilder.WriteString(hexStr)
56+
hexStr, err = Hex(xxhash.New128([]byte("Now")).Sum(nil))
57+
assert.NoError(t, err)
58+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
59+
60+
key, err := CreateStorageKey(m, "Timestamp", "Now")
61+
assert.NoError(t, err)
62+
hex, err := Hex(key)
63+
assert.NoError(t, err)
64+
assert.Equal(t, expectedKeyBuilder.String(), hex)
65+
}
66+
67+
func TestCreateStorageKeyArgValidationForMapKey(t *testing.T) {
68+
m := ExamplaryMetadataV13
69+
70+
_, err := CreateStorageKey(m, "System", "Account")
71+
assert.EqualError(t, err, "System:Account is a map, therefore requires precisely one argument. " +
72+
"received: 0")
73+
74+
_, err = CreateStorageKey(m, "System", "Account", nil)
75+
assert.EqualError(t, err, "System:Account is a map, therefore requires precisely one argument. " +
76+
"received: 0")
77+
78+
_, err = CreateStorageKey(m, "System", "Account", nil, []byte{})
79+
assert.EqualError(t, err, "System:Account is a map, therefore requires precisely one argument. " +
80+
"received: 0")
81+
82+
_, err = CreateStorageKey(m, "System", "Account", nil, []byte{0x01})
83+
assert.EqualError(t, err, "non-nil arguments cannot be preceded by nil arguments")
84+
85+
accountIdSerialized := MustHexDecodeString(AlicePubKey)
86+
87+
// Build expected answer
88+
expectedKeyBuilder := strings.Builder{}
89+
hexStr, err := Hex(xxhash.New128([]byte("System")).Sum(nil))
90+
assert.NoError(t, err)
91+
expectedKeyBuilder.WriteString(hexStr)
92+
hexStr, err = Hex(xxhash.New128([]byte("Account")).Sum(nil))
93+
assert.NoError(t, err)
94+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
95+
accountIdHasher, err := hash.NewBlake2b128Concat(nil)
96+
assert.NoError(t, err)
97+
_, err = accountIdHasher.Write(accountIdSerialized)
98+
assert.NoError(t, err)
99+
hexStr, err = Hex(accountIdHasher.Sum(nil))
100+
assert.NoError(t, err)
101+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
102+
103+
key, err := CreateStorageKey(m, "System", "Account", accountIdSerialized)
104+
assert.NoError(t, err)
105+
hex, err := Hex(key)
106+
assert.NoError(t, err)
107+
assert.Equal(t, expectedKeyBuilder.String(), hex)
108+
}
109+
110+
func TestCreateStorageKeyArgValidationForDoubleMapKey(t *testing.T) {
111+
m := ExamplaryMetadataV13
112+
113+
_, err := CreateStorageKey(m, "Staking", "ErasStakers")
114+
assert.EqualError(t, err, "Staking:ErasStakers is a double map, therefore requires precisely two " +
115+
"arguments. received: 0")
116+
117+
_, err = CreateStorageKey(m, "Staking", "ErasStakers", nil)
118+
assert.EqualError(t, err, "Staking:ErasStakers is a double map, therefore requires precisely two " +
119+
"arguments. received: 0")
120+
121+
_, err = CreateStorageKey(m, "Staking", "ErasStakers", nil, []byte{})
122+
assert.EqualError(t, err, "Staking:ErasStakers is a double map, therefore requires precisely two " +
123+
"arguments. received: 0")
124+
125+
_, err = CreateStorageKey(m, "Staking", "ErasStakers", nil, []byte{0x01})
126+
assert.EqualError(t, err, "non-nil arguments cannot be preceded by nil arguments")
127+
128+
_, err = CreateStorageKey(m, "Staking", "ErasStakers", []byte{0x01})
129+
assert.EqualError(t, err, "Staking:ErasStakers is a double map, therefore requires precisely two " +
130+
"arguments. received: 1")
131+
132+
// Serialize EraIndex and AccountId
133+
accountIdSerialized := MustHexDecodeString(AlicePubKey)
134+
var eraIndex uint32 = 3
135+
eraIndexSerialized := make([]byte, 4)
136+
binary.LittleEndian.PutUint32(eraIndexSerialized, eraIndex)
137+
138+
// Build expected answer
139+
expectedKeyBuilder := strings.Builder{}
140+
hexStr, err := Hex(xxhash.New128([]byte("Staking")).Sum(nil))
141+
assert.NoError(t, err)
142+
expectedKeyBuilder.WriteString(hexStr)
143+
hexStr, err = Hex(xxhash.New128([]byte("ErasStakers")).Sum(nil))
144+
assert.NoError(t, err)
145+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
146+
hexStr, err = Hex(xxhash.New64Concat(eraIndexSerialized).Sum(nil))
147+
assert.NoError(t, err)
148+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
149+
hexStr, err = Hex(xxhash.New64Concat(accountIdSerialized).Sum(nil))
150+
assert.NoError(t, err)
151+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
152+
153+
key, err := CreateStorageKey(m, "Staking", "ErasStakers", eraIndexSerialized, accountIdSerialized)
154+
assert.NoError(t, err)
155+
hex, err := Hex(key)
156+
assert.NoError(t, err)
157+
158+
assert.Equal(t, expectedKeyBuilder.String(), hex)
159+
}
160+
161+
func TestCreateStorageKeyArgValidationForNMapKey(t *testing.T) {
162+
m := ExamplaryMetadataV13
163+
//"Assets", "Approvals", "AssetId(u32)", "AccountId", "AccountId"
164+
165+
_, err := CreateStorageKey(m, "Assets", "Approvals")
166+
assert.EqualError(t, err, "Assets:Approvals is a nmap, therefore requires that number of arguments " +
167+
"should exactly match number of hashers in metadata. Expected: 3, received: 0")
168+
169+
_, err = CreateStorageKey(m, "Assets", "Approvals", nil)
170+
assert.EqualError(t, err, "Assets:Approvals is a nmap, therefore requires that number of arguments " +
171+
"should exactly match number of hashers in metadata. Expected: 3, received: 0")
172+
173+
_, err = CreateStorageKey(m, "Assets", "Approvals", nil, []byte{})
174+
assert.EqualError(t, err, "Assets:Approvals is a nmap, therefore requires that number of arguments " +
175+
"should exactly match number of hashers in metadata. Expected: 3, received: 0")
176+
177+
_, err = CreateStorageKey(m, "Assets", "Approvals", nil, []byte{0x01})
178+
assert.EqualError(t, err, "non-nil arguments cannot be preceded by nil arguments")
179+
180+
_, err = CreateStorageKey(m, "Assets", "Approvals", []byte{0x01})
181+
assert.EqualError(t, err, "Assets:Approvals is a nmap, therefore requires that number of arguments " +
182+
"should exactly match number of hashers in metadata. Expected: 3, received: 1")
183+
184+
// Serialize EraIndex and AccountId
185+
var assetId uint32 = 3
186+
assetIdSerialized := make([]byte, 4)
187+
binary.LittleEndian.PutUint32(assetIdSerialized, assetId)
188+
// Will be used both as owner as well as delegate
189+
accountIdSerialized := MustHexDecodeString(AlicePubKey)
190+
191+
// Build expected answer
192+
expectedKeyBuilder := strings.Builder{}
193+
hexStr, err := Hex(xxhash.New128([]byte("Assets")).Sum(nil))
194+
assert.NoError(t, err)
195+
expectedKeyBuilder.WriteString(hexStr)
196+
hexStr, err = Hex(xxhash.New128([]byte("Approvals")).Sum(nil))
197+
assert.NoError(t, err)
198+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
199+
// Hashing serialized asset id
200+
assetIdHasher, err := hash.NewBlake2b128Concat(nil)
201+
assert.NoError(t, err)
202+
_, err = assetIdHasher.Write(assetIdSerialized)
203+
assert.NoError(t, err)
204+
hexStr, err = Hex(assetIdHasher.Sum(nil))
205+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
206+
// Hashing serialized account id
207+
accountIdHasher, err := hash.NewBlake2b128Concat(nil)
208+
assert.NoError(t, err)
209+
_, err = accountIdHasher.Write(accountIdSerialized)
210+
assert.NoError(t, err)
211+
hexStr, err = Hex(accountIdHasher.Sum(nil))
212+
// Writing it multiple times as both owner and delegate
213+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
214+
expectedKeyBuilder.WriteString(strings.TrimPrefix(hexStr, "0x"))
215+
216+
217+
key, err := CreateStorageKey(m, "Assets", "Approvals", assetIdSerialized, accountIdSerialized,
218+
accountIdSerialized)
219+
assert.NoError(t, err)
220+
hex, err := Hex(key)
221+
assert.NoError(t, err)
222+
223+
assert.Equal(t, expectedKeyBuilder.String(), hex)
224+
}
225+
30226
func TestCreateStorageKeyPlainV13(t *testing.T) {
31227
m := ExamplaryMetadataV13
32228

33-
key, err := CreateStorageKey(m, "Timestamp", "Now", nil)
229+
key, err := CreateStorageKey(m, "Timestamp", "Now")
34230
assert.NoError(t, err)
35231
hex, err := Hex(key)
36232
assert.NoError(t, err)
@@ -40,7 +236,7 @@ func TestCreateStorageKeyPlainV13(t *testing.T) {
40236
func TestCreateStorageKeyPlainV10(t *testing.T) {
41237
m := ExamplaryMetadataV10
42238

43-
key, err := CreateStorageKey(m, "Timestamp", "Now", nil)
239+
key, err := CreateStorageKey(m, "Timestamp", "Now")
44240
assert.NoError(t, err)
45241
hex, err := Hex(key)
46242
assert.NoError(t, err)
@@ -50,7 +246,7 @@ func TestCreateStorageKeyPlainV10(t *testing.T) {
50246
func TestCreateStorageKeyPlainV9(t *testing.T) {
51247
m := ExamplaryMetadataV9
52248

53-
key, err := CreateStorageKey(m, "Timestamp", "Now", nil)
249+
key, err := CreateStorageKey(m, "Timestamp", "Now")
54250
assert.NoError(t, err)
55251
hex, err := Hex(key)
56252
assert.NoError(t, err)
@@ -60,7 +256,7 @@ func TestCreateStorageKeyPlainV9(t *testing.T) {
60256
func TestCreateStorageKeyPlainV4(t *testing.T) {
61257
m := ExamplaryMetadataV4
62258

63-
key, err := CreateStorageKey(m, "Timestamp", "Now", nil)
259+
key, err := CreateStorageKey(m, "Timestamp", "Now")
64260
assert.NoError(t, err)
65261
hex, err := Hex(key)
66262
assert.NoError(t, err)

0 commit comments

Comments
 (0)