github.com/stafiprotocol/go-substrate-rpc-client@v1.4.7/types/storage_key.go (about) 1 // Go Substrate RPC Client (GSRPC) provides APIs and types around Polkadot and any Substrate-based chain RPC calls 2 // 3 // Copyright 2020 Stafi Protocol 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package types 18 19 import ( 20 "fmt" 21 "io" 22 23 "github.com/stafiprotocol/go-substrate-rpc-client/pkg/scale" 24 "github.com/stafiprotocol/go-substrate-rpc-client/xxhash" 25 ) 26 27 // StorageKey represents typically hashed storage keys of the system. 28 // Be careful using this in your own structs – it only works as the last value in a struct since it will consume the 29 // remainder of the encoded data. The reason for this is that it does not contain any length encoding, so it would 30 // not know where to stop. 31 type StorageKey []byte 32 33 // NewStorageKey creates a new StorageKey type 34 func NewStorageKey(b []byte) StorageKey { 35 return b 36 } 37 38 // CreateStorageKey uses the given metadata and to derive the right hashing of method, prefix as well as arguments to 39 // create a hashed StorageKey 40 // Using variadic argument, so caller do not need to construct array of arguments 41 func CreateStorageKey(meta *Metadata, prefix, method string, args ...[]byte) (StorageKey, error) { 42 stringKey := []byte(prefix + " " + method) 43 44 entryMeta, err := meta.FindStorageEntryMetadata(prefix, method) 45 if err != nil { 46 return nil, err 47 } 48 49 if entryMeta.IsNMap() { 50 return createKeyNMap(method, prefix, args, entryMeta) 51 } 52 53 if entryMeta.IsDoubleMap() { 54 if len(args) != 2 { 55 return nil, fmt.Errorf("%v is a double map, therefore requires precisely two arguments. received: %d", method, len(args)) 56 } 57 return createKeyDoubleMap(meta.Version, method, prefix, stringKey, args[0], args[1], entryMeta) 58 } 59 60 //if len(args) != 1 { 61 // return nil, fmt.Errorf("%v is a map, therefore requires precisely one argument. received: %d", method, len(args)) 62 //} 63 return createKey(meta.Version, method, prefix, stringKey, args[0], entryMeta) 64 } 65 66 func CreateStorageKeyWithEntryMeta(version uint8, entryMeta StorageEntryMetadata, prefix, method string, args ...[]byte) (StorageKey, error) { 67 stringKey := []byte(prefix + " " + method) 68 69 //entryMeta, err := meta.FindStorageEntryMetadata(prefix, method) 70 //if err != nil { 71 // return nil, err 72 //} 73 74 if entryMeta.IsNMap() { 75 return createKeyNMap(method, prefix, args, entryMeta) 76 } 77 78 if entryMeta.IsDoubleMap() { 79 if len(args) != 2 { 80 return nil, fmt.Errorf("%v is a double map, therefore requires precisely two arguments. received: %d", method, len(args)) 81 } 82 return createKeyDoubleMap(version, method, prefix, stringKey, args[0], args[1], entryMeta) 83 } 84 85 //if len(args) != 1 { 86 // return nil, fmt.Errorf("%v is a map, therefore requires precisely one argument. received: %d", method, len(args)) 87 //} 88 return createKey(version, method, prefix, stringKey, args[0], entryMeta) 89 } 90 91 // Encode implements encoding for StorageKey, which just unwraps the bytes of StorageKey 92 func (s StorageKey) Encode(encoder scale.Encoder) error { 93 return encoder.Write(s) 94 } 95 96 // Decode implements decoding for StorageKey, which just reads all the remaining bytes into StorageKey 97 func (s *StorageKey) Decode(decoder scale.Decoder) error { 98 for i := 0; true; i++ { 99 b, err := decoder.ReadOneByte() 100 if err == io.EOF { 101 break 102 } 103 if err != nil { 104 return err 105 } 106 *s = append((*s)[:i], b) 107 } 108 return nil 109 } 110 111 // Hex returns a hex string representation of the value (not of the encoded value) 112 func (s StorageKey) Hex() string { 113 return fmt.Sprintf("%#x", s) 114 } 115 116 func createKeyNMap(method, prefix string, args [][]byte, entryMeta StorageEntryMetadata) (StorageKey, error) { 117 hashers, err := entryMeta.Hashers() 118 if err != nil { 119 return nil, err 120 } 121 122 if len(hashers) != len(args) { 123 return nil, fmt.Errorf("number of arguments should exactly match number of hashers in metadata. Expected: %d, received: %d", len(hashers), len(args)) 124 } 125 126 key := createPrefixedKey(method, prefix) 127 128 for i, arg := range args { 129 hashers[i].Write(arg) 130 key = append(key, hashers[i].Sum(nil)...) 131 } 132 133 return key, nil 134 } 135 136 // createKeyDoubleMap creates a key for a DoubleMap type 137 func createKeyDoubleMap(version uint8, method, prefix string, stringKey, arg, arg2 []byte, 138 entryMeta StorageEntryMetadata) (StorageKey, error) { 139 if arg == nil || arg2 == nil { 140 return nil, fmt.Errorf("%v is a DoubleMap and requires two arguments", method) 141 } 142 143 hasher, err := entryMeta.Hasher() 144 if err != nil { 145 return nil, err 146 } 147 148 hasher2, err := entryMeta.Hasher2() 149 if err != nil { 150 return nil, err 151 } 152 153 if version <= 8 { 154 _, err := hasher.Write(append(stringKey, arg...)) 155 if err != nil { 156 return nil, err 157 } 158 _, err = hasher2.Write(arg2) 159 if err != nil { 160 return nil, err 161 } 162 return append(hasher.Sum(nil), hasher2.Sum(nil)...), err 163 } 164 165 _, err = hasher.Write(arg) 166 if err != nil { 167 return nil, err 168 } 169 _, err = hasher2.Write(arg2) 170 if err != nil { 171 return nil, err 172 } 173 174 key := createPrefixedKey(method, prefix) 175 key = append(key, hasher.Sum(nil)...) 176 key = append(key, hasher2.Sum(nil)...) 177 178 return key, nil 179 } 180 181 // createKey creates a key for either a map or a plain value 182 func createKey(version uint8, method, prefix string, stringKey, arg []byte, entryMeta StorageEntryMetadata) ( 183 StorageKey, error) { 184 if entryMeta.IsMap() && arg == nil { 185 return nil, fmt.Errorf("%v is a Map and requires one argument", method) 186 } 187 188 hasher, err := entryMeta.Hasher() 189 if err != nil { 190 return nil, err 191 } 192 193 if version <= 8 { 194 _, err := hasher.Write(append(stringKey, arg...)) 195 return hasher.Sum(nil), err 196 } 197 198 if entryMeta.IsMap() { 199 _, err := hasher.Write(arg) 200 if err != nil { 201 return nil, err 202 } 203 arg = hasher.Sum(nil) 204 } 205 206 return append(createPrefixedKey(method, prefix), arg...), nil 207 } 208 209 func createPrefixedKey(method, prefix string) []byte { 210 return append(xxhash.New128([]byte(prefix)).Sum(nil), xxhash.New128([]byte(method)).Sum(nil)...) 211 }