2

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 :)

  • Do you account the cost of running EVM code in your fee? You are also paying for the EVM CPU time. – Mikko Ohtamaa Apr 30 at 21:12
  • If you want to measure the gas cost of saving the string "Test123", then write a function which saves that string directly and explicitly. In your code, you are doing a lot more than just saving that specific string, for example: 1. You receive it as input. 2. You push it into an array. – goodvibration May 1 at 4:01
  • @MikkoOhtamaa: Do you mean the sstore operation mentioned from goodvibration? I only looked at the appendix G from the yellow paper. It doesn't mention CPU time, only operations it is doing – Mr. 124 May 1 at 9:22
2

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.

| improve this answer | |
  • Wow, thank you so much. I actually didn't think about the sstore operation! Now that you mentioned it, it is quite obvious. – Mr. 124 May 1 at 9:18
  • @Mr.124: You're welcome. Note that my answer still doesn't fully account for the exact cost (64244) of your transaction, but slightly less than that. – goodvibration May 1 at 10:09
  • The approximation is quite correct, but there are a couple of things that may be worth to note: 1) input data is much longer, it is 100 bytes, although it is mostly zero bytes (need to be encoded in solidity abi), 2) with Istanbul fork non-zero bytes in calldata cost 16, 3) short strings are stored in a compact way using a single slot. – Ismael May 1 at 16:21
  • @Ismael: Thanks for the review!! I was aware of #1, but multiplying that (number of non-zero bytes) by 68 didn't quite account for the missing 3k gas. – goodvibration May 1 at 16:59
  • @goodvibration Executing the code in remix gives 22.2k in transaction costs and 42.6k in execution. So there is an extra 1.2k in input data and 2.6k in execution. Those numbers may vary with compiler and optimization, but seems reasonable for a function dealing with a string. – Ismael May 1 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.