Hedera上几乎相同交易中`gasUsed`值的巨大差异 – 为什么?

huangapple go评论52阅读模式
英文:

Large discrepancy in `gasUsed` values in near-identical transactions on Hedera - why?

问题

以下是翻译好的部分:

我注意到一个问题,即一笔交易使用的燃气数量几乎相同:

我连续两次调用一个智能合约,并且两次调用的参数几乎相同,唯一的区别是在第一次调用中,我将gasLimit设置为eth_estimateGas返回的确切值,而在第二次调用中,我将gasLimit设置为eth_estimateGas * 1.1

以下是输出,显示了以下情况:

  • gasLimit设置为400,000时,gasUsed为320,000
  • gasLimit设置为440,000时,gasUsed为352,000

为什么第二次调用会额外消耗32,000单位的燃气?
(我期望两种情况下gasUsed的值是相同的。)

以下是智能合约的代码:

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.18;

contract ExpendSomeGasDemo {
    uint256 public state;

    function updateState(
        uint256 newState
    )
        public
        returns (uint256 updatedState)
    {
        state = newState;
        updatedState = newState;
    }
}

请注意,此合约部署在 Hedera Testnet 上:
0x9C58D0159495F7a8853A24574f2B8F348a72424c

请注意,上述的 JavaScript 示例中使用了 ethers.js。

英文:

I have noticed that there is a discrepancy between the amount of gas used
by a transaction is almost identical:

I'm making a call to a smart contract,
with the same parameters twice in a row,
and the only difference between the 2
is that I'm setting gasLimit to the exact value
returned by eth_estimateGas in the 1st one,
and I'm setting gasLimit to eth_estimateGas * 1.1 in the 2nd one.

    // with exact estimated amount of gas
    const estimatedGas2 = (await expendGasSc.estimateGas.updateState(1_000_000_123n)).toBigInt();
    console.log('estimatedGas2', estimatedGas2);
    const gasLimit2 = estimatedGas2 * 1n;
    console.log('gasLimit2', gasLimit2);
    const txResponse2 = await (await expendGasSc
        .updateState(
            1_000_000_123n,
            { gasLimit: gasLimit2 },
        ))
        .wait();
    const gasUsed2 = txResponse2.gasUsed.toBigInt();
    console.log('gasUsed2', gasUsed2);

    // with 110%  of estimated amount of gas
    const estimatedGas3 = (await expendGasSc.estimateGas.updateState(1_000_000_123n)).toBigInt();
    console.log('estimatedGas3', estimatedGas3);
    const gasLimit3 = estimatedGas3 * 11n / 10n;
    console.log('gasLimit3', gasLimit3);
    const txResponse3 = await (await expendGasSc
        .updateState(
            1_000_000_123n,
            { gasLimit: gasLimit3 },
        ))
        .wait();
    const gasUsed3 = txResponse3.gasUsed.toBigInt();
    console.log('gasUsed3', gasUsed3);

Here's the output, which shows that:

  • when gasLimit is set to 400,000, gasUsed is 320,000
  • when gasLimit is set to 440,000, gasUsed is 352,000
estimatedGas2 400000n
gasLimit2 400000n
gasUsed2 320000n
estimatedGas3 400000n
gasLimit3 440000n
gasUsed3 352000n

Why does the 2nd invocation expend an additional 32,000 in gas?
(I expected the gasUsed value to be the same in both cases.)


Here's the smart contract:

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.18;

contract ExpendSomeGasDemo {
    uint256 public state;

    function updateState(
        uint256 newState
    )
        public
        returns (uint256 updatedState)
    {
        state = newState;
        updatedState = newState;
    }
}

Note that this contract is deployed on Hedera Testnet:
0x9C58D0159495F7a8853A24574f2B8F348a72424c

Note that the Javascript example above is using ethers.js.

答案1

得分: 4

这是因为:
HIP-185: 智能合约服务基于燃气的限制

为了确保交易能够正常执行,通常会设置一个比执行所需的燃气更高的燃气预留。

在以太坊主网上,整个预留都会在执行之前收取到账户,然后未使用的部分将被退还。

然而,以太坊主网利用了内存池,并在块生产时进行事务排序,这允许块限制仅基于已使用的燃气而不是预留燃气。

本质上,gasLimit 指的是“更高的燃气预留”,
gasUsed 指的是“执行消耗的燃气”。
在以太坊中,计算很简单:

gasUsed = gasConsumed

换句话说,gasLimit 不是 一个因素。

然而,在 Hedera 中,这是不可能的,
因为 Hedera 的共识节点不使用事务池,
然后在块内对事务进行排序。
事实上,Hedera 甚至没有块的概念
在其共识节点中,
只在其存档节点(Mirror 节点)中添加了这个概念 -
参见 HIP-415: 块的引入

因此,Hedera 需要一种与以太坊的替代机制
以使其能够限制过度预留的燃气。
它通过激励来实现了这一点:
为了防止智能合约服务的过度预留,与预留相关的燃气将被限制在最多预留金额的20%。
从不同的角度来看,根据预留计算的用户所收取的最低燃气量将至少是预留的80%。
这将激励交易提交者确保其使用的燃气量不超过实际燃气用量的25%,以免被收取未使用的预留。

因此,在 Hedera 中,gasUsed 的计算方式是:

gasUsed = max(gasConsumed, gasLimit * 0.8)

换句话说,gasLimit 一个因素,
当您指定的值超过实际燃气消耗时,
这就是您在 gasLimit 中指定额外的40,000 燃气时获得额外的 32,000 gasUsed 的方式。

英文:

This is because of:
HIP-185: Smart Contract Service Gas Based Throttling

> In order to ensure that the transactions can execute properly it is common to set a higher gas reservation than will be consumed by execution.
> In Ethereum Mainnet the entire reservation is charged to the account prior to execution and then unused portion of the reservation is credited back.
> Ethereum Mainnet, however, utilizes a memory pool and does transaction ordering at block production time, and that allows the block limit to be based only on used gas and not reserved gas.

Essentially gasLimit refers to the "higher gas reservation",
and gasUsed is refers to the gas "consumed by execution".
In Ethereum, the calculation is simply:

gasUsed = gasConsumed


In other words, gasLimit is not a factor.

However, in Hedera, this isn't possible,
since Hedera's consensus nodes do not make use of a transaction pool,
and then subsequently order transactions within a block.
In fact, Hedera does not even have the concept of blocks
within its consensus nodes,
and only add this concept in its archival nodes (Mirror nodes) -
see HIP-415: Introduction Of Blocks.

Therefore Hedera needs an alternative mechanism to Ethereum's
to enable it to limit over-reservation of gas.
It has done so by disincentivisation:

> In order to prevent over-reservation of the smart contract services the gas credited back relative to the reservation will be limited to at most 20% of the reservation amount.
> From a different perspective the minimum amount of gas charged to a user based on the reservation will be a minimum of 80% of the reservation.
> This will incentivize transaction submitters to get within 25% of the actual gas used in order to not be charged for unused reservation.

So the computation for gasUsed in Hedera is:

gasUsed = max(gasConsumed, gasLimit * 0.8)


In other words, gasLimit is a factor,
when you specify one that is more than actual gas consumed.

This is how you get the additional 32,000 gasUsed
when you specify an additional 40,000 in gasLimit.

huangapple
  • 本文由 发表于 2023年5月15日 11:02:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76250641.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定