Assignment - Storage Design

For the storage assignment, my deployment and transaction costs were as follows:

ArrayStorage Deployment: 333,508 gas
MapStorage Deployment: 193,129 gas

Array addEntity: 88,312 gas
Map addEntity: 66,260 gas

Array updateEntity: 26,868 gas
Map updateEntity: 24,121 gas

For my implementation, map storage proved to be the most efficient type of storage to minimize gas costs.

pragma solidity 0.8.0;

contract MapStorage{

struct EntityStruct{
    uint data;
    address _address;
}

mapping (address => EntityStruct) entityMap;

function addEntity(uint data) public returns(bool success) {
    entityMap[msg.sender].data = data;
    entityMap[msg.sender]._address = msg.sender;
    return true;
}

function updateEntity(uint data) public returns(bool success) {
    entityMap[msg.sender].data = data;
    return true;
}

// Which design consumes the most gas? (Execution cost) Why?
}Preformatted text

pragma solidity 0.8.0;

contract ArrayStorage{ 

    struct Entity{
        uint data;
        address _address;
    }

    Entity[] public entityList;

    function addEntity(uint data) public {
        Entity memory newEntity;
        newEntity._address = msg.sender;
        newEntity.data = data;
        entityList.push(newEntity);
    }

    function updateEntity(uint rowNumber, uint data) public returns(bool success) {
        require(rowNumber <= entityList.length-1, "There is no entry in this row!");
        entityList[rowNumber].data = data;
        return true;
    }

    // Which design consumes the most gas?  (Execution cost) Why?
}

Hi Guys, see below my solution:

pragma solidity 0.7.5;

contract MappingStorage {

    struct Entity{

        uint data;

        address _address;

    }

    mapping(address => Entity) MStorage;

    function addEntity(uint _data) public returns(bool success){

        MStorage[msg.sender].data = _data;

        MStorage[msg.sender]._address = msg.sender;

        return true;

    }

    function updateEntity(uint _data) public returns (bool success){    

        MStorage[msg.sender].data = _data;

        return true;

    }

}

contract ArrayStorage {

   

    struct Entity{

        uint data;

        address _address;

    }

    Entity[] AStorage;

    function addEntity(uint _data) public returns(bool success){

        Entity memory newEntity;

        newEntity.data = _data;

        newEntity._address = msg.sender;

        AStorage.push(newEntity);

        return true;

    }

    function updateEntity(uint _data) public returns (bool success){

        for(uint i = 0; i < AStorage.length; i++){

            if(AStorage[i]._address != msg.sender) continue;//skip rest of the loop if addresses do not match

            AStorage[i].data = _data;

            return true;

        }

        return false; //false if msg.sender not in array

    }

}

Discussion:

1. When executing the addEntity function, which design consumes the most gas (execution cost)? Is it a significant difference? Why/why not?

MappingStorage used around 30% less in gas than Astorage which is a significant difference

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 and why?

AStorage consumes way more gas than MStorage to update entries. This is because in AStorage the function loops through the array until the msg.sender entry is found. MStorage is non-index and hence much more efficient in retrieving/updating stored data.

2 Likes

Here is my code for both contracts:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

contract StorageMapping {

    struct Entity{
        uint data;
        address _address;
    } 

    mapping (address => Entity) entityMapping;

    function addEntity(uint _data) public {
        entityMapping[msg.sender] = Entity(_data, msg.sender);
    }

    function updateEntity(uint _data) public {
        entityMapping[msg.sender].data = _data;
    }
}

contract StorageArray {

    struct Entity{
        uint data;
        address _address;
    }

    Entity[] public entityArray;

    function addEntity(uint _data) public {
        entityArray.push(Entity(_data, msg.sender));
    }

    function updateEntity(uint _data) public {
        for(uint i = 0; i <= entityArray.length - 1; i++) {
            if(entityArray[i]._address == msg.sender) {
                entityArray[i].data = _data;
            }
        }
    }
}

Not a question but I saw someone above add this and do think it is interesting:
Array storage deploy cost: 303135 gas
Mapping storage deploy cost: 239450 gas

