4

I've a simple but problematic problem. I read a value of a struct from a smart contract with a function like this:

  function getOwner(address _id) constant returns (bytes32) {
    uint pos = ownerID[_id];
    Owner memory foundOwner;
    foundOwner = owners[pos];

    return foundOwner.name;
  }

Essentially I pass a key (in this case _id) that is used to get an index base on this mapping:

mapping(address => uint) public ownerID;

After I have the right index (pos), I copy the struct into a memory variable called foundOwner. At the end, I return the name field of the struct.

The problem is: If I have 2 ID registered, say ID1 and ID2:

  • when I pass ID1 I get back ID1 name
  • when I pass ID2 I get back ID2 name
  • when I pass ID3 (with this sequence: ID1, ID2, ID3) I get back ID1 name, and this is a problem!

I know that with mapping, all the possible indexes are referenced so that the returned struct will have all fields set to 0x0.

I've also tried without the memory variable, returning directly owners[pos].name, but when I pass an unregistered ID, I always get back the element with the first index in the mapping.

How can I be sure that when passing an ID not registered, the function returns an empty struct?

Thanks in advice!

UPDATE: The Owner is set like this

  function registerOwner(bytes32 _name, bytes32 _surname) {
    owners.length++;
    uint pos = owners.length - 1;
    ownerID[msg.sender] = pos;
    owners[pos] = Owner(msg.sender, _name, _surname, true, block.number, block.timestamp);
  }

As I've said in the comments, my temporary solution is to create (within the constructor) a dummy variable with all 0x0 or false field. I think the problem is that when there is no match in the mapping, the pos variable will assume value 0, so returning the first entity I save. I think that maybe I can solve the problem simply starting from pos=1, so removing the -1 from line uint pos = owners.length - 1;

  • 1
    provide more information about the setter(setOwner) you use and the owners definition? you could provide the whole contract i could test it – Badr Bellaj Jan 11 '17 at 15:05
  • For the moment I've solved creating a dummy entity (all fields at 0x0 or false) at pos=0. I think the problem is that when there is no matching, pos assumes the value 0, so returning the data for the first entity registered if it's registered with index 0. So now I have a dummy entity at pos=0 and the first real entity from pos=1. I don't think it's an elegant solution, but it's working. – gatb27 Jan 11 '17 at 16:48
  • 1
    Your solution is the one I see most often in practice. One question: Why not just map directly from address => Owner? I don't really see the point of having the intermediate OwnerID step – Tjaden Hess Jan 11 '17 at 17:20
  • 1
    Yes, why would that be an issue? – Tjaden Hess Jan 11 '17 at 22:19
  • 2
    @TjadenHess I've removed the array and with the direct mapping address => Owner everything is working correctly! Less line of code, less variables inside the contract and no dummy variable needed. When I pass an unregistered ID, it returns my a struct with all empty fields :) – gatb27 Jan 12 '17 at 9:47

Your Answer

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

Browse other questions tagged or ask your own question.