气体计数。燃烧过的煤气和用过的煤气有啥区别?

Posted

技术标签:

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

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

【问题讨论】:

【参考方案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 对应于实际花费验证者一些计算工作的费用)。

【讨论】:

以上是关于气体计数。燃烧过的煤气和用过的煤气有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

基于51单片机的呼出有毒气体(煤气酒精co)检测仪设计

基于51单片机的呼出有毒气体(煤气酒精co)检测仪设计

转发-基于51单片机的呼出有毒气体(煤气酒精co)检测仪设计

转发-基于51单片机的呼出有毒气体(煤气酒精co)检测仪设计

记事员和用过的vas

企业IT机房中使用什么灭火器?