Array storage contract: 88190 gas
This is for the first addEntity transaction. I expect this is because it sets up the initial array where it was not before?
Second + addEntity: 71090 gas
Cost difference between first and all other times: ~21.47%
Total Cost: 372550 gas
Interestingly not that much more for the 5 addEntity calls than initial deploy.

Mapping storage contract: 66054 gas
Total cost for 5 entities: 330270 gas
No difference in first or any subsequent addEntity requests for the mapping.

The difference between the first addEntity on array and mapping:
~28.70%
The difference between the second or later calls to addEntity on array and mapping:
~7.34%
Total difference between total addEntity of both contracts:
~12.03%

When executing the addEntity function, which design consumes the most gas (execution cost)? Is it a significant difference? Why/why not?

The shocking result that is while if you only add 1 entity the difference is quite large (~30%), as more entries are added the less pronounced the difference between arrays and mappings become (~7%).

I would say that the difference is still significant even if you do more than the first call to addEntity. No where near as absurd as it may first appear. With a reduction beyond the first call of a little less than 4x the difference while noticeable is not as bad as the gas prices in California right now.

> 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 and why?

For the array contract updating the 5th entry costs:
43356 gas
For the mapping contract updating the 5th entry costs:
26741 gas
Total difference:
~47.40%
The array contract costs significantly more than the mapping contract. This is because of having to loop through each entry until it finds the correct one to update.

I thought that perhaps if you picked the first entry the array would be at least cheaper than updating the last entry. From my testing it is the exact same cost.

This actually makes me question if the looping is the added cost. Perhaps the array still loops through all no matter when it finds the correct one to update. Just came to me what about a break? Going to test.

So I simply added a break; after the update in the for loop in the array contract. Strangely even updating the 5th entry got cheaper with the break added:
42894 gas vs 43356 gas

However as expected the 1st entry was much cheaper after adding the break;. No longer having to complete the loop through the whole array which is to be expected.

1st entry update after adding the break compared to no break:
31526 gas vs 43356 gas

1 Like
contract StorageDesignMapping {
    mapping(address => Entity) public entities;

    function addEntity(uint data) public returns (Entity memory) {
        Entity memory newEntity;
        newEntity._address = msg.sender;
        newEntity.data = data;
        entities[msg.sender] = newEntity;
        return entities[msg.sender];
    }

    function updateEntity(uint data) public returns (Entity memory) {
        entities[msg.sender].data = data;
        return entities[msg.sender];
    }
}

contract StorageDesignArray {
    Entity[] public entities;

    function addEntity(uint data) public returns (Entity memory) {
        Entity memory newEntity;
        newEntity._address = msg.sender;
        newEntity.data = data;
        entities.push(newEntity);
        return entities[entities.length - 1];
    }

    function updateEntity(uint data) public returns (Entity memory) {
        for (uint i; i < entities.length; i++) {
            if (entities[i]._address == msg.sender) {
                entities[i].data = data;
                return entities[i];
            }
        }
        revert();
    }
}

In adding an entity, Array consumes slightly more as array always needs more gas. It’s not a significant difference because the operation is similar, create the object and it to the array / mapping.

In updating an entity, Array consumes more gas as there’s a looping operation to it.

1 Like

Hey folks,
Right after finishing contracts and after tests my assumptions was that array variant will consume more gas because of loop on board. And a tests after contract deployment approves my assumptions.

MappingDb.sol

pragma solidity 0.8.13;

contract MappingDb {
    struct Entity{
        uint data;
        address _address;
    }
    mapping(address => Entity) entities;

    function addEntity(uint _data) public {
        Entity storage selectedEntity = entities[msg.sender];
        require(selectedEntity._address != msg.sender);
        selectedEntity.data = _data;
        selectedEntity._address = msg.sender;
    }

    function updateEntity(uint _data) public {
        Entity storage selectedEntity = entities[msg.sender];
        require(selectedEntity._address == msg.sender);
        selectedEntity.data = _data; 
    }
}

ArrayDb.sol

pragma solidity 0.8.13;

