0

I am using string as a key on mapping data structure.

[Q] While we are use mapping, when the length of the key string increases, does it also increase the gas usage?

mapping(string => int) map;

contract.array("mykey");                                 //short key length.
contract.array("mykey_mykey_mykey_mykey_mykey_mykey");   //longer key length is used.

function array(string key){
    map[key] = 10;
}

Thank you for your valuable time and help.

6
  • Does this even compile? Generally you would hash the value to create a fixed-length key, which will incidentally have the same gas usage as any other key. Oct 7, 2017 at 13:03
  • Actually it does compile, I am able to use it with different key length sizes. @Edmund Edgar
    – alper
    Oct 7, 2017 at 13:05
  • OK, it's probably hashing the string for you anyhow, in which case you'll have constant gas. Oct 7, 2017 at 13:07
  • So no matter what if I pass longer string to the function it won't affect the gas usage right? @EdmundEdgar
    – alper
    Oct 7, 2017 at 13:10
  • That would be my guess, except for the cost of hashing the input, which should be fairly trivial compared to storage unless your strings are crazy long. Oct 7, 2017 at 13:47

1 Answer 1

5

Passing longer strings to your function will use more gas for a number of reasons:

  1. The CALLDATA of the transaction, which contains the parameters passed to the functions of your contract, is charged at 16 gas per non-zero byte (G_txdatanonzero in the Yellow Paper).

  2. Each word of data passed to KECCAK256 by the EVM costs an extra 6 gas (G_sha3word). So if your string is more than 32 bytes long, it will add 6 gas per 32 bytes extra. KECCAK256 is used to turn the string into a key for the mapping lookup.

  3. The compiled code uses CALLDATACOPY to copy the string into memory. This costs 3 gas per 32 byte word (G_copy), so again increases with length of string.

  4. Each extra word of memory used by the EVM costs gas - a longer string will cause more memory to be used. The marginal cost of memory allocation increases quadratically with memory size, so it depends on how much memory you are already using. See equation (222) in the YP.

That's all I can think of for now, but there may be more.

8
  • Great answer! To understand better, if I pass uint32 instead of passing 45 length string, would it cost less gas? If yes, I will change my implementation and use uint32 as a key instead of using 45 length or longer string. What would be your advice? @benjaminion
    – alper
    Oct 7, 2017 at 19:08
  • 1
    uint32 would give you a constant cost (nearly! zero bytes in the calldata cost only 4 gas, rather than 68, but at least the gas cost would be bounded). On the whole, hashing the string before sending it seems a bit cleaner to me, but you lose transparency in that the string is no longer available to see in the transaction history on the blockchain. Really depends on your use case and requirements. I wouldn't say it's a big issue. Oct 7, 2017 at 19:20
  • Thank you sir. Hash the string, and use its hash as the key seems like the best option because I provide more than one string to the function and I can just merge them. For hashing do you recommend any algorithm to use? I was thinking to use base64 decode/encode but I was not sure since I won't able to use base64 decoded string as uint64 format. @benjaminion
    – alper
    Oct 7, 2017 at 19:48
  • 1
    Not really my area of expertise, but SHA-256 would produce the right output size (32 bytes/256 bits) and is standard. base64 doesn't give you a constant output size, I think. Oct 7, 2017 at 20:06
  • 1
    Oh that was the reason I was trying in python/populus and giving was as string that was the main reason I guess. @benjaminion
    – alper
    Oct 8, 2017 at 17:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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