该EIP提案旨在通过对访问列表(Access List)的数据足迹进行收费,以防止绕过EIP-7623设定的数据地板价。此举通过将访问列表数据计入总数据Token和地板价计算,确保了所有交易数据来源定价的一致性,有效降低了最坏情况下的区块大小约21%。
markdown
此 EIP 根据数据占用量向访问列表收费,防止规避 EIP-7623 的最低定价。通过对用户影响最小化,这有效地将最坏情况下的区块大小减少约21%。
访问列表只为存储付费,而不为其数据付费。
此外,访问列表可以通过贡献 EVM gas 来规避 EIP-7623 的最低定价,同时仍然留下不可忽略的数据占用。这使得通过以一定比例结合访问列表和 calldata 来实现最大可能的区块大小成为可能。
| Parameter | Value | Source |
|---|---|---|
ACCESS_LIST_ADDRESS_COST |
2400 |
EIP-2930 |
ACCESS_LIST_STORAGE_KEY_COST |
1900 |
EIP-2930 |
TOTAL_COST_FLOOR_PER_TOKEN |
10 |
EIP-7623 |
令 $access\_list\_nonzero\_bytes$ 和 $access\_list\_zero\_bytes$ 分别为访问列表中包含的地址(每个20字节)和存储键(每个32字节)中的非零字节和零字节的数量。
令 $tokens\_in\_access\_list = access\_list\_zero\_bytes + access\_list\_nonzero\_bytes * 4$。
访问列表的成本公式从 EIP-2930 更改为包含数据成本:
access_list_cost = (
ACCESS_LIST_ADDRESS_COST * access_list_addresses
+ ACCESS_LIST_STORAGE_KEY_COST * access_list_storage_keys
+ TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_access_list
)
EIP-7623 的最低计算方式被修改为包含访问列表的 token:
tokens_in_calldata = zero_bytes_in_calldata + nonzero_bytes_in_calldata * 4
total_data_tokens = tokens_in_calldata + tokens_in_access_list
data_floor_gas_cost = TX_BASE_COST + TOTAL_COST_FLOOR_PER_TOKEN * total_data_tokens
使用的 gas 计算变为:
tx.gasUsed = (
21000
+
max(
STANDARD_TOKEN_COST * tokens_in_calldata
+ execution_gas_used
+ isContractCreation * (32000 + INITCODE_WORD_COST * words(calldata))
+ access_list_cost,
TOTAL_COST_FLOOR_PER_TOKEN * total_data_tokens
)
)
任何 gas 限制低于 $21000 + TOTAL\_COST\_FLOOR\_PER\_TOKEN * total\_data\_tokens$ 或低于其 $intrinsic\_gas\_cost$ 的交易都将被视为无效。
访问列表数据总是按最低费率收费(加入到 $access\_list\_cost$ 中),并且访问列表 token 被包含在最低计算中。这确保了:
这是一个向后不兼容的 gas 重新定价,需要进行计划的网络升级。
需要更新钱包和节点中的 gas 估算。正常使用模式基本不受影响。
def calculate_access_list_tokens(access_list: Tuple[Access, ...]) -> Uint:
"""计算访问列表地址和存储键中的数据 token。"""
zero_bytes = Uint(0)
nonzero_bytes = Uint(0)
for access in access_list:
for byte in access.account:
if byte == 0:
zero_bytes += Uint(1)
else:
nonzero_bytes += Uint(1)
for slot in access.slots:
for byte in slot:
if byte == 0:
zero_bytes += Uint(1)
else:
nonzero_bytes += Uint(1)
return zero_bytes + nonzero_bytes * Uint(4)
def calculate_intrinsic_cost(tx: Transaction) -> Tuple[Uint, Uint]:
"""
计算固有 gas 成本和最低 gas 成本。
返回 (intrinsic_gas, floor_gas)。
"""
# Calldata token
calldata_zero_bytes = Uint(0)
for byte in tx.data:
if byte == 0:
calldata_zero_bytes += Uint(1)
tokens_in_calldata = (
calldata_zero_bytes + (ulen(tx.data) - calldata_zero_bytes) * Uint(4)
)
# 访问列表 token 和成本
tokens_in_access_list = Uint(0)
access_list_cost = Uint(0)
if has_access_list(tx):
tokens_in_access_list = calculate_access_list_tokens(tx.access_list)
for access in tx.access_list:
access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
access_list_cost += ulen(access.slots) * TX_ACCESS_LIST_STORAGE_KEY_COST
# EIP-7981: 始终收取数据成本
access_list_cost += tokens_in_access_list * TOTAL_COST_FLOOR_PER_TOKEN
# EIP-7981: 最低成本包含所有数据 token
total_data_tokens = tokens_in_calldata + tokens_in_access_list
floor_gas = TX_BASE_COST + total_data_tokens * TOTAL_COST_FLOOR_PER_TOKEN
# 固有 gas
calldata_cost = tokens_in_calldata * STANDARD_TOKEN_COST
create_cost = TX_CREATE_COST + init_code_cost(tx.data) if is_create(tx) else Uint(0)
intrinsic_gas = TX_BASE_COST + calldata_cost + create_cost + access_list_cost
return intrinsic_gas, floor_gas
此 EIP 堵塞了一个允许规避 EIP-7623 最低定价的漏洞。如果没有此修复,攻击者可以通过将访问列表与 calldata 结合起来实现超出预期的更大区块。现在所有交易数据源都一致地参与最低计算。
通过 CC0 放弃版权及相关权利。
- 原文链接: github.com/nerolation/EI...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!