[Ethereum] How to return a mapping type

mappingsolidity

I have a contract with a mapping inside a struct

contract Voting {
 struct voter {
   address voterAddress;
   uint256 tokensBought;
   mapping (bytes32 => uint256) tokensUsed;
 }
 mapping (address => voter) public voterInfo;
}

I want a function that returns voter information given an address. I found out I can not have a function return a Struct. So, I tried writing a function which returns tokensBought and tokensUsed like below:

function voterDetails(address user) returns (uint256, mapping (bytes32 => uint256)) {
  return (voterInfo[user].tokensBought, voterInfo[user].tokensUsed);
}

When I try to compile this code, I get the following errors:

Error: Type is required to live outside storage.

Error: Internal type is not allowed for public or external functions

Looks like I can't return mapping type in a function. How do I write a function that returns all the voter information?

Best Answer

You need to break the interface down into smaller chunks. In practice, you'll want to extend the internal storage pattern a little, I think.

Iterable mapping comes to mind. You keep lists of keys to mappings in arrays. Something like this:

  struct VoterStruct {
    address voterAddress;
    uint256 tokensBought;
    mapping (bytes32 => uint256) tokensUsed;
    bytes32[] tokenIndex; // a list of mapping keys that exist for the voter
  }

  mapping (address => VoterStruct) public voterStructs;

Then you can expose functions that allow iterating over lists while the contract returns one set of values at a time. Very sketchy to inspire some ideas:

// client can discover how may tokens are in the list for one voter
function getVoterTokenCount(address voter) returns(uint tokenCount) {
    return voterStructs[voter].tokenIndex.length;}

// client can discover the tokenId for a voter in a given row
function getVoterTokenAtIndex(address voter, uint index) returns(bytes32 tokenId) {
    return voterStructs[voter].tokenIndex[index];}

// client can discover token used by voter and tokenId
function getVoterTokenUsed(address voter, bytes32 tokenId) returns(uint tokensUsed) {
    return voterStructs[voter].tokensUsed[tokenId];}

// append keys to the list as you go
function insertVoterToken(address voter, bytes32 tokenId) returns(bool success) {
    voterStructs[voter].tokenIndex.push(tokenId);
    return true;}

Hope I didn't flub the syntax. It might be possible to sketch out the contract a little more. Would need a general description of what it's going to do. When I use this pattern, I always add some rules to ensure there are no duplicate keys, and so on.

Anyway, possibly the hints will inspire some ideas.

Hope it helps.