Solidity Tutorial: Mappings

Solidity Tutorial: Mappings

In the previous episode, we discussed arrays and how to use them. From the example, we had studentAges as an array where we knew the element's index, so we could easily fetch the index value. But, what if we don't actually know the index? How do we fetch such element values? Let us talk about mappings.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

contract Mapping {
    // Mapping from address to uint
    mapping(address => uint) public myMap;
}

This is how we write a basic mapping in solidity. A mapping is a data type that allows for the storage of key-value pairs, where the keys are unique and cannot be changed. Mappings are similar to JavaScript objects or Python dictionaries, but they are stored on the Ethereum blockchain. They are used to create and manage smart contract state, and they can be used to store data such as user balances, account information, and other types of data. Mappings are typically declared using the mapping keyword, followed by the types of the key and value.

Another important aspect of mappings is that they are not iterable, which means you can't loop through them like arrays or structs. However, you can use the keccak256() function to create a unique hash of the key, which can then be used to access the value associated with the key.

Mappings and arrays are similar in that they both allow you to store multiple pieces of data in a single variable. However, they have some key differences:

  1. Keys: In mappings, the keys are unique and cannot be changed, whereas in arrays, the keys are integers (indices) and they can be changed by adding or removing elements.

  2. Data types: In mappings, the keys and values can be of any data type, whereas in arrays, the elements must be of the same data type.

  3. Access: In mappings, you can access a specific value by providing its key, whereas in arrays, you must provide the index of the element you want to access.

  4. Storage: In mappings, the keys and values are stored on the blockchain and consume gas when read or written. In arrays, the elements are stored on the blockchain but are not indexed, so reading an element from an array consumes more gas than reading from a mapping.

  5. Usage: Mappings are generally used when you want to store data that can be accessed by a unique key, such as user balances, account information, etc. Arrays are generally used when you want to store a collection of elements that you need to iterate over, such as a list of students in a class.

Now back to our student's ages in a class use case. We can write this using a mapping as follows

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.3;

contract StudentAges {

    // Define a struct to store student information
    struct Student {
        string name;
        uint age;
    }

    // Create a public mapping to store student information
    mapping(address => Student) public students;

    /**
     * Add a new student to the contract
     * @param student: Ethereum address of the student
     * @param studentName: name of the student
     * @param age: age of the student
     */
    function addStudent (address student, string memory studentName, uint age) public {
        students[student] = Student({
            name: studentName,
            age: age
        });
    }

    /**
     * Retrieve the age of a student
     * @param student: Ethereum address of the student
     * @return age of the student
     */
    function getAge(address student) public view returns (uint) {
        return students[student].age;
    }
}

So guys, this contract is called "StudentAges". The contract defines a struct called "Student" that has two fields: "name" and "age", both of which are strings and unsigned integers, respectively.

It also creates a public mapping called "students" that maps an Ethereum address to a "Student" struct. This mapping is used to store student information.

The contract has two public functions: "addStudent" and "getAge". The "addStudent" function takes in three parameters: an Ethereum address of the student, a string representing the name of the student, and an unsigned integer representing the age of the student. The function then adds the student information to the "students" mapping.

The "getAge" function takes in one parameter: an Ethereum address of the student, and returns the age of that student as an unsigned integer.

Now let us open this up on remix, deploy and actually interact with this contract.

From above, we have our 'addStudent' field, which requires us to parse in the student address, name and age. Once we do that, we can then retrieve the student's data from the 'getAge' field and the 'students' field by simply providing the address.

Now scroll up to access the accounts given to us by remix, so we can freely test out our codes. We have 10 accounts each preloaded with 100 eth for testing.

An account refers to a unique identity on the Ethereum blockchain that is associated with a private key. Accounts are used to interact with and deploy smart contracts, as well as to send and receive Ether (the native cryptocurrency of Ethereum) and other tokens. Each account has its own address, which is used to identify it on the blockchain, and a balance of Ether and tokens.

Click on the area marked red. You will see a dropdown of accounts available to us.

The first account is the deployer account, so we can simply choose the next account and copy its address.

We paste in the copied address into the address field, the name of the student into the studentName field and the age of 23 into the age field. Click transact, and we get our the transaction confirmation on the bottom right. Beautiful, now we test to see if our mappings based contract works fine.

Once we paste the address into the getAge field and click on the button we immediately get our result which is 23! That's our call report on the bottom right. We can do the same with the students field too.

Our student field gives us the students name and the age. X number of students can also be added into the contract and for instance in an actual classroom situation where there are 1000 students. This is a modified system where teachers can simply input the students addresses to get their names and ages.

In Conclusion

So we have gotten an overview of how mappings can be used in solidity to solve real world problems. Hope you learned something new.

Mappings are also highly efficient in terms of gas usage. Accessing a value in a mapping by its key takes constant time, regardless of the size of the mapping. This makes them a good choice for storing large amounts of data, such as a large database of user information.

To round up, mappings are an important and versatile data structure in Solidity, and are widely used in smart contract development to store and retrieve data in an efficient and organized way.

See you on the next episode!