EIP-4844改进提议:分片Blob事务

Posted by LB on Mon, Feb 27, 2023

SSI

EIP-4844 分片Blob事务以简单、向前兼容的方式扩展以太坊的数据可用性。

一、摘要

为“携带blob的交易”引入一种新的交易格式,其中包含大量 EVM 执行无法访问的数据,但可以访问其承诺。该格式旨在与将在全分片中使用的格式完全兼容。

二、动机

Rollups 在短期和中期,甚至可能在长期内,是以太坊唯一的去信任扩展解决方案。几个月来,L1 的交易费用一直非常高,并且迫切需要做任何必要的事情来帮助促进整个生态系统转向汇总。 Rollups 显着降低了许多以太坊用户的费用:Optimism 和 Arbitrum 经常提供比以太坊基础层本身低 3-8 倍的费用,而 ZK rollups 具有更好的数据压缩并且可以避免包含签名,费用比基础层低 40-100 倍。

然而,即使这些费用对许多用户来说也太贵了。长期解决 rollups 自身长期不足的长期解决方案一直是数据分片,这将为 rollups 可以使用的链增加每块专用数据空间约 16 MB。然而,数据分片仍然需要相当长的时间才能完成实施和部署。

这个 EIP 提供了一个权宜之计解决方案,通过实现将在分片中使用的交易格式,而不是实际分片这些交易。相反,这种交易格式的数据只是信标链的一部分并由所有共识节点完全下载(但可以在相对较短的延迟后删除)。与完整数据分片相比,这个 EIP 减少了可以包含的交易数量上限,对应于每个区块约 0.25 MB 的目标和约 0.5 MB 的限制。

三、Specification 规范

3.1 Parameters 参数

Constant - 常量Value
BLOB_TX_TYPEBytes1(0x05)
FIELD_ELEMENTS_PER_BLOB4096
BLS_MODULUS52435875175126190479447740508185965837690552500527637822603658699938581184513
BLOB_COMMITMENT_VERSION_KZGBytes1(0x01)
POINT_EVALUATION_PRECOMPILE_ADDRESSBytes20(0x14)
POINT_EVALUATION_PRECOMPILE_GAS50000
MAX_DATA_GAS_PER_BLOCK2**19
TARGET_DATA_GAS_PER_BLOCK2**18
MIN_DATA_GASPRICE1
DATA_GASPRICE_UPDATE_FRACTION2225652
MAX_VERSIONED_HASHES_LIST_SIZE2**24
MAX_CALLDATA_SIZE2**24
MAX_ACCESS_LIST_SIZE2**24
MAX_ACCESS_LIST_STORAGE_KEYS2**24
MAX_TX_WRAP_KZG_COMMITMENTS2**12
LIMIT_BLOBS_PER_TX2**12
DATA_GAS_PER_BLOB2**17
HASH_OPCODE_BYTEBytes1(0x49)
HASH_OPCODE_GAS3

3.2 Type aliases 类型别名

TypeBase type 底座型Additional checks 额外检查
BLSFieldElementuint256x < BLS_MODULUS
BlobVector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]
VersionedHashBytes32
KZGCommitmentBytes48Same as BLS standard “is valid pubkey” check but also allows 0x00..00 for point-at-infinity 与 BLS 标准“是有效公钥”检查相同,但也允许 0x00..00 用于无穷远点
KZGProofBytes48Same as for KZGCommitment与 KZGCommitment 相同

3.3 Cryptographic Helpers 加密助手

在整个提案中,我们使用相应的共识 4844 规范中定义的加密方法和类。具体来说,我们使用来自 polynomial-commitments.md 的以下方法:

3.4 Helpers

1def kzg_to_versioned_hash(kzg: KZGCommitment) -> VersionedHash:
2    return BLOB_COMMITMENT_VERSION_KZG + sha256(kzg)[1:]

使用泰勒展开逼近 factor * e ** (numerator / denominator)