contract ArrayDb {
    struct Entity{
        uint data;
        address _address;
    }
    Entity[] entities;

    function addEntity(uint _data) public {
        (bool isNew, Entity storage selectedEntity) = _getSelectedEntity();
        require(isNew);
        selectedEntity.data = _data;
        selectedEntity._address = msg.sender;
    }

    function updateEntity(uint _data) public {
        (bool isNew, Entity storage selectedEntity) = _getSelectedEntity();
        require(!isNew);
        selectedEntity.data = _data;
    }

    function _getSelectedEntity() private returns (bool isNew, Entity storage entity) {
        for(uint i = 0; i < entities.length; i++) {
            if (entities[i]._address == msg.sender) return (false, entities[i]);
        }
        return (true, entities.push());
    }
}

“addEntity” cost using Array format: 90237
“addEntity” cost using Mapping format: 27165

As mentioned in the previous lesson, Mapping uses a key value pairing feature that instantly assigns the address to a value. Its order is not stored, it is simply assigned to one value. The array style of storage has to remember the order in which the key value pair was created. This requires more gas as more has to be done in order to execute the function completely.

“updateEntity” cost for the Array format: 73159
“updateEntity” cost for the Mapping format: 27514

With the Array format more gas is consumed because more actions have to be achieved to successfully complete the function call. My mapping does not write any extra data then what needs to be assigned, whereas my Array version has to set a temporary variable (using the struct format) so that i may update the entity. This temporary variable was also used in the addEntity function resulting in even further gas consumption.

1 Like
Mapping
pragma solidity 0.7.5;
pragma abicoder v2;


contract Assign01Mapping{
    struct Entity{
        uint data;
        address _address;
    }

    mapping(address => Entity) public entities;

    function addEntity(uint _newData) external {
        entities[msg.sender].data = _newData;
        entities[msg.sender]._address = msg.sender;
    }

    function updateEntity(uint _updateData) external {
        require(entities[msg.sender]._address == msg.sender);
        entities[msg.sender].data = _updateData;
    }
}
Array
pragma solidity 0.7.5;
pragma abicoder v2;

