i had a struct containing the following data types (in this order) that is passed via calldata:
1. address
2. bytes
3. bytes
i inserted a uint96 between the address and the first bytes field because i figured that there'd by 96 bits that are unused, since the first bytes value would probably be 32-byte-aligned
however, to my surprise, the total amount of calldata actually grew by 32 bytes. where did i go wrong? how can i compute how big the uint can actually be without increasing the calldata size?
Aug 29, 2022, 4:27 PM
i tried following https://docs.soliditylang.org/en/v0.8.16/internals/layout_in_storage.html when making my assumptions. however, some of the information given there seems to be wrong. in particular, it says the following about structs:
"Structs and array data always start a new slot and their items are packed tightly according to these rules."
this cannot be true because my struct contains 2 dynamically-sized values (the two values of type bytes). if the contents of the struct were actually tightly packed, there'd be no way of knowing when the first bytes value ends and when the second one begins
"Structs and array data always start a new slot and their items are packed tightly according to these rules."
this cannot be true because my struct contains 2 dynamically-sized values (the two values of type bytes). if the contents of the struct were actually tightly packed, there'd be no way of knowing when the first bytes value ends and when the second one begins
Aug 29, 2022, 4:30 PM
Le code?
Aug 29, 2022, 4:32 PM
here is le code minimale:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.11;
contract CalldataSizeTest {
struct Call {
address leAddress;
// uint96 leUint;
bytes leBytesPremier;
bytes leByetsSecond;
}
Call public phonebox;
function callMe(Call calldata baby) external {
phonebox = baby;
}
}
pragma solidity ^0.8.11;
contract CalldataSizeTest {
struct Call {
address leAddress;
// uint96 leUint;
bytes leBytesPremier;
bytes leByetsSecond;
}
Call public phonebox;
function callMe(Call calldata baby) external {
phonebox = baby;
}
}
i deployed it to rinkeby both with the uint96 line present and with it commented out:
- https://rinkeby.etherscan.io/tx/0x28f9351c76df60d7f7e3c4773e2ab5b2aa0727e5850ecc438bd38cf1bc23c91e
- https://rinkeby.etherscan.io/tx/0x2932365f6ea05bf150cc440fb5c8a2f679cca30b99fb40dd729150af44d95388
- https://rinkeby.etherscan.io/tx/0x28f9351c76df60d7f7e3c4773e2ab5b2aa0727e5850ecc438bd38cf1bc23c91e
- https://rinkeby.etherscan.io/tx/0x2932365f6ea05bf150cc440fb5c8a2f679cca30b99fb40dd729150af44d95388
the calldata of the first one (present) is 586 hex characters long (according to etherscan), the second one (commented out) only 522 hex characters, making them differ by 32 bytes
it says it's tightly packed. if it's tightly packed,
["0xc2c5A236395382f861a3D956C720b29A4Ae4f15B", 1, "0xab", "0xcd"]
should only require 1 slot
["0xc2c5A236395382f861a3D956C720b29A4Ae4f15B", 1, "0xab", "0xcd"]
should only require 1 slot
even if arrays start a new slot,
["0xc2c5A236395382f861a3D956C720b29A4Ae4f15B", 1, "0xab", "0xcd"]
should only require 3 slots if anything is tightly packed and 1 is a uint8
["0xc2c5A236395382f861a3D956C720b29A4Ae4f15B", 1, "0xab", "0xcd"]
should only require 3 slots if anything is tightly packed and 1 is a uint8
160 + 8 is way below 256
it's added below something that should have 96 bits left til a full slot
Aug 29, 2022, 5:02 PM
doesn´t calldata follow contract abi specification? afaik calldata values are all zero padded to 32 values so each argument would be a slot theorically
https://docs.soliditylang.org/en/v0.8.16/abi-spec.html
https://docs.soliditylang.org/en/v0.8.16/abi-spec.html
Aug 29, 2022, 5:18 PM
thank you
both of you
i just noticed that this actually explains quite a few situations where i found the gas costs weird. i measured the gas costs w/o checking out whether the call data increased because i was so sure that any struct where the constituents are fixed-length types and sum to at most 256 bit only take up 32 bytes of calldata. i forgot to account for the extra cost paid for calldata
i sometimes squeeze like 10 variables into a single slot using structs ... damn 10x cost for calldata...
Aug 29, 2022, 5:30 PM
No packing on calldata. Every single element is 32 bytes
^this
Well you can still use packing in calldata, but need to extract out params individually
Aug 29, 2022, 5:37 PM
Yeah that's what I'm going to do with my big structs now
Hoping that the compiler is smart enough to know that it cancopy 32 bytes from calldata to memory without always copying just 3 bytes from calldata to memory and then always 32 bytes reading + 32 bytes writing for every 3 bytes chunk when transferring the data from memory to storage
Given how stupid the compiler is in terms of optimization in a lot of situations, I have a really bad feeling about this
Aug 29, 2022, 5:41 PM
Did your friend really screenshot from remix and put it on a pdf?
Aug 29, 2022, 5:54 PM
Seems like way more work than sending the sol file
Aug 29, 2022, 5:57 PM
Are you sure you don't want to send a picture you took with your phone of a print-out of the email your friend sent you with an in-line embedding of that PDF?
Aug 29, 2022, 6:01 PM
i've seen worse, a screenshot on an excel file and the .xlsx attached to the ticket
Aug 29, 2022, 6:02 PM
It's not screenshots, though. The text is selectable
Guys, i think we need some JPEG compression artifacts and a 9gag and an ifunny watermark
Aug 29, 2022, 6:03 PM
absolutely barbaric
this man is gonna send us a charles hoskinson youtube stream frame by frame in a ppt file, god save us
Aug 29, 2022, 6:13 PM
Interlaced
Aug 29, 2022, 6:14 PM
hahahahah hoskinsonwave
Aug 29, 2022, 6:14 PM
But seriously, i think we have a winner with that line printer
Aug 29, 2022, 6:41 PM
I found my new IDE.
Aug 29, 2022, 6:43 PM
Yeah, why spend money on a 49 inch ultra wide curved monitor if you can have a 200 ft flexible screen?
Aug 29, 2022, 6:48 PM
L0L
Aug 29, 2022, 6:50 PM
💯
Aug 29, 2022, 7:00 PM