Solidity Frustrations: References and Mapping

Warning, this is a technical post for Solidity developers, others can probably skip it.

Memory and Storage and ...

Here's a pop quiz I failed today: does this "singleton" construct work?

contract Sample {  
  mapping (uint => bool) doOnce;    
  uint _actionNumber;

  function() {  
     var a = doOnce[_actionNumber];
     if (a == true) { throw; }
     a = true;

     msg.sender.call();
     _actionNumber++;
 }
}

Actually, I got this part right. This does not work. a is a copy of the value in doOnce, and so we don't ever get true saved to the mapping.

Except, the contract I looked at was slightly different:

contract Sample {  
  struct info { bool doOnce; }
  mapping (uint => info) infoMap;    
  uint _actionNumber;

  function() {
     var a = infoMap[_actionNumber];
     if (a.doOnce == true) { throw; }
     a.doOnce = true;

     msg.sender.call();
     _actionNumber++;
 }
}

This does work(!) because a is a reference variable, essentially a pointer to the struct data.

So, the same construct for mutex or other recursive call protection can work or not work, depending on the mapping type.

This is Annoying

This sort of behavior is pretty common in many languages. Python or Go will both occasionally cause some cursing due to syntax sugar which automatically dereferences some sorts of pointers.

But.

We are not in such a world. We are in a world where a tiny code error may not be easily fixable.

In that world, this is a very annoying language feature, one that could cause real problems.

The code I was reviewing actually believed that all solidity mappings work like my first example -- they had a line like

infoMap[_actionNumber] = a;  

to re-save into the mapping. This sort of re-store is required in go; go by default does not treat map values as addressable. That's a sane decision, and one I think solidity should adopt.

Recommendations

This is tough. My gut is that you should train yourself to re-save the mapping item, regardless of type. But, this could lead to the mistaken belief that if you don't do this, you won't have mutated storage, a belief which is very false in the second case.

For now, it has to go on the list of things on your mental list of stuff to not forget.

My preferred languages keep that list short, so this is a bummer.

As always, my team is available for smart contract authoring and security reviews: [email protected].

Peter Vessenes

Read more posts by this author.

Subscribe to Peter Vessenes

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!