# How long can a string be until it spills into the next word?

`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");
}
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.

• Splitting in emoji? Mar 9, 2018 at 14:09
• "1234567890" > "(happy face)56(happy face)" Mar 11, 2018 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 ? Mar 11, 2018 at 17:07
• Here is the Solidity doc that talks to this. Basically, a sting of up to 31 bytes stays in 1 word, 31 bytes for the string itself and 1 byte for the string length. Once the strings hits 32 bytes it takes 2 words, 1 word for the state slot, which stores the length, and 1 word for the string itself. At this point additional words are added each time the next 32 byte boundary is broken. The cost/length data in the question bares this out. Mar 27 at 11:59

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