1def fake_exponential(factor: int, numerator: int, denominator: int) -> int:
2    i = 1
3    output = 0
4    numerator_accum = factor * denominator
5    while numerator_accum > 0:
6        output += numerator_accum
7        numerator_accum = (numerator_accum * numerator) // (denominator * i)
8        i += 1
9    return output // denominator

3.5 New transaction type 新的交易类型

我们引入了一种新的 EIP-2718 交易类型,格式为单字节 BLOB_TX_TYPE后跟包含交易内容的 SignedBlobTransaction容器的 SSZ 编码:

 1class SignedBlobTransaction(Container):
 2    message: BlobTransaction
 3    signature: ECDSASignature
 4
 5class BlobTransaction(Container):
 6    chain_id: uint256
 7    nonce: uint64
 8    max_priority_fee_per_gas: uint256
 9    max_fee_per_gas: uint256
10    gas: uint64
11    to: Union[None, Address] # Address = Bytes20
12    value: uint256
13    data: ByteList[MAX_CALLDATA_SIZE]
14    access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE]
15    max_fee_per_data_gas: uint256
16    blob_versioned_hashes: List[VersionedHash, MAX_VERSIONED_HASHES_LIST_SIZE]
17
18class AccessTuple(Container):
19    address: Address # Bytes20
20    storage_keys: List[Hash, MAX_ACCESS_LIST_STORAGE_KEYS]
21
22class ECDSASignature(Container):
23    y_parity: boolean
24    r: uint256
25    s: uint256

max_priority_fee_per_gas和 max_fee_per_gas字段遵循 EIP-1559 语义, access_list与 EIP-2930相同。

EIP-2718使用“包装数据”进行扩展,类型化的交易可以根据上下文以两种形式编码:

  • Network (default): TransactionType || TransactionNetworkPayload或 LegacyTransaction
  • Minimal (as in execution payload):TransactionType || TransactionPayload或 LegacyTransaction

执行负载/块使用交易的最小编码。在交易池和本地交易日志中使用网络编码。 对于以前类型的交易,网络编码没有什么不同,即 TransactionNetworkPayload == TransactionPayloadTransactionNetworkPayload用附加数据包装 TransactionPayload:应该在签名验证之前或之后直接验证此包装数据。

当 blob 事务通过网络传递时(请参阅下面的网络部分),事务的 TransactionNetworkPayload  版本还包括 blobs和 kzgs(承诺列表)。执行层在签名验证后针对部 TransactionPayload验证包装器有效性:

  • blob_versioned_hashes中的所有哈希必须以字节 BLOB_COMMITMENT_VERSION_KZG开头
  • 一个有效块中最多可能有 MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB总 blob 承诺。
  • 有等量的版本化哈希、kzg 承诺和 blob。
  • KZG 承诺哈希到版本哈希,即 kzg_to_versioned_hash(kzg[i]) == versioned_hash[i]
  • KZG 承诺与 blob 内容相匹配。 (注意:这可以通过附加数据进行优化,使用从承诺和 blob 数据派生的两个点进行随机评估的证明)

签名被验证并且 tx.origin被计算如下:

1def unsigned_tx_hash(tx: SignedBlobTransaction) -> Bytes32:
2    # The pre-image is prefixed with the transaction-type to avoid hash collisions with other tx hashers and types
3    return keccak256(BLOB_TX_TYPE + ssz.serialize(tx.message))
4
5def get_origin(tx: SignedBlobTransaction) -> Address:
6    sig = tx.signature
7    # v = int(y_parity) + 27, same as EIP-1559
8    return ecrecover(unsigned_tx_hash(tx), int(sig.y_parity)+27, sig.r, sig.s)

已签名的 blob 交易的哈希值应计算为:

1def signed_tx_hash(tx: SignedBlobTransaction) -> Bytes32:
2    return keccak256(BLOB_TX_TYPE + ssz.serialize(tx))

3.6 Header extension 头扩展

当前标头编码使用新的 256 位无符号整数字段 excess_data_gas进行扩展。这是自此 EIP 激活以来链上消耗的过量数据气体的运行总量。如果数据气体总量低于目标, excess_data_gas上限为零。

