0

I've written a sample contract below. My question is, do i really need so much mappings and arrays? It's very gas hungry by storing a couple of times basically the same data. Could the same result be achieved with fewer storage operations?

contract example { 

    struct StructPrimary {
        uint start;
        bool isActive;
        uint index;
        address owner;
        uint[] indexcounter;
    }

    uint globalCounter;
    uint[] public userArray;

    // Mapping
    mapping(uint => StructPrimary) public structByIndex;
    mapping(address => StructPrimary) public structByAddress;


    function addCandidate (address _candidate) public returns (uint) {
        // Data stored in the StructPrimary, needed to get global info on the candidate
        StructPrimary storage accounts = structByIndex[userArray.length];
        accounts.start = 0;
        accounts.owner = _candidate;
        accounts.isActive = true;
        accounts.index = userArray.length;
        accounts.indexcounter.push(userArray.length);

        // Index stored in a mapping. Needed for most contract functions (operates by ID, not by address)
        structByIndex[accounts.index].owner = _candidate;

        // Address stored in a mapping. This gives a quick overview of all registered indexes belonging to the same address
        structByAddress[_candidate].indexcounter.push(userArray.length);

        globalCounter++ ;

        // This array is used troughout the contract to loop trough the users
        return userArray.push(accounts.index);
    }
}
  • 1
    You can pack your struct variables better I.e. uints together – Samuel Dare Sep 11 '18 at 11:14
  • 1
    @Data_Kid uint is a 32 byte unit, they can't pack. It could be packed by switching isActive and index, since bool/owner can take up one slot. – flygoing Sep 11 '18 at 13:20
1

You need to use a combination of mapping and arrays to store data.

Refer the following example :

pragma solidity ^0.4.24;
contract example { 
    struct User {
      string name;
      uint level;
      uint[] indexcounter;
    }
    mapping (address => User) userStructs;
    address[] public userAddresses;

    function createUser(string name, uint level)public {

      // set User name using our userStructs mapping
      userStructs[msg.sender].name = name;
      // set User level using our userStructs mapping
      userStructs[msg.sender].level = level;
      // push user address into userAddresses array
      userStructs[msg.sender].indexcounter.push(userAddresses.push(msg.sender)-1);
    }

    function getUserByIndex(uint index)view public returns(string,uint,uint[]){
        return(userStructs[userAddresses[index]].name,userStructs[userAddresses[index]].level,userStructs[userAddresses[index]].indexcounter);        
    }

   function getUserByAddress(address userAddress)view public returns(string,uint,uint[]){
        return(userStructs[userAddress].name,userStructs[userAddress].level,userStructs[userAddress].indexcounter);        
    }
}

You can access mapping by address as you are able to do it now(without any code change). Instead of structByIndex you just need to store addresses in an array. You can access the address by index(ID) and by using the address you can access the data stored in mappings.

Refer this blog for more details. Let me know if you want any further clarification.

  • That's a great starting point, but when playing around with it, i noticed i'm unable to fetch all inputs by a single user. Your example lacks the array inside the struct, and it's a combination of inserting all these that make my example so expensive. Is their a way to return a one-to-many array with your code example, or am i missing something? – De ruige Sep 11 '18 at 11:10
  • I have modified the code in which there is an array in the struct. Let me know if it helps you. – Soham Lawar Sep 11 '18 at 11:39
  • Thank you. I've compiled and compared it, and the gas usage is almost as high as my original code. Does this mean that my code was basically 'as good' as the example you've written in terms of gas usage? – De ruige Sep 11 '18 at 14:22
  • Can you share values with a screenshot? I am very much sure that the example I share will use less gas. – Soham Lawar Sep 11 '18 at 14:31
  • @Deruige, I have modified the code. Previously array indices were not stored properly in an array indexcounter. Please check the code and let me know if any further clarification is required. – Soham Lawar Sep 12 '18 at 7:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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