Smart Contract – Best Way to Store a String’s Compressed Version in a Smart Contract

contract-developmentstring

Storing string is expensive on smart-contracts and charge us expensive fees even if we want to store them in Events. Instead I want to store each string's decoded version in a smart-contract in order to save some memory and gas-fee charge. Overall, when I return string's decoded version, it also should be able to decoded into the original string.

As an example I want to pass my string as compressing base64 input format and its code. But when I stored compressed base64 string on a smart-contract, its returned version is not same as the one I passed.

Example example.js:

var Base64String = require('./base64-string');

var string = "QmWmyoMoctfbAaiEs2G46gpeUmhqFRDW6KWo64y5r581Vm";
console.log("Size of sample is: " + string.length);
var compressed = Base64String.compress(string);
console.log("compressed:" + compressed)
console.log("Size of compressed sample is: " + compressed.length);
string = Base64String.decompress(compressed);
console.log("Sample is: " + string);

Results node example.js: //as you can see 46 length string is compressed into 19 length.

Size of sample is: 46
compressed: ł斦쪃⡲ퟛƨ蒳憸幒桪ᔐ훨ꖨ릯鼵嗐
Size of compressed sample is: 19
Sample is: QmWmyoMoctfbAaiEs2G46gpeUmhqFRDW6KWo64y5r581VmAA

Passed base64 compressed string: //I want to store it on my smart-contract.

ł斦쪃⡲ퟛƨ蒳憸幒桪ᔐ훨ꖨ릯鼵嗐

Contract.set("ł斦쪃⡲ퟛƨ蒳憸幒桪ᔐ훨ꖨ릯鼵嗐");

From the smart-contract its returned version seems not same as the string I passed. // Contract.get()

ł斦쪃⡲<d7db>ƨ蒳憸幒桪ᔐ훨<a5a8>릯鼵嗐

Overall: "ł斦쪃⡲ퟛƨ蒳憸幒桪ᔐ훨ꖨ릯鼵嗐" != "ł斦쪃⡲<d7db>ƨ蒳憸幒桪ᔐ훨<a5a8>릯鼵嗐"

Please note that I have tried this on remix-solidity.

pragma solidity ^0.4.0;
contract Contract {
    string str;

    function set(string val) public {
        str = val;
    }

    function get() public constant returns (string) {
        return str;
    }
}

Please also not that we can provide string's IPFS-hash, but still I want to compress the IPFS-hash which will bring the string size from 46 to 19, this will save nearly around more than half memory.

So possible approach would be:

Large File → IPFS-hash (46 characters) → compress base64(IPFS-hash) (19 characters)

[Q] How should I pass compressed base64 string into a smart-contract? or basically what should I do to store my string compressed version on a smart-contract that when I returned it, it should match with the string I passed?

Thank you for your valuable time and help.

Best Answer

An IPFS address consists, in reverse order, of a hash of the data, the length of the said hash, and an identifier to tell you what algorithm is being used for the hashing. The algorithms in wide use produce hashes 32 bytes long. This is then encoded into a base58 string.

To store this efficiently you should undo the base58 encoding to get bytes. You shouldn't need to store the data length since it is implied by the version, so you need 32 bytes, plus a way to know the version. 32 bytes fits exactly into an EVM storage slot.

The 32 byte hash is effectively random, so you shouldn't expect to be able to compress it any smaller, and even if you could it may not help you because often you'd still end up using a 32-byte storage slot. If storage is very tight, you may choose to ignore the version identifier and just require that everybody use sha2-256, which is the current de-facto standard. If you need future-proofing, you may need an additional variable for this.

Related Topic