Use Maps for Storing Values
Use mapping to store data as key-value pairs.
Last updated
Use mapping to store data as key-value pairs.
Last updated
In , you developed a smart contract for storing and retrieving a single numeric value.
This tutorial illustrates how you can extend the functionality of your smart contract to manage one number per user. To add this functionality, you'll use the type.
The ink! language provides the Mapping type to enable you to store data as key-value pairs. For example, the following code illustrates mapping a user to a number:
With the Mapping
data type, you can store a unique instance of the storage value for each key.
For this tutorial, each AccountId
represents a key that maps to one and only one stored numeric my_map
.
Each user can only store, increment, and retrieve the value associated with their own AccountId
.
Mapping
The first step is to initialize the mapping between an AccountId
and a stored value.
Specify the mapping key and the value mapped to it.
The following example illustrates how to initialize a Mapping
and retrieve a value:
In the preceding example, you might have noticed the Self::env().caller()
function call.
This function is available throughout the contract logic and always returns the contract caller.
It is important to note that the contract caller is not the same as the origin caller.
If a user accesses a contract that then calls a subsequent contract, the Self::env().caller()
in the second contract is the address of the first contract, not the original user.
There are many scenarios where having the contract caller available is useful.
For example, you can use Self::env().caller()
to create an access control layer that only allows users to access their own values.
You can also use Self::env().caller()
to save the contract owner during contract deployment.
For example:
Because you have saved the contract caller using the owner
identifier, you can later write functions that check whether the current contract caller is the owner of the contract.
You are now ready to introduce a storage map to the incrementer
contract.
To add a storage map to the incrementer
contract:
Open a terminal shell on your computer, if needed.
Verify that you are in the incrementer
project folder.
Open the lib.rs
file in a text editor.
Import the Mapping
type.
Add the mapping key from AccountId
to the i32
data type stored as my_map
.
In the new
constructor create a new Mapping
and use that to initialize your contract.
In the default
constructor add a new default Mapping
along with the already defined default value
.
Add a get_mine()
function to read my_map
using the Mapping API's get()
method and return my_map
for the contract caller.
Add a new test to the initialize accounts.
Save your changes and close the file.
Use the test
subcommand and nightly
toolchain to test your work by running the following command:
The command should display output similar to the following to indicate successful test completion:
The final step in the Incrementer
contract is to allow users to update their own values.
You can use calls to the Mapping API to provide this functionality in the smart contract.
The Mapping
provides direct access to storage items.
For example, you can replace a previous value held for a storage item by calling Mapping::insert()
with an existing key.
You can also update values by first reading them from storage using Mapping::get()
, then update the value with Mapping::insert()
.
If there is no existing value at a given key, Mapping::get()
returns None
.
Because the Mapping API provides direct access to storage, you can use the Mapping::remove()
method to remove the value at a given key from storage.
To add insert and remove functions to the contract:
Open a terminal shell on your computer, if needed.
Verify that you are in the incrementer
project folder.
Open the lib.rs
file in a text editor.
Add an inc_mine()
function that allows the contract caller to get the my_map
storage item and insert an incremented value
into the mapping.
Add a remove_mine()
function that allows the contract caller to clear the my_map
storage item from storage.
Add a new test to verify that the inc_mine()
functions works as expected.
Add a new test to verify that the remove_mine()
functions works as expected.
Check your work using the test
subcommand:
The command should display output similar to the following to indicate successful test completion:
In this tutorial, you learned how to use the ink::storage::Mapping
type and Mapping API in a smart contract. For example, this tutorial illustrated:
How to initialize a mapping for storing key-value pairs.
How to identify and use the contract caller in a smart contract.
How to add functions that enable users to insert and remove the values stored for them in a map using a smart contract.
You can learn more about smart contract development in the following topics:
You can find an example of the final code for this tutorial in the assets for the .