因此,生成的标头 RLP 编码为:

 1rlp([
 2    parent_hash,
 3    0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347, # ommers hash
 4    coinbase,
 5    state_root,
 6    txs_root,
 7    receipts_root,
 8    logs_bloom,
 9    0, # difficulty
10    number,
11    gas_limit,
12    gas_used,
13    timestamp,
14    extradata,
15    prev_randao,
16    0x0000000000000000, # nonce
17    base_fee_per_gas,
18    withdrawals_root,
19    excess_data_gas
20])

excess_data_gas 的值可以使用块中的父标头和 blob 数来计算。

1def calc_excess_data_gas(parent: Header, new_blobs: int) -> int:
2    consumed_data_gas = new_blobs * DATA_GAS_PER_BLOB
3    if parent.excess_data_gas + consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK:
4        return 0
5    else:
6        return parent.excess_data_gas + consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK

对于第一个分叉后区块, parent.excess_data_gas被评估为 0

3.7 Beacon chain validation 信标链验证

在共识层上,blob 现在在信标块主体中被引用,但未完全编码。不是将全部内容嵌入正文,而是将 blob 的内容单独传播,作为“sidecar”。

这种“边车”设计通过黑盒 is_data_available()为进一步增加的数据提供前向兼容性:完全分片 is_data_available()可以用数据可用性采样 (DAS) 代替,从而避免所有 blob 被网络上的所有信标节点下载网络。

请注意,共识层的任务是持久化数据可用性的 blob,而执行层则不是。 ethereum/consensus-specs存储库定义了此 EIP 中涉及的以下信标节点更改:

  • Beacon chain信标链:处理更新的信标块并确保 blob 可用。
  • P2P 网络:Goosip和同步更新的信标块类型和新的 blob 边车。
  • Honest validator 诚实验证器:使用 blob 生成信标块,发布 blob sidecars。

3.8 Opcode to get versioned hashes 获取版本哈希的操作码

我们添加了一个操作码 DATAHASH(字节值为 HASH_OPCODE_BYTE),它从栈顶读取 index作为大端 uint256,如果是 tx.message.blob_versioned_hashes[index]则用 index < len(tx.message.blob_versioned_hashes)替换它在栈上,并且否则使用归零的 bytes32值。操作码的 gas 成本为 HASH_OPCODE_GAS

3.9 Point evaluation precompile 点评估预编译

在 POINT_EVALUATION_PRECOMPILE_ADDRESS 添加预编译,用于验证 KZG 证明,该证明声称blob(由承诺表示)在给定点计算为给定值。

预编译花费 POINT_EVALUATION_PRECOMPILE_GAS并执行以下逻辑:

 1def point_evaluation_precompile(input: Bytes) -> Bytes:
 2    """
 3    Verify p(z) = y given commitment that corresponds to the polynomial p(x) and a KZG proof.
 4    Also verify that the provided commitment matches the provided versioned_hash.
 5    """
 6    # The data is encoded as follows: versioned_hash | z | y | commitment | proof |
 7    versioned_hash = input[:32]
 8    z = input[32:64]
 9    y = input[64:96]
10    commitment = input[96:144]
11    kzg_proof = input[144:192]
12
13    # Verify commitment matches versioned_hash
14    assert kzg_to_versioned_hash(commitment) == versioned_hash
15
16    # Verify KZG proof
17    assert verify_kzg_proof(commitment, z, y, kzg_proof)
18
19    # Return FIELD_ELEMENTS_PER_BLOB and BLS_MODULUS as padded 32 byte big endian values
20    return Bytes(U256(FIELD_ELEMENTS_PER_BLOB).to_be_bytes32() + U256(BLS_MODULUS).to_be_bytes32())

预编译必须拒绝非规范的字段元素(即提供的字段元素必须严格小于 BLS_MODULUS)。

3.10 Gas accounting

