Let's say I have require statement like this:
require(owner == msg.sender, "Only owner can call this function xxxxxxxxxx");
The string is longer than 32 bytes so my question is if it is stored in 2 storage slots.
And if we can save gas if the string is shorter than 32 bytes.
Thanks
Your assumption is somewhat correct. But it's not as straightforward as "one storage slot per each 32 bytes, times 2100 gas units per each slot read".
First of all, it's a constant, so it's included in the compiled contract bytecode (that is effectively stored in multiple storage slots). Depending on how much bytecode is stored before this string in the same slot, sometimes even a string shorter than 32 bytes can be theoretically split between 2 slots.
But because it's a part of the contract bytecode, the whole executed function is loaded into memory and the string is returned from memory, without any additional storage reads.
So, having a longer error message is more expensive during contract deployment (need to store longer bytecode). But the execution cost only increases by 3 gas units per each memory slot access, which is insignificant in most cases.
Example 1 - bytecode 374 bytes, execution of foo()
21510 gas.
pragma solidity ^0.8;
contract MyContract {
function foo() external {
require(false, "Only owner can call this function xxxxxxxxxx");
}
}
Example 2 - bytecode 322 bytes, execution of foo()
21492 gas.
pragma solidity ^0.8;
contract MyContract {
function foo() external {
require(false, "no");
}
}