I'm assuming this has to do with Ethereum's 7 variable stack limit but in the following code test
struct TestStruct5 {
uint8 m_nOther1;
uint8 m_nOther2;
uint8 m_nOther3;
uint8 m_nOther4;
uint8 m_nOther5;
}
struct TestStruct6 {
uint8 m_nOther1;
uint8 m_nOther2;
uint8 m_nOther3;
uint8 m_nOther4;
uint8 m_nOther5;
uint8 m_nOther6;
}
struct TestStruct7 {
uint8 m_nOther1;
uint8 m_nOther2;
uint8 m_nOther3;
uint8 m_nOther4;
uint8 m_nOther5;
uint8 m_nOther6;
uint8 m_nOther7;
}
struct TestStruct8 {
uint8 m_nOther1;
uint8 m_nOther2;
uint8 m_nOther3;
uint8 m_nOther4;
uint8 m_nOther5;
uint8 m_nOther6;
uint8 m_nOther7;
uint8 m_nOther8;
}
struct TestStruct9 {
uint8 m_nOther1;
uint8 m_nOther2;
uint8 m_nOther3;
uint8 m_nOther4;
uint8 m_nOther5;
uint8 m_nOther6;
uint8 m_nOther7;
uint8 m_nOther8;
uint8 m_nOther9;
}
TestStruct5[] internal m_testStruct5;
TestStruct6[] internal m_testStruct6;
TestStruct7[] internal m_testStruct7;
TestStruct8[] internal m_testStruct8;
TestStruct9[] internal m_testStruct9;
function GasTest5(address a_owner) external returns (uint256)
{
TestStruct5 memory item = TestStruct5({
m_nOther1 : 0,
m_nOther2 : 0,
m_nOther3 : 0,
m_nOther4 : 0,
m_nOther5 : 0
});
uint256 nItemID = m_testStruct5.push(item) - 1;
}
function GasTest6(address a_owner) external returns (uint256)
{
TestStruct6 memory item = TestStruct6({
m_nOther1 : 0,
m_nOther2 : 0,
m_nOther3 : 0,
m_nOther4 : 0,
m_nOther5 : 0,
m_nOther6 : 0
});
uint256 nItemID = m_testStruct6.push(item) - 1;
}
function GasTest7(address a_owner) external returns (uint256)
{
TestStruct7 memory item = TestStruct7({
m_nOther1 : 0,
m_nOther2 : 0,
m_nOther3 : 0,
m_nOther4 : 0,
m_nOther5 : 0,
m_nOther6 : 0,
m_nOther7 : 0
});
uint256 nItemID = m_testStruct7.push(item) - 1;
}
function GasTest8(address a_owner) external returns (uint256)
{
TestStruct8 memory item = TestStruct8({
m_nOther1 : 0,
m_nOther2 : 0,
m_nOther3 : 0,
m_nOther4 : 0,
m_nOther5 : 0,
m_nOther6 : 0,
m_nOther7 : 0,
m_nOther8 : 0
});
uint256 nItemID = m_testStruct8.push(item) - 1;
}
function GasTest9(address a_owner) external returns (uint256)
{
TestStruct9 memory item = TestStruct9({
m_nOther1 : 0,
m_nOther2 : 0,
m_nOther3 : 0,
m_nOther4 : 0,
m_nOther5 : 0,
m_nOther6 : 0,
m_nOther7 : 0,
m_nOther8 : 0,
m_nOther9 : 0
});
uint256 nItemID = m_testStruct9.push(item) - 1;
}
The Gas output for the following is:
GasTest5 gas: 49046
GasTest6 gas: 49098
GasTest7 gas: 49206
GasTest8 gas: 86443
GasTest9 gas: 91843
We can see that adding a 6th and 7th element to the struct adds trivial extra gas, but once you add an 8th item the gas cost almost doubles and a 9th item is 5k+ extra gas. Since all items are uint8s the total is well below a uint256.
What is causing this? I have a lot of data to track related to an ERC721 and was hoping to pack most of it into a single uint256 struct but this causes major problems.
Edit: Truffle Compiler settings
compilers: {
solc: {
version: "0.5.2", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
settings: { // See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: true,
runs: 1000
},
//evmVersion: "constantinople"
}
}
Edit 2: It seems to have to do with pushing the item into an array or mapping. Without that gas doesnt explode with more struct items. I wonder if copying it into storage with more than 7 variables causes problems. No one seems to know the answer and I can't find any info anywhere.
GasTest9
is48926 gas
. What version of Solidity are you using and what compiler?