0

I have defined a contract which I would like to use for storing user details i.e a field for storing the hash of his document and a field for storing the address of a block which has some other information of user. I used the following structure for the same:

pragma solidity ^0.4.17;

contract UserDetails {
  struct User {
    string fileHash;
    address addr;
  }
  User[] userArr;

  function addUserDetail(string hash,address blockAddress) public returns (bool) {

    User memory usr;
    usr = User({fileHash:hash, addr:blockAddress});

    userArr.push(usr);

  }
}

1) Is this is the right data structure for this purpose?.

2) How to pass the arguments to the function addUserDetail while deploying the contract using web3?

1 Answer 1

1

I would tweak it a little bit.

The first thing that jumps out is you have the user address inside the struct. That will be redundant because you'll want to keep track of keys some other way. You'll want to look up by key, for example. In that, you'll already know the key you want to look up, right? No need to store it again inside each struct.

I noticed you are storing hashes, so I go forward on the assumption that there will be some offchain storage of meta data. Even so, you might (usually) have some additional on-chain fields. How to know the difference? If the contract needs access to a field in order to perform some in-contract logic, then the field belongs in the struct.

I made the key list public so a client can enumerate the keys and added a function to get a quick count, because raising an error is a nasty way to discover the list length, in my opinion.

pragma solidity ^0.4.17;

contract UserDetails {

  struct UserStruct {
    string fileHash;
    uint userListPointer;
    // you may continue with other non-key fields that are needed for contract logic
  }

  // unique identifiers
  address[] public userList;
  mapping(address=>UserStruct) public userStructs;

  function isUser(address userAddress) public view returns(bool isIndeed) {
      if(userList.length ==0) return false;
      return userList[userStructs[userAddress].userListPointer] == userAddress;
  }

  function addUserDetail(string hash,address userAddress) public returns (bool) {
    require(!isUser(userAddress));
    UserStruct memory usr;
    usr.fileHash = hash;
    usr.userListPointer = userList.push(userAddress) - 1;
    userStructs[userAddress] = usr;
  }

  function getUserCount() public view returns(uint count) {
      return userList.length;
  }
}

You can find some related patterns here: Are there well-solved and simple storage patterns for Solidity?

And a full explainer that coincidentally uses Users for the example over here: https://medium.com/@robhitchens/solidity-crud-part-1-824ffa69509a

Hope it helps.

7
  • Thank you for the detailed explanation. As I am new to blockchain and contracts, right now I am not able to decide what would be the best architecture for my project. Can you please share your email so that I can ask you for the project guidance? I'll share you the more detail. Apr 16, 2018 at 5:45
  • And should I have to deploy the contract only one and then call the addUserDetail function on next api call? If yes, how it would be done via web3.js? Apr 16, 2018 at 6:00
  • If I go with that architecture, if my user base grows very large then would it be still efficient or we should go for each block for each user? Apr 16, 2018 at 12:45
  • It can grow as fast as users or administrator can afford to send create transactions to the contract. There is no limit per block aside from Ethereum itself. Apr 16, 2018 at 12:50
  • Thanks for replying. Can you please tell me why I shouldn't go with one different block for each user architecture? Apr 16, 2018 at 13:22

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.