Compress Size of Mapping in Solidity with Keccak256

Jonas Sunandar
HARA Engineering
Published in
3 min readSep 6, 2019

Ethereum is the most well-known smart contract platform, with one of the largest communities around the world. Tons of smart contracts are built on top of Ethereum Network. In recent years, many Decentralized Apps have launched in various industries, such as social media, games, exchange, health, and insurance, to name a few.

There’s one big difference when programming on Ethereum, compared to programming on other platforms: each operation has a cost. The more complicated the code, the bigger the cost. That’s why it’s important for us Ethereum developers to do our “magic” to optimize our Solidity code as much as possible.

One of the best “magic” that we can do is compressing the size of mapping in a smart contract - let’s see how we can do that!

Let the magic begin!

Let’s see the real example from EIP-780.

EIP-780 is a smart contract interface that allows everyone to attest any subject. In other words, it allows you to submit a review on a certain subject in the blockchain ecosystem. Also, you can claim or verify your own address.

Here is the code in Solidity:

contract EthereumClaimsRegistry {

mapping(address => mapping(address => mapping(bytes32 => bytes32))) public registry;

event ClaimSet(
address indexed issuer,
address indexed subject,
bytes32 indexed key,
bytes32 value,
uint updatedAt);

event ClaimRemoved(
address indexed issuer,
address indexed subject,
bytes32 indexed key,
uint removedAt);

// create or update claims
function setClaim(address subject, bytes32 key, bytes32 value) public {
registry[msg.sender][subject][key] = value;
emit ClaimSet(msg.sender, subject, key, value, now);
}

function setSelfClaim(bytes32 key, bytes32 value) public {
setClaim(msg.sender, key, value);
}

function getClaim(address issuer, address subject, bytes32 key) public view returns(bytes32) {
return registry[issuer][subject][key];
}

function removeClaim(address issuer, address subject, bytes32 key) public {
require(msg.sender == issuer);
delete registry[issuer][subject][key];
emit ClaimRemoved(msg.sender, subject, key, now);
}
}
function setClaim(address subject, bytes32 key, bytes32 value) public {
registry[msg.sender][subject][key] = value;
emit ClaimSet(msg.sender, subject, key, value, now);
}

This function makes the issuer to set the claim value with the key about thesubject. To store the claim we need to access 3-dimensional mapping. It costs a lot of memory. When a memory size increases, the price that you pay to run the code escalates as well. So how do developers create the “magic” that I mentioned before? Can we reduce the mapping size from 3-dimensional to 1-dimensional?

Keccak256 comes to save the world!!!

The idea is simple. Because of Avalanche Effect, we can create a signature from the parameters like the subject, key, and the issuer address. More importantly, the signature will be in the form of bytes32. Therefore we can set the variable registry to 1-D instead of 3-D mapping.

mapping(bytes32 => bytes32) public registry;

So our new smart contract will only store one bytes32 mapping. Here is the implementation of setClaim using keccak256.

function setClaim(address subject, bytes32 key, bytes32 value) public {
bytes32 encryptedBytes = keccak256(abi.encodePacked(subject, key, msg.sender));
registry[encryptedBytes] = value;
emit ClaimSet(msg.sender, subject, key, value, now);
}

To conclude, by encrypting all parameters of the mapping, developers can reduce the cost and size of the smart contract.

If you are interested in the full implementation of the smart contract, visit my Github here. Please stay tuned to what the HARA team is up to.

References:

  1. https://en.wikipedia.org/wiki/SHA-3
  2. https://www.ethereum.org/
  3. https://web3js.readthedocs.io/
  4. https://en.wikipedia.org/wiki/Avalanche_effect

Join our community on Twitter!

--

--