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  }