坚固性:函数参数的大小如何影响气体成本?



在此之前,这里有一些上下文:

假设我正在实现一个dApp,我想减少用户必须调用相关智能合约的次数。为此,所有用户的操作都堆叠在客户端。最终,用户将不得不将他们的操作提交到智能合约,以便在链上更新他们的数据。

智能合约将所有用户操作的队列作为参数,并对其进行迭代,主要进行一些检查和更新。 有点像这样:

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

我的问题是:"动作"对象的大小如何影响气体成本? 在"actions.length = 2"和"actions.length = 3"之间,gas的增量是多少?

我仍然对">内存"和">存储"变量感到困惑,并且不知道函数调用参数属于哪个类别。

正如我从评论中看到的那样,忽略参数的gas成本不是一个好主意。参数,我们将将其称为调用数据将用于多个操作码。为了更好地了解它如何影响gas成本,我们应该检查与calldata相关的操作码。

您可以在EtherVM上找到所有操作码

我们要寻找的操作码是CALLDATALOAD,CALLDATACOPY。

这些操作码的解释是首先加载带有偏移量的几个调用数据,然后将数据复制到内存中。

当您使用参数进行过程并将结果保存到内存或存储变量时,您必须将此数据复制到内存中,并且需要花费汽油。简单地说,它通过调用数据中的非零值增加gas。

如果您键入动态数组,则结构类似于您的情况。在编译时,solidity 将添加一个操作码来查找值大小。它读取每个插槽(32 字节(以找到有效负载的终点。这些都是汽油成本。

"actions" 对象的大小如何影响 gas 成本?在"actions.length = 2"和"actions.length = 3"之间,gas的增量是多少?

我看到其他答案谈到了内存、计算和存储如何影响 gas 使用,但在我看来,你的问题是关于更多参数或更大的列表如何影响 gas 使用,而不考虑内存、计算和存储,所以这里是:

影响交易中使用的gas量的参数之一是"输入数据",每个零字节花费4个gas,每个非零字节花费16个gas。您可以在此处阅读更多详细信息。

当你传递一个数组时,假设[1, 2]到一个函数参数,交易数据将是:

FFFFFFFF <- The first 4 bytes of the sighash
0000000000000000000000000000000000000000000000000000000000000060 <- signal that an array will start
0000000000000000000000000000000000000000000000000000000000000002 <- the array size
0000000000000000000000000000000000000000000000000000000000000001 <- first item of array
0000000000000000000000000000000000000000000000000000000000000002 <- second item of array

请注意,sighash 之后的所有内容都具有 32 字节大小。

0x60然后是 0x 就是 RLP 编码的工作方式,它是一种告诉虚拟机阵列将启动以及它有多大的方法。

每 2 位数字代表一个字节。您可以通过将"00"的数量乘以 4 和非"00"的数量乘以 16 来计算将花费多少汽油。

通过查看上面的例子,数组中的项目"1"和"2"将多花费 140 gas,因为它们有 1 个非零字节和 31 个零字节(16 * 1 + 4 * 31) = 140 gas

如果数组还有一个项目,假设"3",就像[1, 2, 3]一样,它将花费 140 汽油。因为数字 3 也只使用 1 个字节中的 32 个。

如果数组具有使用所有字节的数字,例如:

FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

然后它会花费32 * 16 = 512 gas.

最新更新