I've read several related answers and blog posts, all of them suggesting that for the sake of reading complex state variables (i.e., arrays and structures), one should always prefer declaring the local variable used for this purpose as memory rather than as storage:
I've conducted several tests, performing let response = await someTransaction() and then recording the value of response.receipt.gasUsed. All of these tests have unanimously shown that declaring the local variable as memory yields a higher gas-consumption than declaring it as storage.
Here is a very simple Truffle test which illustrates this:
Contract:
pragma solidity 0.4.25;
contract MyContract {
struct Record {
bool valid;
uint val1;
uint val2;
uint val3;
}
mapping(uint => Record) public table;
uint public count;
function insert(uint key, uint val1, uint val2, uint val3) external {
Record storage record = table[key];
if (record.valid == false) {
record.valid = true;
record.val1 = val1;
record.val2 = val2;
record.val3 = val3;
count += 1;
}
}
function storage_remove(uint[] keys) external {
for (uint i = 0; i < keys.length; i++) {
Record storage record = table[keys[i]];
if (record.valid == true) {
delete table[keys[i]];
count -= 1;
}
}
}
function memory_remove(uint[] keys) external {
for (uint i = 0; i < keys.length; i++) {
Record memory record = table[keys[i]];
if (record.valid == true) {
delete table[keys[i]];
count -= 1;
}
}
}
}
Test:
contract("MyContractTest", function() {
const keys = [...Array(10).keys()];
it("storage_remove gas consumption", async function() {
const myContract = await artifacts.require("MyContract").new();
for (let key of keys)
await myContract.insert(key, key, key, key);
const response = await myContract.storage_remove(keys);
console.log(response.receipt.gasUsed);
});
it("memory_remove gas consumption", async function() {
const myContract = await artifacts.require("MyContract").new();
for (let key of keys)
await myContract.insert(key, key, key, key);
const response = await myContract.memory_remove(keys);
console.log(response.receipt.gasUsed);
});
});
Results:
Contract: MyContractTest storage_remove gas consumption: 142257
Contract: MyContractTest memory_remove gas consumption: 145976
Side Note:
The above is essentially a comparison between:
- The gas cost of reading
record.validusingstorage record - The gas cost of reading
record.validusingmemory record
So what course of action should I take - use memory as suggested everywhere, or use storage which has proved to be less expensive?
Thank you!
storagereference data to amemoryreferenced variable, we are copying data fromstoragetomemory. New memory is allocated. That's why you are getting this. – Mahesh Rajput Jan 30 '19 at 13:23storage vs memorytoby reference vs by valuefrom C/C++). However, none of the posts that I've read mentioned anything about this, so I tend to think that this type of comparison between the block-chain and "traditional" systems is incorrect. – goodvibration Jan 30 '19 at 13:26