6

This question already has an answer here:

An IPFS hash can be expressed in hexadecimal which is 34 bytes long. Afaik it is most efficient to store fixed length values in a Ethereum contract, thus a maximum of 32 bytes (bytes32). Because the first two bytes of the IPFS hex hash describe the hash function and the hash size it could be split and stored with something like this:

  bytes32 hash
  uint8 hash_function
  uint8 size

I tried to do the splitting of the hash in solidity:

function splitHash(bytes source) internal returns(uint8, uint8, bytes32 hash) {
  uint8 tag = uint8(source[0]);
  uint8 len = uint8(source[1]);

  assembly {
    hash := mload(add(source,34))
  }

  return (tag, len, hash);
}

and combining it again using:

function combineHash(uint8 _tag, uint8 _len, bytes32 _hash) internal returns(bytes) {
  bytes memory out = new bytes(34);

  out[0] = byte(_tag);
  out[1] = byte(_len);

  uint8 i;
  for (i = 0; i < 32; i++) {
    out[i+2] = _hash[i];
  }

  return out;
}

This seems to work well but I fail to use it from web3.js and I fail to retrieve the hashes.

Is this approach useful? Does anybody has an example or some best practices on how to store and load IPFS hashes?

marked as duplicate by alper, Achala Dissanayake, Richard Horrocks, eth Aug 31 '18 at 6:44

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

9

Whilst I have not worked with IPFS hashes, the solidity types documentation states that you can store fixed size byte arrays up to 32 bytes.

As such if you want to store the whole hash in one data property you have to use the dynamic array type bytes. This is outlined here.

If you want to store them separately, it seems perverse to me to implement the splitting and concatenation on chain, as this will simply utilise gas for processing that is not necessary for trustless consensus.

The docs do note that bytes is more expensive that a fixed size array, so it may well be worth splitting. As alluded to above, I would do this in your client before storing the data on the chain.. I.E. Do the splitting in Javascript. str.split() is your friend.

That said it is not necessarily the case that the hashes will always be 32 bytes so for future proofing you will need a well defined upgrade path for your contract.

I personally would also convert from base58 to hex (in the client) because most things Ethereum work in hex, and I am a stickler for consistency.

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