Hi, here’s my answers.
Array-Based Design
// SPDX-License-Identifier: GPL 3.0
pragma solidity 0.7.5;
contract ArrayBasedDesign {
struct Entity {
uint data;
address entityAddress;
}
Entity[] entities;
function addEntity() public {
entities.push(Entity({
data: 0,
entityAddress: msg.sender
}));
}
function updateEntity(uint _updatedData) public {
for(uint i=0; i < entities.length; i++) {
if(msg.sender == entities[i].entityAddress) {
entities[i].data = _updatedData;
break;
}
}
}
}
Mapping-Based Design
// SPDX-License-Identifier: GPL 3.0
pragma solidity 0.7.5;
contract MappingBasedDesign {
struct Entity {
uint data;
address entityAddress;
}
mapping(address => Entity) entities;
function addEntity() public {
entities[msg.sender] = Entity({
data: 0,
entityAddress: msg.sender
});
}
function updateEntity(uint _updatedData) public {
entities[msg.sender].data = _updatedData;
}
}
Execution cost comparison table
Question #1
When executing the addEntity function, which design consumes the most gas (execution cost)?
The array design consumes the most gas when executing the addEntity (67888 gas; while the mapping design consumes 45752 gas).
Is it a significant difference?
I don’t know the threshold at which the difference of gas consumption starts to become significant.
I take a wild guess!
Because:
So, 22136 gas could be a significant difference.
Why?
I believe that the reason is the array design requires CREATE operations to create a new entity and append the entity to the array.
On the other hand, in the mapping design, when we add a new entity to the mapping, what goes under the hood is that every address is mapped to a default entity with data=0, entityAddress=0x0, so when the addEntity
is executed, the storage value entityAddress
is set to non-zero address from 0x0 and the storage value’s zeroness data
remains unchanged.
No such things as new entities being created or get pushed to the mapping (CREATE operations), only changing value from one state to the other or remaining unchanged (SSTORE operations).
The result is a significant difference of gas consumption between the two designs.
Question #2
Add 5 Entities into storage using the addEntity function and 5 different addresses. Then update the data of the fifth address you used. Do this for both contracts and take note of the gas consumption (execution cost).
Which solution consumes more gas?
The array design consumes more gas to update the data of the fifth address.
Why?
In the array design, the updateEntity
function needs to run a test on every element of the array until it finds out the right entity for the msg.sender
, then the function can possibly update the data of that entity.
Updating the 5th entity’s data consumes more gas (58599 gas) than the 2nd one’s (50997 gas), because finding the 2nd entity only takes 2 tests.
In the mapping design, without running a single test, the updateEntity
can identify the entity instantly and update its data.
Regardless of the order of an entity being added to the mapping, the amount of gas consumption is the same for updating every entity (43819 gas).
So, because of running multiple tests to identify the 5th entity before updating its data, the array design consumes more gas than the mapping design.