Solidity Encoding – How to Parse a bytes32 in Solidity for Storage and Memory

decodingencodingmemorysoliditystorage

I have a bytes32 object in memory or storage and I want to parse it into little chunks, for example into one uint8, followed by a bool, followed by uint10, followed by address. How can one do that? I have tried two options:

// option 1
function parseBytes32_op1(bytes32 _data) pure public returns (byte fist, byte second, bytes10 third, bytes20 fourth) {
    assembly {
        let freemem_pointer := mload(0x40)
        mstore(add(freemem_pointer,0x00), _data)
        _first := mload(add(freemem_pointer,0x00))
        _second := mload(add(freemem_pointer,0x01))
        _third := mload(add(freemem_pointer,0x02))
        _fourth := mload(add(freemem_pointer,0x0b))
      }
   // and then convert somehow into the respective types

  }

// option2
function parseBytes32_op2(bytes32 _data) pure public returns (byte fist, byte second, bytes10 third, bytes20 fourth) {
    
        first = uint8(bytes1(_data));
        second = bool(uint8(bytes1(_data << 8)));
        third = uint10(bytes9(_data << 8 * 2));
        fourth = address(bytes9(_data << 8 * 12));
}

However, in the first option I am feeling uncomfortable about the memory stack. I fear that I might use the wrong pointer if there is something atop the stack that is not the data.

In the second option I am feeling uncomfortable with the shift operation. Where do those bytes shift? In fact when I ran some similar code on remix I got a compiler error saying:

CompilerError: Stack too deep, try removing local variables.

What is the best option?

Best Answer

It could be implemented without memory access, just with shifts

function parseBytes32_op1(bytes32 _data) pure public returns (bytes1 first, bytes1 second, bytes10 third, bytes20 fourth) {
    assembly {
        first := _data
        second := shl(8, _data)
        third := shl(add(8, 8), _data)
        fourth := shl(add(16, 80), _data)
    }
}

It could be implemented in solidity and it will be almost identical to your solution

function parseBytes32_op2(bytes32 _data) pure public returns (bytes1 fist, bytes2 second, bytes10 third, bytes20 fourth) {

    first = bytes1(_data);
    second = bytes1(_data << 8);
    third = bytes10(_data << 8 * 2);
    fourth = bytes20(_data << 8 * 12);
}

The EVM is stack based so simple operations like shift are implemented using the machine stack.


The error message

CompilerError: Stack too deep, try removing local variables.

means you are using too many local variables + return values + input parameters + temporary operations.

Try simplifying the function, dividing in two parts, use {} to limit variables scope. For other recommendations see this Error while compiling: Stack too deep.