Alert Source Discuss
🚧 Stagnant Standards Track: Core

EIP-2045: EVM 操作码的微粒化 gas 消耗

Authors Casey Detrio (@cdetrio), Alex Beregszaszi (@axic)
Created 2019-05-17
Discussion Link https://ethereum-magicians.org/t/eip-2045-fractional-gas-costs/3311

摘要

根据最近的基准测试,用于计算的 EVM 操作码(ADDSUBMUL 等)相对于用于存储 I/O 的操作码(SLOADSSTORE 等)而言,通常定价过高。目前,最小的 gas 成本为 1(即一个单位的 gas),并且大多数计算操作码的成本接近 1(例如 3、5 或 8),因此可能的成本降低范围有限。一种新的最小 gas 单位,称为“微粒 (particle)”,是 1 gas 的一小部分,将扩大 gas 成本的范围,从而实现低于当前最小值的降低。

动机

以太坊区块的交易容量取决于交易的 gas 成本相对于区块 gas 限制。提高交易容量的一种方法是提高区块 gas 限制。不幸的是,提高区块 gas 限制也会增加状态增长的速度,除非同时将扩展状态的存储操作码(SSTORECREATE 等)的成本增加到相同的比例。增加存储操作码的成本可能会产生不利的副作用,例如改变已部署合约 gas 费用的经济假设,或者可能破坏当前合约执行中的不变量(如 EIP-20351 中所述,需要更多研究来了解增加存储操作码成本的潜在影响)。

提高区块交易容量的另一种方法是降低交易的 gas 成本。降低计算操作码的 gas 成本,同时保持存储操作码的成本不变,实际上等同于提高区块 gas 限制,并同时增加存储操作码的成本。然而,降低计算操作码的成本可能会避免增加存储操作码成本带来的不利副作用(同样,需要对该主题进行更多研究)。

目前,计算操作码的成本已经太接近最小单位 1 gas,无法实现大幅度的成本降低,而最近的基准测试2表明,需要对操作码 gas 成本进行调整,以适应优化的 EVM 实现的性能。更小的最小单位,称为“微粒 (particle)”,是 1 gas 的一小部分(或细分),将实现大幅度的成本降低。

规范

除了现有的 gas 计数器 gasUsed 之外,EVM 中还添加了一个新的 gas 计数器 particlesUsed。单位 1 gas 等于 10000 个微粒 (PARTICLES_PER_GAS)。particlesUsed 计数器仅针对以微粒定价的操作码增加(即成本低于 1 gas 的操作码)。如果增加 particlesUsed 导致超过 1 gas,则将 1 gas 添加到 gasUsed(并从 particlesUsed 中扣除)。

当前 gas 逻辑如下所示:

def vm_execute(ext, msg, code):
    # Initialize stack, memory, program counter, etc
    # 初始化堆栈、内存、程序计数器等
    compustate = Compustate(gas=msg.gas)
    codelen = len(code)

    while compustate.pc < codelen:
        opcode = code[compustate.pc]
        compustate.pc += 1

        compustate.gasUsed += opcode.gas_fee

        # out of gas error
        # gas 不足错误
        if compustate.gasUsed > compustate.gasLimit:
            return vm_exception('OUT OF GAS')

        if op == 'STOP':
            return peaceful_exit()
        elif op == 'ADD':
            stk.append(stk.pop() + stk.pop())
        elif op == 'SUB':
            stk.append(stk.pop() - stk.pop())
        elif op == 'MUL':
            stk.append(stk.pop() * stk.pop())

.....

使用微粒的新 gas 逻辑可能如下所示:

PARTICLES_PER_GAS = 10000

def vm_execute(ext, msg, code):
    # Initialize stack, memory, program counter, etc
    # 初始化堆栈、内存、程序计数器等
    compustate = Compustate(gas=msg.gas)
    codelen = len(code)

    while compustate.pc < codelen:
        opcode = code[compustate.pc]
        compustate.pc += 1

        if opcode.gas_fee:
            compustate.gasUsed += opcode.gas_fee
        elif opcode.particle_fee:
            compustate.particlesUsed += opcode.particle_fee
            if compustate.particlesUsed >= PARTICLES_PER_GAS:
                # particlesUsed will be between 1 and 2 gas (over 10000 but under 20000)
                # particlesUsed 将在 1 到 2 gas 之间(超过 10000 但低于 20000)
                compustate.gasUsed += 1
                # remainder stays in particle counter
                # 余数保留在微粒计数器中
                compustate.particlesUsed = compustate.particlesUsed % PARTICLES_PER_GAS

        # out of gas error
        # gas 不足错误
        if compustate.gasUsed > compustate.gasLimit:
            return vm_exception('OUT OF GAS')

        if op == 'STOP':
            return peaceful_exit()
        elif op == 'ADD':
            stk.append(stk.pop() + stk.pop())
        elif op == 'SUB':
            stk.append(stk.pop() - stk.pop())
        elif op == 'MUL':
            stk.append(stk.pop() * stk.pop())

.....

上面的伪代码是为了清晰起见而编写的。更高效的实现可能会将 opcode 的 gas 成本乘以 10000,并将 gasLimit 乘以 10000,从而保持单个 particlesUsed 计数器,并在执行结束时使用 ceil(particlesUsed / PARTICLES_PER_GAS) 将微粒转换回 gas。使用作为 2 的幂的 PARTICLES_PER_GAS 比率(例如 8192 或 16384)而不是 10000 可能也更有效;上面的规范是草案,预计会根据反馈进行更新。

操作码成本变更

许多计算操作码的成本将会降低,新的成本由基准分析建议。例如,DUPSWAP 的成本从 3 gas 降低到 3000 个微粒(即 0.3 gas)。ADDSUB 的成本从 3 gas 降低到 6000 个微粒。MUL 的成本从 5 gas 降低到 5000 个微粒(即 0.5 gas)。

原理

采用微粒化 gas 成本应该只是 EVM 内部的实现细节,不应改变当前围绕交易 gas 限制和区块 gas 限制的用户体验。微粒 (particles) 的概念不需要暴露给以太坊用户或大多数合约作者,而只需暴露给 EVM 实现者和关注优化 gas 使用的合约开发者。此外,只有每个执行的操作码收取 gas 的 EVM 逻辑应受此更改的影响。所有其他处理 gas 和 gas 限制的上下文,如区块头和交易格式,应不受影响。

Ewasm

“微粒 (particles)”一词最初是为 Ewasm3 引入的,以便为低成本 wasm 指令进行 gas 记账,同时保持与 EVM gas 成本的兼容性。本 EIP 建议引入微粒作为 EVM 操作码新的最小 gas 单位,与 Ewasm 无关。

向后兼容性

此更改不向后兼容,需要进行硬分叉才能激活。

测试用例

TODO

实现

TODO

参考文献

1. EIP-2035: 无状态客户端 - 重新定价 SLOAD 和 SSTORE 以支付区块证明的费用

2. https://github.com/ewasm/benchmarking

3. 术语“微粒 (particle)”的灵感来自 Ewasm gas 成本 的提案。

版权

版权及相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Casey Detrio (@cdetrio), Alex Beregszaszi (@axic), "EIP-2045: EVM 操作码的微粒化 gas 消耗 [DRAFT]," Ethereum Improvement Proposals, no. 2045, May 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2045.