Solidity Storage – Working with Nested Structs in Contract Design

contract-designipfssoliditystoragestruct

Is it possible to have a struct inside a struct?
I am not sure about the data type internals, but I was basically trying to do something like (pseudo-code):

library IpfsUtils {

  struct IpfsHash {
    bytes32 hash;
    uint8 hashFunction;
    uint8 hashSize;
  }

  function insert(bytes _hash) {}
  function combine() {}
}

contract Members {

  struct Member {
     IpfsUtils.IpfsHash profile;
     uint id;
  }
  mapping (address => Member) public members;

  function addMember(uint id, bytes profileHash) {
    Member m = members[msg.sender];
    m.id = id;
    m.profile.insert(profileHash);
  } 
}

I'm trying to store an IPFS hash with fixed length data types and I thought about extracting the storage of the ipfs hash function, size and the actual bytes32 hash into its own struct.

Can someone point me somewhere to learn more about the internals?

EDIT:
nested structs are possible. BUT the the mapping (here members) can not be public causing the following error: TypeError: Internal type is not allowed for public state variable

Best Answer

You can store a struct in a struct.

pragma solidity ^0.4.11;

contract Nest {

  struct IpfsHash {
    bytes32 hash;
    uint hashSize;
  }

  struct Member {
    IpfsHash ipfsHash;
  }

  mapping(uint => Member) members;

  function addMember(uint id, bytes32 hash, uint size) public returns(bool success) {
    members[id].ipfsHash.hash = hash;
    members[id].ipfsHash.hashSize = size;
    return true;
  }

  function getMember(uint id) public constant returns(bytes32 hash, uint hashSize) {
    return(members[id].ipfsHash.hash, members[id].ipfsHash.hashSize);
  }
}

This nesting is a little on the pointless side if there is only one IPFS per Member as I assume is the case. I didn't want to fix too much and drift away from the original question.

Yes, you can nest structs inside structs. Mappings and arrays, too, or even mappings of structs or arrays of structs.

Possibly helpful: struct declarations are only declaring a type not instances of the type.

In terms of coordinating all this to make something useful, have a look at the patterns over here: Are there well-solved and simple storage patterns for Solidity?

If you are looking for a one-to-many (many IPFS per Member), this pattern might be helpful: https://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart-contracts-a9ab1427ff42

Hope it helps.