Solidity : How does function parameters' size affects gas cost?
Asked Answered
E

2

11

before anything here's some context :

Let's say I'm implementing a dApp, and I want to reduce the number of times users have to call the related smart-contract. In order to do this, all the users' actions are stacked-up, client-side. Eventually, users will have to commit their actions to the smart-contract, in order to update their datas on chain.

The smart-contract takes a queue of all the users' actions as a parameter, and iterate over it to do mainly some checkings and update. A bit like this :

function verifyUsersActions(Queue actions) public
{
    while(actions.length != 0)
    {
        Action currentAction = actions.pop(); 
            /* tests on currentAction, update datas, etc */
    }
}

My question is: how does the size of the "actions" object affects gas cost ? What's the increment in gas, between an "actions.length = 2" and an "actions.length = 3" ?

I'm still confused with "memory" and "storage" variables, and don't know in which category does function call parameters fall in.

Elfredaelfrida answered 10/10, 2018 at 9:52 Comment(3)
I think this medium.com/coinmonks/… has answer to your question. Function's parameters are memory. Gas cost for memory is ignoreable compared to cost of instructions. This ethereum.stackexchange.com/questions/29896/… also provide example for memory cost calculation.Grossman
Okay, so according to this first link, function parameters are always in memory, thanks for the clarifications ! After testing in the Remix IDE, it seems like passing arrays as parameters is quite cheap: I first tried to add 10 integers using only memory variables, and stored the result in a state variable; costed 26k gas. Adding 100 uint256 costs around 60k gas, so, it handles scaling pretty well; as you said, the fact of passing parameters is nearly free; what costs gas is mostly storage access and operations, which is good to knowElfredaelfrida
@Elfredaelfrida this is great finding. Thanks for your question.Chuck
L
2

As i saw from comments, ignoring the gas cost of parameter is not a good idea. Parameters, that we gonna call that as calldata will be used on several op codes. To better understand how it affects gas cost we should check the op codes relevant with calldata.

You can find all opcodes at EtherVM

The opcodes we gonna look for are CALLDATALOAD, CALLDATACOPY

The explanations of these op codes are first loads the several calldata with offset, and the second copies the data to the memory.

In solidity when you make a process with parameter and save the result to the memory or storage variable, you have to copy this data to the memory and it cost gas. And simply it increases gas by non-zero values inside the calldata.

If you type dynamic array, struct like your case. At the compilation solidity will add an opcodes to find the value size. It reads each slots(32 bytes) to find the end of your payload. These are all costs gas.

Luthanen answered 28/8, 2022 at 12:57 Comment(0)
L
1

how does the size of the "actions" object affects gas cost ? What's the increment in gas, between an "actions.length = 2" and an "actions.length = 3" ?

I see the other answers talk about how memory, computation, and storage affects the gas usage, but it seems to me your question is about how more arguments or larger lists affects gas usage, without considering memory, computation and storage, so here it is:

One of the parameters that affect the amount of gas used in a transaction is the "input data", it costs 4 gas for every zero byte and 16 gas for every non-zero byte. You can read more details here.

When you pass an array, let's say [1, 2] to a function argument, the transaction data will be:

FFFFFFFF <- The first 4 bytes of the sighash
0000000000000000000000000000000000000000000000000000000000000060 <- signal that an array will start
0000000000000000000000000000000000000000000000000000000000000002 <- the array size (size of [1, 2] is 2)
0000000000000000000000000000000000000000000000000000000000000001 <- first item of array
0000000000000000000000000000000000000000000000000000000000000002 <- second item of array

Note that everything after the sighash has a 32 byte size.

0x60 and then 0x2 (0x2 = size of array) is just how RLP encoding works, it's a way to tell the virtual machine that an array will start and how large it is.

Every 2 digits in hexadecimal represents a byte. You can calc how much more gas will be spent by multiplying the amount of "00"s by 4 and the amount of non "00"s by 16.

By looking at the example above, both items '1' and '2' in the array will spend 140 more gas because they have 1 non-zero byte and 31 zero-byte (16 * 1 + 4 * 31) = 140 gas

If the array has one more item, let's say '3', like [1, 2, 3], it would cost 140 more gas. Because the number 3 also only uses 1 of the 32 bytes.

If the array has a number that uses all bytes, for example:

FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

Then this specific number would add a cost of 32 * 16 = 512 gas to the transaction.

Legitimate answered 17/11, 2022 at 22:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.