Storage in substrate -Part2
Amit Nadiger
Polyglot(Rust??, C++ 11,14,17,20, C, Kotlin, Java) Android TV, Cas, Blockchain, Polkadot, UTXO, Substrate, Wasm, Proxy-wasm,AndroidTV, Dvb, STB, Linux, Engineering management.
I will be discussing about each of the below storage methods in detail in this article.
What Are Simple StorageValue?
Simple storage values in Substrate are a way to store individual data units efficiently on the blockchain. They are suitable for a wide range of use cases but require careful consideration of data size and performance to ensure smooth blockchain operation, especially in parachain projects.
Simple storage values are a way to store data on the blockchain. They are designed for values that are considered a single unit by the runtime. These values are commonly used for various purposes, including:
Considerations for Simple Storage Values:
When working with simple storage values, there are a few important considerations to keep in mind:
StorageValue Documentation:
To explore the full capabilities and methods of StorageValue, Lets refer StorageValue in frame_support::storage - Rust (paritytech.github.io)
Below define 3 different ways of storage items within a Substrate runtime module, each with its own type and accessibility which allows us to store and retrieve data on the blockchain in an organized and efficient manner, catering to various data types and runtime configurations.
1. SomePrivateValue:
#[pallet::storage]
type SomePrivateValue<T> = StorageValue<_, u32, ValueQuery>;
2. SomePrimitiveValue:
#[pallet::storage]
#[pallet::getter(fn some_primitive_value)]
pub(super) type SomePrimitiveValue<T> = StorageValue<_, u32, ValueQuery>;
SomePrimitiveValue is another storage item, similar to SomePrivateValue, but with a few differences:
It has a getter function specified using #[pallet::getter(fn some_primitive_value)]. This means that other parts of the code can access this value using some_primitive_value as a function call.
pub(super) indicates that this storage item is publicly accessible within the module (pub) but not outside of it (super limits access to the module itself).
Like SomePrivateValue, it stores a single value of type u32 and can be queried (ValueQuery).
3. SomeComplexValue:
#[pallet::storage]
pub(super) type SomeComplexValue<T: Config> = StorageValue<_, T::AccountId, ValueQuery>;
Single Key Storage Maps in Substrate:
Single key storage maps in Substrate are a way to efficiently manage and access data where each element has a unique key. You can choose the hashing algorithm that best suits your needs, and Substrate provides documentation to help you understand how to use these maps effectively.
Single key storage maps are data structures used to manage sets of items where elements need to be accessed randomly, rather than sequentially. These maps work similarly to traditional hash maps, where each element has a unique key associated with it, allowing for efficient random lookups.
Key-to-Value Mapping:
Customizable Hashing Algorithm:
Selecting the Right Hashing Algorithm:
StorageMap Methods:
Example :
Below code defines a storage map named SomeMap within a Substrate runtime module. It's a map that associates user/account IDs (of type T::AccountId) with 32-bit unsigned integers. Users can use the some_map getter function to access and query the values stored in this map within the runtime. The data is stored using the Blake2_128Concat hashing algorithm for efficient key storage.
#[pallet::storage]
#[pallet::getter(fn some_map)]
pub(super) type SomeMap<T: Config> = StorageMap<
_,
Blake2_128Concat, T::AccountId,
u32,
ValueQuery
>;
领英推荐
Double Key Storage Maps:
In blockchain development, storage is crucial for keeping track of data. A "DoubleStorageMap" is a specialized data structure that is used to store information in a way that involves two keys instead of just one.
DoubleStorageMap is a data structure that stores information using two keys, making it particularly useful when you need to retrieve data based on two pieces of related information. It's a way to efficiently handle common queries in a blockchain application.
Example:
The below code defines a Double Map storage item named SomeDoubleMap. It allows you to store values associated with a combination of two keys: a u32 and an account ID (represented by T::AccountId). The hashing algorithms Blake2_128Concat are used to efficiently manage these keys in storage. This storage item is available within the module and its submodules and can be used to store and query data in the Substrate runtime.
#[pallet::storage]
pub(super) type SomeDoubleMap<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat, u32,
Blake2_128Concat, T::AccountId,
u32,
ValueQuery
>;
Here StorageDoubleMap is a special type provided by Substrate for defining a storage item that uses a double map data structure.
Similar to Single Key Storage Maps:
DoubleStorageMap works similarly to a "Single Key Storage Map," which is a common way to store data on a blockchain. In a Single Key Storage Map, you have a key-value pair, where you can retrieve a value by providing a specific key.
Two Keys for Common Queries:
The key feature of a DoubleStorageMap is that it uses two keys. This is especially useful when you need to query or retrieve values based on two pieces of information that are commonly used together.
Example:
Imagine you're building a blockchain application for a library. In a Single Key Storage Map, you might store books by their ISBN (International Standard Book Number), and you can easily find a book by its ISBN.
However, if you want to add the ability to search for books by both ISBN and author's name, a DoubleStorageMap is handy. You can use one key for ISBN and another for the author's name. This way, you can efficiently query the database for books using either the ISBN or the author's name, or even both together.
Why It's Useful:
Using a DoubleStorageMap makes sense when you have data that is commonly looked up or queried using a combination of two attributes or keys. It helps optimize the way data is stored and retrieved, enhancing the efficiency of your blockchain application.
Multi-Key Storage Maps:
In blockchain development, storage is a fundamental concept. It's where you store data that needs to be maintained on the blockchain. Storage maps are a way to organize and store data efficiently. They allow you to associate a key with a value, making it easy to retrieve and update data.
StorageNMap:
StorageNMap is a type of storage structure in Substrate (a blockchain development framework). It's similar to single-key and double-key storage maps, but with a significant difference: it enables you to define and use any number of keys for each entry in the map.
Defining Keys in StorageNMap:
To use StorageNMap, you need to specify the keys you want to use. These keys are defined as a tuple containing the NMapKey struct. The number of keys you specify in the tuple determines how many keys you can use for each entry in the map.StorageNMap in frame_support::storage - Rust (paritytech.github.io)
Example :
The below code defines a multi-key storage map named SomeNMap that can store u32 values. It uses three different key types with their corresponding hashing algorithms for indexing values in the storage map. This storage map is associated with a Substrate pallet and can be accessed within the current module and its submodules. The actual behavior and usage of this storage map would depend on the context and functionality of the Substrate runtime module in which it is defined.
#[pallet::storage]
#[pallet::getter(fn some_nmap)]
pub(super) type SomeNMap<T: Config> = StorageNMap<
_,
(
NMapKey<Blake2_128Concat, u32>,
NMapKey<Blake2_128Concat, T::AccountId>,
NMapKey<Twox64Concat, u32>,
),
u32,
ValueQuery,
>;
Handling Query Return Values in Storage:
In a blockchain's storage system, we can declare how queries should behave when they try to retrieve a value, but there's no value stored for the specified key. This is important because it allows us to handle cases where data might or might not exist in storage.
Three Query Options:
Practical Use:
These three query options (OptionQuery, ResultQuery, and ValueQuery) allow developers to handle different scenarios when querying data from a blockchain's storage system. They provide flexibility in dealing with situations where data may or may not exist, and they allow for various error-handling and default value strategies.
When we declare a storage item in a blockchain's runtime, we can choose how queries should respond to it. We can use OptionQuery if we are okay with the possibility of no data, ResultQuery if we expect data and want an error otherwise, or ValueQuery for straightforward retrieval with optional defaults. These choices allow developers to handle data retrieval and errors in a way that makes sense for their specific use cases.
Let me end this article here , will write a separate article on below topics which are demonstrated in the above examples :
Thanks for reading till end . Please comment of you have anything :
Referance : Runtime storage structures | Substrate_ Docs