Creating a Smart Contract having Iterable Mapping

RayonProtocol
RayonProtocol
Published in
4 min readAug 31, 2018
iterable-mapping

Smart contracts created with Solidity provide a mapping type for storing key-value pairs. This mapping type is useful for storing or reading value values ​​for a specific key. However, it does not provide an iteration function to retrieve all the lists stored in the mapping, or to sequentially read the value by repeating the list.

In this article, let’s look at a pattern that iterates lists stored in a mapping. You’ll also notice some things to keep in mind when adding a new list to a mapping or deleting an existing list.

Non-iterable smart contract with only mapping

Let’s look at a smart contract example that includes a mapping that has an address type as key and a byte32 type as value

It contains maps, add, remove, contains, and getByKey functions of type mapping (address => bytes32)

The mapping type provides the ability to store and retrieve values ​​for a particular key. However, it does not provide the ability to return an iterable list of keys. If you want to create an iterable mapping, you must include additional functionality.

Things to consider when creating an iterable mapping

1. Save the mapping keys as an array

Add a keyList to the array to record the keys stored in the map. The keyList is composed of an array of addresses which are the type corresponding to the key of the map.

The add function adds a key to the keyList in addition to writing the value to map.

A size function that returns the length of the entire map with keyList, and a getKeys function that returns a complete list of keys have been added.

In the above example, there are some not included features.

  • The existing key in add function has not been processed.
  • remove function is not implemented.
  • Determines whether it is not a scored value with the value 0 in the contains function. There is a constraint that the value in the map can not be zero.

The common points of the above items are the problems that arise because the index value of the keyList can not be known to the key input when add and remove function are executed. You can loop through all the items in keyList to find the index value, but it is necessary to record the index position of the keyList because it is inefficient.

2. Record the index value of the array together

Let’s store the index value of the keyList in the value stored in the map.

Create a new struct to create an Entry that contains a value and an index, and replace it with the value type of the mapping.

The Entry struct contains the value of the value and the index of the keyList. Note that the index value is the real index value of keyList plus one. The index of the keyList has a value ranging from 0 to (length-1). Since 0 is used as a value for indicating an item having no value, a value of 1 to length is recorded in the Entry.

If we look at the contents of the add function, we find the entry in the map from the input key value and compare the stored index value. If index = 0, add a new item to the keyList with push function. Then, the value of Entry.index is stored as the index in keyList plus one.

The contains function determines whether the index value of the Entry is 0, as described above. In this case, you can store a value of 0 as a value.

The remove function is not included, but is described in the next section.

3. Remove an array item when implementing remove

The remove function is more complicated than add. You can find the entry in the map and delete it with the input key value, and get the index value to delete the keyList. There are considerations when deleting an item from an Array. When you add a new item to keyList, you can easily add an item with the push function of Array type. However, when deleting an item, it is necessary to implement the operation of directly changing the index of the array.

If you look at lines 2 through 4, find the entry in the map with the key value entered in the remove function. Checking the entry.index value causes an error if it is an entry without an entry or an invalid index value.

If you look at lines 7 through 11, it is the process of removing the index item from the keyList. Array does not provide a function for deletion. When delete keyList [index] is executed, the corresponding item value is changed to 0, and the item of keyList is not deleted. So here we move the value of the last item of the keyList to the index, and delete the last item. The deletion of the last item in the keyList only needs to reduce the value of keyList.length by one. delete keyList [keyList.length-1] does not need to consume gas while executing it because it changes the value to 0 only.

Line 12 is the process of deleting the items in the map.

Final code

The following is a summary of the smart contract example with the iterable mapping.

You can check the example code and test code through github ( https://github.com/rayonprotocol-research/solidity-iterable-mapping ).

--

--