我们将数据气体作为一种新型气体引入。它独立于普通气体并遵循自己的目标规则,类似于 EIP-1559。我们使用 excess_data_gas标头字段来存储计算数据 gas 价格所需的持久数据。目前,只有 blob 以数据 gas 计价。

 1def calc_data_fee(tx: SignedBlobTransaction, parent: Header) -> int:
 2    return get_total_data_gas(tx) * get_data_gasprice(header)
 3
 4def get_total_data_gas(tx: SignedBlobTransaction) -> int:
 5    return DATA_GAS_PER_BLOB * len(tx.message.blob_versioned_hashes)
 6
 7def get_data_gasprice(header: Header) -> int:
 8    return fake_exponential(
 9        MIN_DATA_GASPRICE,
10        header.excess_data_gas,
11        DATA_GASPRICE_UPDATE_FRACTION
12    )

区块有效性条件被修改为包括数据气体检查:

 1def validate_block(block: Block) -> None:
 2    ...
 3
 4    for tx in block.transactions:
 5        ...
 6
 7        # the signer must be able to afford the transaction
 8        assert signer(tx).balance >= tx.message.gas * tx.message.max_fee_per_gas + get_total_data_gas(tx) * tx.message.max_fee_per_data_gas
 9
10        # ensure that the user was willing to at least pay the current data gasprice
11        assert tx.message.max_fee_per_data_gas >= get_data_gasprice(parent(block).header)

通过 data_fee计算的实际 calc_data_fee在交易执行前从发送方余额中扣除并销毁,并且在交易失败的情况下不予退还。

3.11 Networking 网络

节点不得自动向其对等节点广播 blob 事务。相反,这些交易仅使用 NewPooledTransactionHashes消息公布,然后可以通过 GetPooledTransactions手动请求。

交易在执行层网络上显示为 TransactionType || TransactionNetworkPayload,有效负载是一个 SSZ 编码的容器:

1class BlobTransactionNetworkWrapper(Container):
2    tx: SignedBlobTransaction
3    # KZGCommitment = Bytes48
4    blob_kzgs: List[KZGCommitment, MAX_TX_WRAP_KZG_COMMITMENTS]
5    # BLSFieldElement = uint256
6    blobs: List[Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB], LIMIT_BLOBS_PER_TX]
7    # KZGProof = Bytes48
8    kzg_aggregated_proof: KZGProof

我们对 BlobTransactionNetworkWrapper对象进行网络级验证,如下所示:

 1def validate_blob_transaction_wrapper(wrapper: BlobTransactionNetworkWrapper):
 2    versioned_hashes = wrapper.tx.message.blob_versioned_hashes
 3    commitments = wrapper.blob_kzgs
 4    blobs = wrapper.blobs
 5    # note: assert blobs are not malformatted
 6    assert len(versioned_hashes) == len(commitments) == len(blobs)
 7
 8    # Verify that commitments match the blobs by checking the KZG proof
 9    assert verify_aggregate_kzg_proof(blobs, commitments, wrapper.kzg_aggregated_proof)
10
11    # Now that all commitments have been verified, check that versioned_hashes matches the commitments
12    for versioned_hash, commitment in zip(versioned_hashes, commitments):
13        assert versioned_hash == kzg_to_versioned_hash(commitment)

四、基本原理

4.1 On the path to sharding 在分片的路上

该 EIP 引入了 blob 事务,其格式与最终分片规范中预期存在的格式相同。通过允许它们最初扩展到每个槽 0.25 MB,这为汇总提供了一个临时但显着的扩展缓解,一个单独的费用市场允许费用非常低,同时该系统的使用受到限制。

rollup 缩放权宜之计的核心目标是提供临时的缩放缓解,而不会给 rollup 施加额外的开发负担以利用这种缓解。今天,汇总使用调用数据。将来,rollup 将别无选择,只能使用分片数据(也称为“blob”),因为分片数据会便宜得多。因此,rollups 不可避免地要对其处理数据的方式进行一次大升级。但我们能做的是确保 rollups 只需要升级一次。这立即意味着有两种可能的权宜之计:(i)降低现有调用数据的 gas 成本,以及(ii)提出将用于分片数据但尚未实际分片的格式。之前的EIP都是第(i)类的解决方案;该 EIP 是类别 (ii) 的解决方案。

设计这个 EIP 的主要权衡是现在实施更多与以后必须实施更多:我们是在实现完全分片的过程中实施 25% 的工作,还是 50%,还是 75%?

该 EIP 中已经完成的工作包括:

  • 一种新的交易类型,其格式完全相同,需要存在于“全分片”中
  • 全分片所需的所有执行层逻辑
  • 全分片所需的所有执行/共识交叉验证逻辑
  • BeaconBlock验证和数据可用性采样 blob 之间的层分离
  • 完全分片所需的大部分 BeaconBlock逻辑
  • blob 的自我调整的独立 gasprice

要实现完全分片,还有待完成的工作包括:

  • 共识层 blob_kzgs的低度扩展,允许二维采样
  • 数据可用性采样的实际实现
  • PBS(提议者/构建者分离),以避免要求单个验证者在一个时隙中处理 32 MB 的数据
  • 每个验证器的保管证明或类似的协议内要求,以验证每个块中分片数据的特定部分

该 EIP 还为长期协议清理奠定了基础:

  • 新增SSZ交易类型,开创了所有新交易类型都应该是SSZ的先例
  • 它定义了 TransactionNetworkPayload来分隔交易类型的网络和块编码
  • 它的(更清洁的)gas 价格更新规则可以应用于主要基本费用

4.2 How rollups would function

rollups 不是将 rollup 块数据放在交易调用数据中,而是希望 rollup 块提交者将数据放入 blob 中。这保证了可用性(这是 rollup 所需要的),但比 calldata 便宜得多。汇总需要数据一次可用,足够长以确保诚实的参与者可以构建汇总状态,但不是永远可用。

Optimistic rollups 只需要在提交欺诈证明时实际提供基础数据。欺诈证明可以以更小的步骤验证转换,通过 calldata 一次最多加载 blob 的几个值。对于每个值,它将提供一个 KZG 证明,并使用点评估预编译来根据之前提交的版本化哈希验证该值,然后像今天一样对该数据执行欺诈证明验证。

ZK rollups将为其交易或状态增量数据提供两个承诺:blob 中的 kzg 和使用 ZK 汇总内部使用的任何证明系统的一些承诺。他们将使用等价协议的承诺证明,使用点评估预编译来证明 kzg(协议确保指向可用数据)和 ZK rollup 自己的承诺引用相同的数据。

4.3 Versioned hashes & precompile return data  版本化哈希和预编译返回数据

我们使用版本化哈希(而不是 kzgs)作为对执行层中 blob 的引用,以确保与未来更改的向前兼容性。例如,如果我们出于量子安全原因需要切换到 Merkle 树 + STARKs,那么我们将添加一个新版本,允许点评估预编译使用新格式。 Rollup 不必对其工作方式进行任何 EVM 级别的更改;排序者只需要在适当的时候切换到使用新的交易类型。

但是,点评估发生在有限域内,并且只有在场模已知的情况下才能明确定义。智能合约可以包含一个将承诺版本映射到模数的表,但这不允许智能合约考虑未来对未知模数的升级。通过允许访问 EVM 内部的模数,可以构建智能合约,以便它可以使用未来的承诺和证明,而无需升级。

为了不添加另一个预编译,我们直接从点评估预编译返回模数和多项式次数。然后它可以被调用者使用。它也是“免费”的,因为调用者可以忽略这部分返回值而不会产生额外成本——在可预见的未来保持可升级的系统现在可能会使用这条路线。

4.4 Data gasprice update rule 数据 gasprice 更新规则

数据 gasprice 更新规则旨在近似公式 data_gasprice = MIN_DATA_GASPRICE * e**(excess_data_gas / DATA_GASPRICE_UPDATE_FRACTION) ,其中 excess_data_gas是该链相对于“目标”数量(每个块 TARGET_DATA_GAS_PER_BLOCK)消耗的数据 gas 总量的“额外”量。与EIP-1559 一样,它是一个自我修正的公式:随着超额增加, data_gasprice呈指数增长,减少使用并最终迫使超额回落。

逐块行为大致如下。如果 N块消耗 X数据gas,那么在 N+1块中 excess_data_gas增加 X -TARGET_DATA_GAS_PER_BLOCK ,所以 data_gasprice块的 N+1增加 e**((X - TARGET_DATA_GAS_PER_BLOCK) / DATA_GASPRICE_UPDATE_FRACTION) 。因此,它与现有的 EIP-1559 具有相似的效果,但在某种意义上更“稳定”,因为无论其分布如何,它都以相同的方式响应相同的总使用量。

参数 DATA_GASPRICE_UPDATE_FRACTION控制 blob gas 价格的最大变化率。选择它的目标是每个块 e(TARGET_DATA_GAS_PER_BLOCK / DATA_GASPRICE_UPDATE_FRACTION) ≈ 1.125的最大更改率。

4.5 吞吐量

选择 TARGET_DATA_GAS_PER_BLOCK和 MAX_DATA_GAS_PER_BLOCK的值对应于每个块 2 个 blob (0.25 MB) 和最多 4 个 blob (0.5 MB) 的目标。这些小的初始限制旨在最大程度地减少此 EIP 对网络造成的压力,并且随着网络在更大的块下展示可靠性,预计在未来的升级中会增加。

五、Backwards Compatibility    向后兼容

5.1 Blob non-accessibility    Blob 不可访问

该 EIP 引入了一种交易类型,它具有不同的内存池版本 ( BlobTransactionNetworkWrapper ) 和执行负载版本 ( SignedBlobTransaction ),两者之间只能进行单向转换。 blob 在 BlobTransactionNetworkWrapper 中而不是在 SignedBlobTransaction 中;相反,他们进入了 BeaconBlockBody 。这意味着现在有一部分交易无法从 web3 API 访问。

六、Mempool issues    内存池问题

Blob 交易在 mempool 层具有较大的数据大小,这会带来 mempool DoS 风险,尽管这并不是前所未有的风险,因为这也适用于具有大量 calldata 的交易。

通过只广播 blob 交易的公告,接收节点将可以控制接收哪些交易和接收多少交易,从而允许它们将吞吐量限制在可接受的水平。 EIP-5793 将通过扩展 NewPooledTransactionHashes公告消息以包括交易类型和大小来进一步细粒度地控制节点。

此外,我们建议在 mempool 交易替换规则中包含 1.1 倍的数据 gasprice 涨幅要求。

七、Test Cases    测试用例

待定

八、Security Considerations    安全考虑

该 EIP 最多将每个信标块的存储要求增加约 0.5 MB。这比今天区块的理论最大大小大 4 倍(30M gas / 每个调用数据字节 16 gas = 1.875M 字节),因此它不会大大增加最坏情况下的带宽。合并后,块时间预计是静态的,而不是不可预测的泊松分布,从而为大块的传播提供了保证的时间段。

这个 EIP 的持续负载远低于降低调用数据成本的替代方案,即使调用数据是有限的,因为没有现有的软件可以无限期地存储 blob,并且不期望它们需要存储多长时间执行负载。这使得更容易实施一项政策,即这些斑点应该在例如之后被删除。 30-60 天,与建议的(但尚未实施)执行负载历史的一年轮换时间相比,延迟要短得多。

九、版权所有

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

十、Citation 引用

Vitalik Buterin ( @vbuterin)、Dankrad Feist ( @dankrad)、Diederik Loerakker ( @protolambda)、George Kadianakis ( @asn-d6)、Matt Garnett ( @lightclient)、Mofi Taiwo ( @Inphi)、Ansgar Dietrichs ( @adietrichs),“EIP-4844:分片 Blob 交易 [草案],”以太坊改进提案,第 1 期。 4844,2022 年 2 月。[在线连载]。可用:https://eips.ethereum.org/EIPS/eip-4844。