Use the mapping data type to store key-value pairs.
mapping
. mapping
s are a powerful tool with many uses, but they also have some unexpected limitations. They also aren’t actually hash tables!
msg.sender
global variablemapping
data type appears to be just another hash table implementation that stores pairs of any hashable type as a key, to any other type as a value. The difference is in implementation.
In a more traditional implementation, the data is stored in memory as an array, with a hash-to-index (hashmod) function used to determine which spot in the array to store a given value, based on the key. Sometimes, the hashmod function for two different keys results in the same index, causing a collision.
Collisions are resolved via additional solutions, such as linked list chaining; when the underlying array starts to get full, a bigger one is created, all the keys are re-hash-modded, and all the values moved over to the new array.
In the EVM, mappings
do not have an array as the underlying data structure. Instead, the keccak256
hash of the key plus the storage slot for the mapping itself is used to determine which storage slot out of all 2**256 will be used for the value.
There is no collision-handling, for the same reason that makes wallets work at all - 2**256 is an unimaginably large number. One of the biggest numbers you might encounter regularly is the number of possible configurations for a shuffled deck of cards, which is:
80658175170943878571660636856403766975289505440883277824000000000000
Meanwhile, the number of variations of a keccak256
hash are:
115792089237316195423570985008687907853269984665640564039457584007913129639935
Collisions are very unlikely.
As a result, there are a few special characteristics and limitations to keep in mind with the mapping
data type:
storage
Mappings
. In it, add a mapping
from an address
to a uint
called favoriteNumbers
.
Reveal code
saveFavoriteNumber
that takes an address
and uint
, then saves the uint
in the mapping, with the address
as the key.
Reveal code
favoriteNumber
, but this problem is easy to correct. Similar to arrays, if you mark a mapping
as public, the Solidity compiler will automatically create a getter for values in that mapping
.
Update the declaration of favoriteNumbers
and deploy to test again.
public
function can be called by anyone and everyone with a wallet and funds to pay gas fees. As a result, anyone could go in after you and change your favorite number from lucky number 13 to anything, even 7!
That won’t do at all!
Luckily, you can make use of a global variable called msg.sender
to access the address
of the wallet that sent the transaction. Use this to make it so that only the owner of an address
can set their favorite number.
Reveal code
mapping
data type is that it is not iterable - you cannot loop through and manipulate or return all values in the mapping
.
At least not with any built-in features, but you can solve this on your own. A common practice in Solidity with this and similar problems is to use multiple variables or data types to store the right combination needed to address the issue.
favoriteNumbers
. Simply add the array, and push new keys to it when saving a new favorite number.
Reveal code
addressesOfFavs
, look up that addresses’ favorite number, add it to a return array, and then return the array when you’re done.
Reveal code
address
already has a number as a value in favoriteNumbers
, and only push it to the array if not.
Reveal code
Reveal code
mapping
data type to store key-value pairs in Solidity. You’ve also explored one strategy for solving some of the limitations found in the mapping
type when compared to similar types in other languages.