[Ethereum] Calculate transaction costs for storing data

etherevmgasgas-pricetransactions

I'm trying to figure out how the transaction costs are calculated for a transaction that is storing data on the Ethereum Blockchain. It seems I'm always off. Here is my way of calculating (I'm using the Kovan Testnet but I guess the calculation should be identical):

I uploaded the follwing smart contract

pragma solidity ^0.5.12;

contract NewContract {

    struct Location {
        string JSON;
    }

    Location[] locations;

    function createLocation(string memory _json) public {
        locations.push(Location(_json));
    }

    function viewLocation(uint _id) public view returns(string memory) {
        string memory result = locations[_id].JSON;
        return result;
    }
}

When I save the String: "Test123" I assumed the price would be made up out of the following stats according to the yeelow paper: https://ethereum.github.io/yellowpaper/paper.pdf Appendix G. Fee Schedule

68: Paid for every non-zero byte of data or code for a transaction.

21000: Paid for every transaction.

Since the size of the string "Test123" is 7 Byte my calculation was:
(21.000 + (7*68))*9(Gwei)= 21.476 gas * 9 Gwei = 193.284 Gwei (transaction costs)

Which would be 0.000193284 Ether
My test calculation: https://kovan.etherscan.io/tx/0x8098ddd06cefe06280a4a499c5ff04d9fa93af64a7b77d060173607c32b54c4c
said that it used 64.244 Gas and it cost 0.000578196 Ether

What calculation does the EVM do that I'm not aware of?

Thanks in advance 🙂

Best Answer

First of all, you don't need to add the gas-price into your computation.

This factor is chosen by you (the transaction sender), so there are no questions about it.

The only part in question is the 64244 gas units used in the transaction.

According to the white-paper, you have determined that it should be 21000 + 68 * 7 = 21476:

  • 21000: Paid for every transaction
  • 68: Paid for every non-zero byte of data or code for a transaction

But you forgot to take into account:

  • 20000: Paid for an SSTORE operation when the storage value is set to non-zero from zero

In your code - locations.push(Location(_json)) - there are two of these:

  1. Changing the length of locations from 0 to 1
  2. Changing the length of locations[0] from 0 to 7 (the length of "Test123")

These two yield an additional amount of 20000 * 2 = 40000 gas units.

The bottom line of all of this, is that if you want to measure the gas-cost of saving a specific string, then write a function which saves it directly and explicitly.

Your function does a lot more than just saving that specific string, i.e., it receives it as input and pushes it into an array of strings.

Related Topic