0

string is dynamic length storage.

I imagine a string of length (bytes length) 1, 2 or 3 is all the same length on storage, probably one word.

Which byte causes it to spill over into a second, third and fourth word?


I tried using strings like "123456789abcdef0" that repeated on and on. This is the data I came up with. I also tried splicing in emoji at the beginning or end of the string.

  • Transaction cost / Execution cost / Length(bytes)
  • 48302 26454 1
  • 50222 26454 31
  • 70389 46557 32
  • 90651 66627 33
  • 92635 66627 64
  • 112897 86697 65
  • 114881 86697 96
  • 135143 106767 97
  • 137127 106767 128
  • 157389 126837 129

Test case:

pragma solidity ^0.4.20;
contract StringGas {
    string[] words;
    function StringGas() public {
        words.push("BEGIN");
    }
    function addAWord(string _word) external {
        words.push(_word);
    }
}

I did it by hand. I'm sure somebody has a fancy Truffle way to do this. This is just data, maybe there is SOME input that breaks my experiment here.

| improve this question | | | | |
  • Splitting in emoji? – Teleporting Goat Mar 9 '18 at 14:09
  • "1234567890" > "(happy face)56(happy face)" – William Entriken Mar 11 '18 at 15:42
  • I still have no idea what you're referring to. Is (happy face) supposed to be equivalent to both 1234 and 7890 ? – Teleporting Goat Mar 11 '18 at 17:07
1

A string contains a 1 word (32 byte) length, followed by its bytes packed right zero padded to the nearest 32 byte word. Keep in mind that utf-8 characters like emoji are multiple bytes long.

var ethers = require('ethers');

function getString(length) {
    var s = '';
    while (s.length < length) { s += '0'; }
    return s;
}

for (var l = 0; l < 5 * 32; l++) {
    var b = ethers.utils.AbiCoder.defaultCoder.encode(
        [ 'string' ],
        [ getString(l) ]
    );
    // Subtracting 2 for the 0x prefix (hex string)
    // Dividing by 2 since 2 nibbles per byte (hex string)
    // Subtracting 32 because the ABI includes a pointer
    console.log('length=' + l + ' => bytes=' + ((b.length - 2) / 2 - 32));
}

Which gives us (length is string length, bytes is storage bytes):

  • length=0 => bytes=32
  • length=1 => bytes=64
  • length=2 => bytes=64
  • ...
  • length=32 => bytes=64
  • length=33 => bytes=96
  • ...
  • length=64 => bytes=96
  • length=65 => bytes=128
  • ...
  • length=96 => bytes=128
  • length=97 => bytes=160
  • ...
  • length=128 => bytes=160
  • length=129 => bytes=192
| improve this answer | | | | |

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.