33

I went through the Crowdfunding example in solidity where i encountered the following:

contract Crowdfunding {
struct CampaignData {
    address recipient;
    uint contributed;
    uint goal;
    uint deadline;
    uint num_contributions;
    mapping(uint => Contribution) contributions;
}

struct Contribution {
    address contributor;
    uint amount;
}

uint nextCampaignId;
mapping(uint256 => CampaignData) campaigns;

// Start a new campaign.
function start(address recipient, uint256 goal, uint256 deadline) returns (uint id) {
    var campaign = campaigns[nextCampaignId];
    campaign.recipient = recipient;
    campaign.goal = goal;
    campaign.deadline = deadline;
    nextCampaignId ++;
    id = nextCampaignId;
}

What is really happening here?

Why did we use mapping? How is it helping us? I couldn't understand the working of it and hence not able to use it.

3 Answers 3

35

Anatomy of a Mapping

A mapping is used to structure value types, such as booleans, integers, addresses, and structs. It consists of two main parts: a _KeyType and a _ValueType; they appear in the following syntax:

mapping (_KeyType => _ValueType) mapName

In the example contract provided above,

mapping (uint256 => CampaignData) campaigns

the uint256 is the _KeyType and the CampaignData is the _ValueType. Note for later that the _ValueType, CampaignData, is a struct.

Mapping Value Types to Key Types

Think of the _KeyType as the key you'll pass through a function to be returned a desired value, or _ValueType. By default, a mapping is initially empty, so new a _KeyType will first need to be mapped to a _ValueType.

The example contract's start function handles 3 basic processes: (1) giving a _KeyType to a new _ValueType CampaignData struct; (2) populating the new CampaignData struct with variable values; and (3) procuring a new _KeyType nextCampaignID to be ready on deck for the next time the example contract's start function is called. This segments of the function can be dissected like so:

(1) giving a _KeyType to a new _ValueType CampaignData struct:

    var campaign = campaigns[nextCampaignId];

In this line, nextCampaignId is mapped as the _KeyType, and the new campaign struct is the _ValueType.

(2) populating the new CampaignData struct with variable values:

    campaign.recipient = recipient;
    campaign.goal = goal;
    campaign.deadline = deadline;

(3) procuring a new _KeyType nextCampaignID for the next time the function is called:

    nextCampaignId ++;

Using a mapping here is helpful because a mapping can store many _KeyTypes to _ValueTypes - in this case if there are many campaigns occurring at once they can each have their own campaignID. Each campaign having its own ID is powerful when calling for CampaignData in future functions.

Accessing Value Types from a Mapping with Key Types

This example contract actually does not provide any functions that access value types in the mapping. But we can imagine what one might look like: maybe if the deadline of a campaign is extended somehow, an extendDeadline function might look like:

function extendDeadline(uint campaignID, uint256 newDeadline) {
    var campaign = campaigns[campaignId];
    campaign.deadline = newDeadline;
}

The extendDeadline function would be using the campaignID _KeyType to query the campaigns mapping to find the appropriate CampaignData struct and update its deadline with the newDeadline.

1
  • 1
    So is it just plain kind of an array (not accessed by index) of javascript objects. This answer is kind of good but when I see it in code I still get confused. Dec 10, 2017 at 10:46
1

A mapping is a collection of key value pairs. So, if you are coming from the world of JavaScript you can think of mapping as being very similar to an object.

Coming from Ruby they are like hashes and if you are coming from Python they are like dictionaries.

The key thing to keep in mind about a mapping is that all of the keys have to be the same type and all the values have to be the same type as well.

All the keys have to be of the same type, we can designate mappings like so:

mapping(string => string)

We say mapping and specify the type of key we want to use, a little arrow and then the type of value we want to use.

Here is an example of mapping with key of type int and bool:

mapping(int => bool)

Mappings are most frequently used for storing collections of data.

0
  mapping(uint256 => CampaignData) campaigns;

Above mapping says, keys will be "uint" and the values will be "CampaignData" struct and label the variable with "campaigns". "CampaignData" could be stored in an array but looping through array would cost too much gas. In ethereum, every operation costs you and imagine you have thousands of campaigns stored and you need to look up for each campaign, this would cost tremendous amount of gas. Instead mapping is used because mapping has constant time search.

Mapping in solidity is similar to mapping in javascript but there are some differences:

1- In solidity, keys are not stored. Only the value which is stored at the state memory address calculated by hashing the key itself. In javascript we could retrieve all the "keys" into an array with Object.keys(objectName).

2- Values in solidity mapping are not iterable. We cannot loop over. Mapping is good only for single value lookup.

3- In solidity all values exist. In javascript, if we try to access a key that does not exist, objectName['keyThatDoesNotExist'] we get undefined. But in solidity, we get default value based on the values. If all values are strings, default value is emptry string '', if all values are integers, default value is 0, if all values are booleans default value is false.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.