Skip to content

Instantly share code, notes, and snippets.

@lucasvo
Last active January 10, 2020 17:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lucasvo/5cf682c29325e450b12b4f963c856cf1 to your computer and use it in GitHub Desktop.
Save lucasvo/5cf682c29325e450b12b4f963c856cf1 to your computer and use it in GitHub Desktop.
Gas usage when returning Structs

Mapping of Structs in Solidity

Structs in solidity are implemented as a hash map. They key of a map is hashed with keccak and the storage slot. A costly part of accessing a map is hashing the key to find the slot. When storing a struct in a mapping as opposed to multiple mappings of primitive types you can save the cost of multiple hashes. However when frequently only reading part of the struct, returning an entire struct to a call leads to overhad in memory usage. Below are a few test cases illustrating the different options and their gas usage.

Result

As expected, the most simple, test_map() uses the least amount of gas. The worst option is if you have an external call that returns the entire struct even though only one element is needed (test_structmap_no_getter). Therefore if you have external methods access only partial data from a struct always create a getter for it.

[PASS] test_map() (gas: 4948)
[PASS] test_structmap() (gas: 5137)
[PASS] test_structmap_no_getter() (gas: 7193)

However when you get 5 elements from a map with struct or 5 elements from 5 maps, the struct is more efficient

[PASS] test_multiple() (gas: 16627)
[PASS] test_multiple_struct() (gas: 7474)
pragma solidity ^0.5.12;
import "ds-test/test.sol";
contract Maptest {
struct Map {
bytes32 a;
bytes32 b;
bytes32 c;
bytes32 d;
bytes32 e;
}
mapping (uint => Map) public structmap;
mapping (uint => bytes32) public map;
function getStructMapItem() public returns (bytes32) {
return structmap[0].e;
}
function getMapItem() public returns (bytes32) {
return map[0];
}
constructor () public {
structmap[0] = Map("a", "b", "c", "d", "e");
map[0] = "e";
}
}
contract MaptestTest is DSTest {
Maptest maptest;
function setUp() public {
maptest = new Maptest();
}
function test_map() public logs_gas {
bytes32 result = maptest.getMapItem();
assertEq("e", result);
}
function test_structmap() public logs_gas {
bytes32 result = maptest.getStructMapItem();
assertEq("e", result);
}
function test_structmap_no_getter() public logs_gas {
(,,,, bytes32 e) = maptest.structmap(0);
assertEq("e", e);
}
function test_multiple_struct() public logs_gas {
(bytes32 a, bytes32 b, bytes32 c, bytes32 d, bytes32 e) = maptest.structmap(0);
assertEq("a", a);
assertEq("b", b);
assertEq("c", c);
assertEq("d", d);
assertEq("e", e);
}
function test_multiple() public logs_gas {
bytes32 a = maptest.getMapItem();
bytes32 b = maptest.getMapItem();
bytes32 c = maptest.getMapItem();
bytes32 d = maptest.getMapItem();
bytes32 e = maptest.getMapItem();
assertEq("e", a);
assertEq("e", b);
assertEq("e", c);
assertEq("e", d);
assertEq("e", e);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment