2

I want a function to accept, store and output 56 characters. My other question (How to return bytes array in Solidity Contract) shows that I tried to return bytes[], but it gives me an error:

Internal type is not allowed for public or external functions

I haven't been able to get past this error.

So now, I would like to see if I can split the 56 character input into two bytes32, so that I can return bytes32. How do I do this?

I modified the code from this question (How can I split a Bytes32 source into two halfs and store them in Bytes16?) and created this:

  event trace(bytes x, bytes32 a, bytes32 b);

    function foo(bytes source) {
        bytes32[2] memory y = [bytes32(0), 0];
        assembly {
            mstore(y, source)
            mstore(add(y, 32), source)
        }
        trace(source, y[0], y[1]);
    }

  function cut(bytes sha) constant returns (bytes32 half1, bytes32 half2) {
    assembly {
      let freemem_pointer := mload(0x40)
      mstore(add(freemem_pointer,0x00), sha)
      half1 := mload(add(freemem_pointer,0x00))
      half2 := mload(add(freemem_pointer,0x10))
    }
  }

But I wasn't able to get them to work.

EDIT on 2017-08-22 for benjaminion:

Ideally, I want to return bytes[]. See my code and the error with bytes[] at How to return bytes array in Solidity Contract . Benjaminion's first block of code worked with a little bit of modification. I changed my "iterator" function to the following:

  function iterator() constant returns (address[],uint256[],uint256[],bytes32[],bytes32[]){
      uint256 len = ledger.keys.length;
      address[] memory keys = new address[](len);
      uint256[] memory values = new uint256[](len);
      uint256[] memory values2 = new uint256[](len);
      bytes32[] memory newKeys1 = new bytes32[](len);
      bytes32[] memory newKeys2 = new bytes32[](len);
      for (uint256 i = 0 ; i <  len ; i++) {
         address key = ledger.keys[i];
         keys[i] = key;
         values[i] = ledger.maps[key];
         values2[i] = token.balanceOf(key);

         bytes memory sha = ledger.newKeys[i];
         bytes32 half1;
         bytes32 half2;

         assembly {
            half1 := mload(add(sha,0x20))
            half2 := mload(add(sha,0x40))
         }
         newKeys1[i] = half1;
         newKeys2[i] = half2;
      }
      return (keys,values,values2,newKeys1,newKeys2);
  }
1

This should achieve what your question asks about:

contract Foo {
  function cut(bytes sha) constant returns (bytes32 half1, bytes32 half2) {
    assembly {
      half1 := mload(add(sha,0x20))
      half2 := mload(add(sha,0x40))
    }
  }
}

The point is that the bytes quantity sha comprises a 32-byte length followed by the actual bytes. So we skip the first 32 (= 0x20) bytes to get half1, and then another 32 bytes to get half2.

Note that sha is a pointer to the start of the data it represents, which is why we can use it like this.


Having said this, it's not clear to me why you can't just do the following. bytes is a perfectly allowable return type and can have arbitrary length.

contract Foo {
  function foo(bytes sha) constant returns (bytes) {
    return sha;
  }
}

You probably really want something along these lines.

  • Ideally, I want to return bytes[]. See my code and the error with bytes[] at ethereum.stackexchange.com/questions/24511/… . Your first block of code worked with a little bit of modification. I added the following to my "iterator" function: bytes memory sha = ledger.newKeys[i]; bytes32 half1; bytes32 half2; assembly { half1 := mload(add(sha,0x20)) half2 := mload(add(sha,0x40)) } newKeys1[i] = half1; newKeys2[i] = half2; – Curt Aug 22 '17 at 13:51
  • Are you willing to review my crowdsale contract before I use it? – Curt Aug 22 '17 at 13:58

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.