【问题标题】:Gas counting. What is the difference between burnt gas and used gas?气体计数。燃烧过的煤气和用过的煤气有什么区别?
【发布时间】:2020-03-27 09:50:18
【问题描述】:

在交易执行期间,我们正在计算我们“燃烧了多少气体”和“使用了多少气体”。为什么我们必须单独跟踪这些计数器?

【问题讨论】:

    标签: nearprotocol


    【解决方案1】:

    在写这个答案时,@MaksymZavershynskyi 也回答了。

    他的回答应该被认为是权威的,而我的只是猜测。

    看看源代码让我觉得

    • gas_used 是生产存储和计算的成本(完成不会失败的工作)
    • gas_burnt 是非生产性传输、存储和计算的成本(从 A 点到 B 点获取数据、尝试执行功能但在执行过程中失败或导致错误等)

    这是一堆给我留下这种印象的源代码链接的sn-ps

    来自nearcore/runtime/runtime/src/lib.rs

    fn generate_refund_receipts(
        &self,
        receipt: &Receipt,
        action_receipt: &ActionReceipt,
        result: &mut ActionResult,
    ) -> Result<(), RuntimeError> {
        /// ... snip ...
        let gas_refund = if result.result.is_err() {
            safe_add_gas(prepaid_gas, exec_gas)? - result.gas_burnt
        } else {
            safe_add_gas(prepaid_gas, exec_gas)? - result.gas_used
        };
        /// ... snip ...
    }
    

    source


    来自nearcore/runtime/runtime/src/actions.rs

    pub(crate) fn action_function_call(
        state_update: &mut TrieUpdate,
        apply_state: &ApplyState,
        account: &mut Option<Account>,
        receipt: &Receipt,
        action_receipt: &ActionReceipt,
        promise_results: &[PromiseResult],
        result: &mut ActionResult,
        account_id: &AccountId,
        function_call: &FunctionCallAction,
        action_hash: &CryptoHash,
        config: &RuntimeConfig,
        is_last_action: bool,
    ) -> Result<(), StorageError> {
        /// ... snip ...
        if let Some(outcome) = outcome {
            result.gas_burnt += outcome.burnt_gas;
            result.gas_burnt_for_function_call += outcome.burnt_gas;
            // Runtime in `generate_refund_receipts` takes care of using proper value for refunds.
            // It uses `gas_used` for success and `gas_burnt` for failures. So it's not an issue to
            // return a real `gas_used` instead of the `gas_burnt` into `ActionResult` for
            // `FunctionCall`s.
            result.gas_used += outcome.used_gas;
            result.logs.extend(outcome.logs.into_iter());
        }
        /// ... snip ...
    }
    

    source


    来自nearcore/core/primitives/src/types.rs

    pub struct ChunkExtra {
      /// ... snip ...
    
      /// Actually how much gas were used.
      pub gas_used: Gas
    
    /// ... snip ...
    }
    

    source


    来自nearcore/core/primitives/src/sharding.rs

    pub struct ShardChunkHeaderInner {
      /// ... snip ...
    
      /// Gas used in this chunk.
      pub gas_used: Gas,
    
      /// ... snip ...
    }
    

    source


    来自nearcore/runtime/runtime/src/config.rs

    /// ... snip ...
    
    pub fn tx_cost(
        config: &RuntimeFeesConfig,
        transaction: &Transaction,
        gas_price: Balance,
        sender_is_receiver: bool,
    ) -> Result<(Gas, Gas, Balance), IntegerOverflowError> {
        let mut gas_burnt: Gas = config.action_receipt_creation_config.send_fee(sender_is_receiver);
        gas_burnt = safe_add_gas(
            gas_burnt,
            total_send_fees(&config, sender_is_receiver, &transaction.actions)?,
        )?;
        let mut gas_used = safe_add_gas(gas_burnt, config.action_receipt_creation_config.exec_fee())?;
        gas_used = safe_add_gas(gas_used, total_exec_fees(&config, &transaction.actions)?)?;
        gas_used = safe_add_gas(gas_used, total_prepaid_gas(&transaction.actions)?)?;
        let mut total_cost = safe_gas_to_balance(gas_price, gas_used)?;
        total_cost = safe_add_balance(total_cost, total_deposit(&transaction.actions)?)?;
        Ok((gas_burnt, gas_used, total_cost))
    }
    /// ... snip ...
    
    
    /// Total sum of gas that would need to be burnt before we start executing the given actions.
    pub fn total_exec_fees(
        config: &RuntimeFeesConfig,
        actions: &[Action],
    ) -> Result<Gas, IntegerOverflowError> {
      /// ... snip ...
    }
    
    /// Get the total sum of deposits for given actions.
    pub fn total_deposit(
        actions: &[Action]
    ) -> Result<Balance, IntegerOverflowError> {
      /// ... snip ...
    }
    
    /// Get the total sum of prepaid gas for given actions.
    pub fn total_prepaid_gas(
        actions: &[Action]
    ) -> Result<Gas, IntegerOverflowError> {
      /// ... snip ...
    }
    

    source

    【讨论】:

      【解决方案2】:
      • 使用的气体包括燃烧的气体,所以gas_used &gt;= gas_burnt,总是这样;
      • 收取任何费用时,均计入gas_burntgas_used
      • 当合约执行跨合约调用并将X 数量的gas 附加到此调用时,X 计入gas_used 但不计入gas_burnt。这是gas_usedgas_burnt 之间差异的唯一来源。如果智能合约在完成执行之前失败,则不会执行任何跨合约调用(或由合约创建的交易)并退还附加的 gas;
      • 根据前面的要点,当合约失败时,gas_used - gas_burnt 将被退还给账户,而gas_burnt 将永远丢失(因为gas_burnt 对应于实际花费验证者一些计算工作的费用)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-06-06
        • 2021-02-08
        • 1970-01-01
        • 2016-03-08
        • 1970-01-01
        • 2020-03-21
        • 1970-01-01
        相关资源
        最近更新 更多