contract Assign01Array{
    
    struct Entity{
        uint data;
        address _address;
    }

    Entity[] entities;

    function addEntity(uint _newData) external {
        Entity memory newEntity;
        newEntity._address = msg.sender;
        newEntity.data     = _newData;
        entities.push(newEntity);
    }

    function updateEntity(uint _updateData) external {
        if(entities.length > 0) {
            for (uint i = 0; i <= entities.length-1; i++) {
                if(entities[i]._address == msg.sender) {
                    entities[i].data = _updateData;
                }
            }
        }
    }
}```

The Array contract consumed the most gas when running the addEntity function.
There was about a 12% increase in cost within the Array contract, however the initial run of the function was much more expensive; maintaining an array requires more memory.

The Array contract consumed more gas when running the updateEntity function. Even though the assignment called for 5 addresses committing a single addEntity, and one of those addresses making an updateEntity call, I configured the logic to assume that a single address could make multiple entries. The logic required looping through the array, therefore requiring more processing on top of the additional memory for storing the array.

1 Like

wow @ekr990011 really thorough solution man this is great testimg and research. please keep this work up amazing to see. if your intrested in gas optimization there is so much more ways you can save on gas from copying global variables to memory in functions to, if statement optimization, where you always short circuit your if statemtns, caching array lengths, using calldata instead of memory and for loop stuff too where u alwys load for loop elements to memory. i would highly recomment u watch this video its very infomative
https://www.youtube.com/watch?v=4r20M9Fr8lY

1 Like

nice observation. one thing tho is even if one operation only saves slightly more gas than another dont write off the savings as “barely and better” because any gas saved in soldity is really important. if you consider the fact that if you find 10 operations in a contract that can save 500 gas (which you would think is really insignificat) then add then all up and youve saved 5000 gas. so always always try to optimize and save where u can

status true Transaction mined and execution succeed
transaction hash 0xac53576af2eeafa2d252019abe39c70b020c315880f596f93ab43ebbc467c628
from 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
to MappingStorageAssigment.addEntity(uint256) 0xd9145CCE52D386f254917e481eB44e9943F39138
gas 53326 gas
transaction cost 46370 gas
execution cost 46370 gas
input 0x472…00000
decoded input { “uint256 data”: “0” }
decoded output { “0”: “bool: success true” }
logs []
val 0 wei
1 Like
  1. When executing the addEntity function, which design consumes the most gas (execution cost)? Is it a significant difference? Why/why not?

Array option : 88489 gas
Mapping option : 66260 gas

  1. 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 and why?

Array option : 29358 gas
Mapping option : 26921 gas

Overall the array solution costs the most gas because their are more actions to fulfill.

Array:

pragma solidity 0.8.0;

contract store_array{

    struct Entity {
        uint data;
        address _address;
    }

    Entity[] public entityArray;

    function addEntity(uint data) public returns (bool success){
        Entity memory newEntity;
        newEntity.data = data;
        newEntity._address = msg.sender;
        entityArray.push(newEntity);
        return true;
    }

    function updateEntity(uint index, uint newData) public returns (bool success){
        entityArray[index].data = newData;
        return true;
    }
}

Mapping:

pragma solidity 0.8.0;

contract store_mapping{

    struct Entity {
        uint data;
        address _address;
    }

    mapping (address => Entity) entityMapping;

    function addEntity(uint entityData) public returns (bool success){
        entityMapping[msg.sender].data = entityData;
        entityMapping[msg.sender]._address = msg.sender;
        return true;
    }

    function updateEntity(uint newData) public returns (bool success){
        entityMapping[msg.sender].data = newData;
        return true; 
    }
}
3 Likes

When executing the addEntity function, which design consumes the most gas (execution cost)? Is it a significant difference? Why/why not?

Array design consumes the most gas. I think it is because looping array needs more computational power than mapping. It is a significant difference because the mapping design needs only 70% gas of the array design.

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 and why?

Array design consumes more gas! This is because the loop needs more computational power than mapping. The large length of array needs more computational power to loop the array. Mapping design does not change the amount of gas no matter how many keys store in the dictionary.

  • Mapping method consumed 30960 wei of gas for updating the data of the fifth address

  • Array method consumed 48118 wei of gas for updating the data of the fifth address

My mapping design code

pragma solidity 0.7.5;
pragma abicoder v2;


contract OnlyMapping {
    struct Entity {
        uint data;
        address _address;
    }

    mapping (address => Entity) entityDict;

    function addEntity(uint _data) public returns (bool isAdded) {
        entityDict[msg.sender] = Entity(_data, msg.sender);
        return true;
    }

    function updateEntity(uint _data) public returns (bool isUpdated) {
        entityDict[msg.sender].data = _data;
        return true;
    }
}

My array design code

contract OnlyArray {
    struct Entity {
        uint data;
        address _address;
    }

    Entity[] entityArray;

    modifier stopSecondEntity {
        bool isSecondEntity = false;
        for (uint i=0; i<entityArray.length; i++) {
            if (entityArray[i]._address == msg.sender) {
                isSecondEntity = true;
            }
        }
        require(isSecondEntity==false);
        _;
    }

    function addEntity(uint _data) public stopSecondEntity returns (bool isAdded) {
        entityArray.push( Entity(_data, msg.sender) );
        return true;
    }

    function updateEntity(uint _data) public returns (bool isUpdated) {
        for (uint i=0; i<entityArray.length; i++) {
            if (entityArray[i]._address == msg.sender) {
                entityArray[i].data = _data;
            }
        }
        return true;
    }
}
1 Like

Hey guys! Here’s my solution to the assignment:

Mapping Storage

pragma solidity ^0.8.0;

contract MappingStorage {

    mapping(address => Entity) entitiesMapping;

    struct Entity{
        uint data;
        address _address;
    } 

  function addEntity(uint data) public returns(bool) {
      entitiesMapping[msg.sender] = Entity(data, msg.sender);
        return true;
  }

  function updateEntity(uint data) public returns(bool) {
      entitiesMapping[msg.sender].data = data;
      return true;
  }
} 

Array Storage

pragma solidity ^0.8.0;

contract ArrayStorage {

    Entity[] public entitiesArray;

    struct Entity{
        uint data;
        address _address;
    } 

  function addEntity(uint data) public returns(bool) {
        entitiesArray.push(Entity(data, msg.sender));
        return true;
  }

  function updateEntity( uint data) public returns(bool) {      
      for (uint i=0; i< entitiesArray.length; i++) {
          if(entitiesArray[i]._address == msg.sender) {
            entitiesArray[i].data = data;
            break;
          }
      }
      return true;
  }
} 

(Note: I considered the most simplistic implementation to isolate gas costs from the most relevant operations)

Results:

Execution cost for ArrayStorage:

  • Add item: 88389
  • Add a second item: 71289
  • Update 5th item: 42036

Execution cost for MappingStorage:

  • Add item: 66253
  • Add a second item: 66253
  • Update 5th item: 24121

Final considerations
Gas consumption for array structure is clearly higher than for the mapping storage strategy. Regarding element creation, for Arrays it is approx. 30% more expensive to create the first element, however, for subsequent elements, the gas cost reduces slightly for arrays, while for mapping it’s constant (still lower).
It is in the updating function that the differences are more relevant. Here Array updates take up to 70% more gas even for an array as small as 5 elements, and the tendency is for the execution cost to increase for arrays as the array itself grows in size (given the provided implementation which did not accept an index as a function argument)
The explanation here should be the fact that not only it is more expensive to store structs in an array, but also the cost of iterating through an array to find the correct address match clearly makes the computation much heavier when compared to the instantaneous key->value fetch provided by the mapping structure.

2 Likes
Answer

When adding it is not big difference but when updating array is more expensive because it takes more space in the storage so it costs more.

1 Like

nicework guys. this may seem like a tideous excercise now. but this know;edge is very valuable going forward. it can be difficult sometimes whther to pick between a mapping or a storage array of structs etc and you will always find that oncce youve written a contract you could completely re-write it using different stoarage principles. sometimes its fun to play around with gas optimisation although it can be a chore at times too LOL

  1. Array Struct consumes the most gas. The mapping saves the data directly.
  2. Still Array Struct which consumes the most gas. Because Array Struct need a loop the get the key of msg.sender struct.
2 Likes

One thing I noticed is that for the map, if you are not including checks for if the element exists, the same method could be used for both update and add. Maybe the checks would cost a bit more gas.

However here are my answers and code below:

When executing the addEntity function, which design consumes the most gas (execution cost)?

Using the array uses more gas, I think it’s because arrays are less efficient when compiled. And use more resources to interact with.

Map cost = 66377
Array cost = 88513

Is it a significant difference? Why/why not?
I would consider it to be a significant amount more. Just seeing as they have the exact same functionality, a 30% higher cost is a lot.

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 and why?

Map cost = 29343
Array cost = 31638

Modifying the array costs more in gas than the map. Similar to above, I think arrays are less efficient than maps once compiled.

ArrayStorage.sol

pragma solidity 0.7.5;

contract ArrayStorage {

    struct Entity{
        uint data;
        address _address;
    }

    Entity[] entities;

    function addEntity(uint dataToAdd, address adr) public returns (bool) {
        entities.push(Entity(dataToAdd, adr));
        return true;
    }

    function updateEntity(uint newData, address newAdr, uint index) public returns (bool) {
        entities[index] = Entity(newData, newAdr);        
        return true;
    }

}

MapStorage.sol

pragma solidity 0.7.5;

contract MapStorage {

    struct Entity{
        uint data;
        address _address;
    }

    mapping( address => Entity ) data;

    function addEntity(uint dataToAdd, address adr) public returns (bool) {
        data[msg.sender] = Entity(dataToAdd, adr);
        return true;
    }

    function updateEntity(uint newData, address newAdr) public returns (bool) {
        data[msg.sender] = Entity(newData, newAdr);
        return true;
    }

}

Thanks,
Luke

1 Like

Here’s my solution:

Storage Design with MAPPING

pragma solidity 0.8.0;

contract mappingWithStruct {

    struct entityStruct {

        uint data;

        address _address;

    }

    mapping (address => entityStruct) public entityStructs;

    function updateEntity(uint data) public returns(bool success) {

    entityStructs[msg.sender].data = data;

    return true;

    }

    function addEntity(uint data) public returns(bool success) {

    entityStructs[msg.sender] = entityStruct(data,msg.sender);

    return true;

    }

}

Storage Design with ARRAY:

pragma solidity 0.8.0;

contract arrayWithStruct {

    struct entityArray {

        uint data;

        address _address;

    }

 entityArray[] public entityArrays;

 

    function addEntity(uint data) public returns (bool success){

        entityArray memory newEntity;

        newEntity.data = data;

        newEntity._address = msg.sender;

        entityArrays.push(newEntity);

        return true;

  }

  function updateEntity(uint index, uint newData) public returns (bool success){

        entityArrays[index].data = newData;

        return true;

    }
  1. When executing the addEntity function, which design consumes the most gas (execution cost)? Is it a significant difference? Why/why not?
    gas for mapping: 76191
    gas for array: 101788

Gas in case of mapping is less, I think because of simpler operations in the contract.

  1. 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 and why?

After adding 5 entities:
gas for mapping: 33641
gas for array: 82123

Basically storage design with mapping cost less gas in both cases.

1 Like

My code:
ArrayStorage and MappingStorage

When executing the addEntity function, which design consumes the most gas (execution cost)? Is it a significant difference? Why/why not?
=> It is a small difference (10%). I suppose the difference can be explained by the array structure being more expensive to allocate memory and growing. In other words, a “push” is more expensive than adding a new mapping entry.

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 and why?
=>357,001 gas for Mapping. 401,718 gas for Array. I.e. Array consumes more gas. Same reasons pointed above: Push is more expensive than adding to the mapping. Updating the mapping is also slightly cheaper than updating the array.

1 Like

Assignment Storage Pattern

1.When executing the addEntity function, which design consumes the most gas (execution cost)?

Mapping :
Deployment cost - 302679
Add entity - 67205 (and had a constant value for all entries added)

Array
Deployment cost - 338035
Add entity - 89037, second entry was 71937

The array consumes around 20% more gas than the mapping. The array occupies more storage as you can perform more operations to it which makes it computationally more challenging than the mapping where you can access the record by having a key reference to it. Also for the mapping the values are stored in memory unlike the array where it is stored in a storage slot, making the addEntity call cheaper to use since the values stored are temporary.

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 and why?

Mapping:

updateEntry - 27478

Array: - the gas cost decreases after the second addEntry?
updateEntry - 42449
updateEntry after the updated code - 34606

Again the mapping wins as we only use a pointer to update the data into it, accessing the value directly whereas for the array we need to iterate through it in order to find the index of the position we want to update. Weirdly, after the second addEntry operation, the value of the gas decreased and I am not sure why since I would have expected the gas cost to be actually higher than the first one, it would have made more sense. I’ve tried to find an answer for this but without any luck.

I found a nice solution to decrease the gas cost for the array once you update the entry. Instead of using the array.length inside the for loop, you pass it locally to a variable. For me it reduced the gas cost from 42449 to 34606.

Mapping:

contract MappingTest {
    struct Entity{
        uint data;
        address _address;
    }

    mapping(address=> Entity) public entities;

    function addEntity(uint data, address entityAddress) public returns (Entity memory entityMem){
        Entity memory entity = Entity(data, entityAddress);
        entities[entityAddress] = entity;
        return entity;
    }

    function updateEntity(uint data, address entityAddress) public returns(bool){
        entities[entityAddress].data = data;
        return true;
    }
}

Array:

contract ArrayText {
    struct Entity {
        uint data;
        address _address;
    }

    Entity [] public entities;

    function addEntity(uint data, address entityAddress) public returns(bool) {
        Entity memory entity = Entity(data, entityAddress);
        entities.push(entity);
        return true;
    }

    function updateEntity(uint data, address entityAddress) public returns(bool success){
		// for the updated code we declare the length variable locally to save gas and use it in the for loop
    // uint arrayLength = entities.length;

        for(uint i = 0; i < entities.length ;i++){
//for(uint i = 0; i < arrayLength ;i++){
            if(entities[i]._address == entityAddress){
                entities[i].data = data;
                success = true;
            }else{
                success = false;
            }
            
        }
         return success;
    }
}
1 Like