Capella 是一个共识层的升级,主要聚焦于验证者的提取功能。文章详细介绍了验证者提取的自动化过程、新的自定义类型、容器结构以及状态转换函数,特别是对于历史汇总的处理和提取的操作。这些新特性旨在优化以太坊的验证者管理及其提取过程。
<!-- mdformat-toc start --slug=github --no-anchors --maxlevel=6 --minlevel=2 -->
<!-- mdformat-toc end -->
Capella 是一个共识层升级,包含与验证者提款相关的多个功能,包括:
可提款
验证者。最大有效余额
的验证者进行部分提款。BLS_WITHDRAWAL_PREFIX
更改为 ETH1_ADDRESS_WITHDRAWAL_PREFIX
版本化提款凭证,以便为验证者启用提款。另一个新功能是独立的状态和区块历史累加器,替代了原来的单一历史根。借助这些累加器,可以验证导致特定状态的整个区块历史,而无需除了状态和区块以外的任何附加信息。
我们定义以下 Python 自定义类型以提高类型提示和可读性:
名称 | SSZ 等价物 | 描述 |
---|---|---|
WithdrawalIndex |
uint64 |
Withdrawal 的索引 |
名称 | 值 |
---|---|
DOMAIN_BLS_TO_EXECUTION_CHANGE |
DomainType('0x0A000000') |
名称 | 值 |
---|---|
MAX_BLS_TO_EXECUTION_CHANGES |
2**4 (= 16) |
名称 | 值 | 描述 |
---|---|---|
MAX_WITHDRAWALS_PER_PAYLOAD |
uint64(2**4) (= 16) |
每个负载允许的最大提款数量 |
名称 | 值 |
---|---|
MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP |
16384 (= 2**14 ) |
Withdrawal
class Withdrawal(Container):
index: WithdrawalIndex
validator_index: ValidatorIndex
address: ExecutionAddress
amount: Gwei
BLSToExecutionChange
class BLSToExecutionChange(Container):
validator_index: ValidatorIndex
from_bls_pubkey: BLSPubkey
to_execution_address: ExecutionAddress
SignedBLSToExecutionChange
class SignedBLSToExecutionChange(Container):
message: BLSToExecutionChange
signature: BLSSignature
HistoricalSummary
class HistoricalSummary(Container):
"""
`HistoricalSummary` 匹配 phase0 `HistoricalBatch` 的组成部分
使两者相互兼容 hash_tree_root。
"""
block_summary_root: Root
state_summary_root: Root
ExecutionPayload
class ExecutionPayload(Container):
# 执行区块头字段
parent_hash: Hash32
fee_recipient: ExecutionAddress # 黄色论文中的 'beneficiary'
state_root: Bytes32
receipts_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
prev_randao: Bytes32 # 黄色论文中的 'difficulty'
block_number: uint64 # 黄色论文中的 'number'
gas_limit: uint64
gas_used: uint64
timestamp: uint64
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
base_fee_per_gas: uint256
# 额外负载字段
block_hash: Hash32 # 执行区块的哈希
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] # [Capella 中的新]
ExecutionPayloadHeader
class ExecutionPayloadHeader(Container):
# 执行区块头字段
parent_hash: Hash32
fee_recipient: ExecutionAddress
state_root: Bytes32
receipts_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
prev_randao: Bytes32
block_number: uint64
gas_limit: uint64
gas_used: uint64
timestamp: uint64
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
base_fee_per_gas: uint256
# 额外负载字段
block_hash: Hash32 # 执行区块的哈希
transactions_root: Root
withdrawals_root: Root # [Capella 中的新]
BeaconBlockBody
class BeaconBlockBody(Container):
randao_reveal: BLSSignature
eth1_data: Eth1Data # Eth1 数据投票
graffiti: Bytes32 # 任意数据
# 操作
proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS]
attestations: List[Attestation, MAX_ATTESTATIONS]
deposits: List[Deposit, MAX_DEPOSITS]
voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
sync_aggregate: SyncAggregate
# 执行
execution_payload: ExecutionPayload
# Capella 操作
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [Capella 中的新]
BeaconState
class BeaconState(Container):
# 版本控制
genesis_time: uint64
genesis_validators_root: Root
slot: Slot
fork: Fork
# 历史
latest_block_header: BeaconBlockHeader
block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # 在 Capella 中被冻结,替换为 historical_summaries
# Eth1
eth1_data: Eth1Data
eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH]
eth1_deposit_index: uint64
# 注册表
validators: List[Validator, VALIDATOR_REGISTRY_LIMIT]
balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT]
# 随机性
randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR]
# 处罚
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # 每个周期的处罚有效余额和
# 参与
previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT]
current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT]
# 最终性
justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # 针对每个最近证明周期设置的位
previous_justified_checkpoint: Checkpoint
current_justified_checkpoint: Checkpoint
finalized_checkpoint: Checkpoint
# 不活跃性
inactivity_scores: List[uint64, VALIDATOR_REGISTRY_LIMIT]
# 同步
current_sync_committee: SyncCommittee
next_sync_committee: SyncCommittee
# 执行
latest_execution_payload_header: ExecutionPayloadHeader # [在 Capella 中修改]
# 提款
next_withdrawal_index: WithdrawalIndex # [在 Capella 中的新]
next_withdrawal_validator_index: ValidatorIndex # [在 Capella 中的新]
# 从 Capella 及以后的深度历史
historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] # [在 Capella 中新]
has_eth1_withdrawal_credential
def has_eth1_withdrawal_credential(validator: Validator) -> bool:
"""
检查 ``validator`` 是否具有以 0x01 开头的 "eth1" 提款凭证。
"""
return validator.withdrawal_credentials[:1] == ETH1_ADDRESS_WITHDRAWAL_PREFIX
is_fully_withdrawable_validator
def is_fully_withdrawable_validator(validator: Validator, balance: Gwei, epoch: Epoch) -> bool:
"""
检查 ``validator`` 是否可以完全提款。
"""
return (
has_eth1_withdrawal_credential(validator)
and validator.withdrawable_epoch <= epoch
and balance > 0
)
is_partially_withdrawable_validator
def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> bool:
"""
检查 ``validator`` 是否可以部分提款。
"""
has_max_effective_balance = validator.effective_balance == MAX_EFFECTIVE_BALANCE
has_excess_balance = balance > MAX_EFFECTIVE_BALANCE
return has_eth1_withdrawal_credential(validator) and has_max_effective_balance and has_excess_balance
注意: 在 Capella 中,函数 process_historical_summaries_update
替代了 process_historical_roots_update
。
def process_epoch(state: BeaconState) -> None:
process_justification_and_finalization(state)
process_inactivity_updates(state)
process_rewards_and_penalties(state)
process_registry_updates(state)
process_slashings(state)
process_eth1_data_reset(state)
process_effective_balance_updates(state)
process_slashings_reset(state)
process_randao_mixes_reset(state)
process_historical_summaries_update(state) # [在 Capella 中修改]
process_participation_flag_updates(state)
process_sync_committee_updates(state)
def process_historical_summaries_update(state: BeaconState) -> None:
# 设置历史区块根累加器。
next_epoch = Epoch(get_current_epoch(state) + 1)
if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
historical_summary = HistoricalSummary(
block_summary_root=hash_tree_root(state.block_roots),
state_summary_root=hash_tree_root(state.state_roots),
)
state.historical_summaries.append(historical_summary)
def process_block(state: BeaconState, block: BeaconBlock) -> None:
process_block_header(state, block)
# [在 Capella 中修改] 删除了 Capella 中的 `is_execution_enabled` 检查
process_withdrawals(state, block.body.execution_payload) # [Capella 中的新]
process_execution_payload(state, block.body, EXECUTION_ENGINE) # [在 Capella 中修改]
process_randao(state, block.body)
process_eth1_data(state, block.body)
process_operations(state, block.body) # [在 Capella 中修改]
process_sync_aggregate(state, block.body.sync_aggregate)
get_expected_withdrawals
def get_expected_withdrawals(state: BeaconState) -> Sequence[Withdrawal]:
epoch = get_current_epoch(state)
withdrawal_index = state.next_withdrawal_index
validator_index = state.next_withdrawal_validator_index
withdrawals: List[Withdrawal] = []
bound = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP)
for _ in range(bound):
validator = state.validators[validator_index]
balance = state.balances[validator_index]
if is_fully_withdrawable_validator(validator, balance, epoch):
withdrawals.append(Withdrawal(
index=withdrawal_index,
validator_index=validator_index,
address=ExecutionAddress(validator.withdrawal_credentials[12:]),
amount=balance,
))
withdrawal_index += WithdrawalIndex(1)
elif is_partially_withdrawable_validator(validator, balance):
withdrawals.append(Withdrawal(
index=withdrawal_index,
validator_index=validator_index,
address=ExecutionAddress(validator.withdrawal_credentials[12:]),
amount=balance - MAX_EFFECTIVE_BALANCE,
))
withdrawal_index += WithdrawalIndex(1)
if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
break
validator_index = ValidatorIndex((validator_index + 1) % len(state.validators))
return withdrawals
process_withdrawals
def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
expected_withdrawals = get_expected_withdrawals(state)
assert payload.withdrawals == expected_withdrawals
for withdrawal in expected_withdrawals:
decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
# 如果此区块包含提款,则更新下一个提款索引
if len(expected_withdrawals) != 0:
latest_withdrawal = expected_withdrawals[-1]
state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1)
# 更新下一个验证者索引以开始下一个提款浪潮
if len(expected_withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
# 下一个浪潮在最新提款的验证者索引后面开始
next_validator_index = ValidatorIndex((expected_withdrawals[-1].validator_index + 1) % len(state.validators))
state.next_withdrawal_validator_index = next_validator_index
else:
# 如果没有完整的提款集,则通过浪潮的最大长度提前进行浪潮
next_index = state.next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
next_validator_index = ValidatorIndex(next_index % len(state.validators))
state.next_withdrawal_validator_index = next_validator_index
process_execution_payload
注意: 函数 process_execution_payload
被修改为使用新的 ExecutionPayloadHeader
类型,并删除了 is_merge_transition_complete
检查。
def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None:
payload = body.execution_payload
# [在 Capella 中修改] 删除了 Capella 中的 `is_merge_transition_complete` 检查
# 验证父哈希与之前的执行负载头的一致性
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
# 验证 prev_randao
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
# 验证时间戳
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
# 验证执行负载是否有效
assert execution_engine.verify_and_notify_new_payload(NewPayloadRequest(execution_payload=payload))
# 缓存执行负载头
state.latest_execution_payload_header = ExecutionPayloadHeader(
parent_hash=payload.parent_hash,
fee_recipient=payload.fee_recipient,
state_root=payload.state_root,
receipts_root=payload.receipts_root,
logs_bloom=payload.logs_bloom,
prev_randao=payload.prev_randao,
block_number=payload.block_number,
gas_limit=payload.gas_limit,
gas_used=payload.gas_used,
timestamp=payload.timestamp,
extra_data=payload.extra_data,
base_fee_per_gas=payload.base_fee_per_gas,
block_hash=payload.block_hash,
transactions_root=hash_tree_root(payload.transactions),
withdrawals_root=hash_tree_root(payload.withdrawals), # [Capella 中的新]
)
process_operations
注意: 函数 process_operations
被修改为处理区块中包含的 BLSToExecutionChange
操作。
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
# 验证未处理的存款是否处理到最大存款数量
assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)
def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
for operation in operations:
fn(state, operation)
for_ops(body.proposer_slashings, process_proposer_slashing)
for_ops(body.attester_slashings, process_attester_slashing)
for_ops(body.attestations, process_attestation)
for_ops(body.deposits, process_deposit)
for_ops(body.voluntary_exits, process_voluntary_exit)
for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) # [Capella 中的新]
process_bls_to_execution_change
def process_bls_to_execution_change(state: BeaconState,
signed_address_change: SignedBLSToExecutionChange) -> None:
address_change = signed_address_change.message
assert address_change.validator_index < len(state.validators)
validator = state.validators[address_change.validator_index]
assert validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX
assert validator.withdrawal_credentials[1:] == hash(address_change.from_bls_pubkey)[1:]
# 跨分叉的域,因为地址更改在跨分叉期间有效
domain = compute_domain(DOMAIN_BLS_TO_EXECUTION_CHANGE, genesis_validators_root=state.genesis_validators_root)
signing_root = compute_signing_root(address_change, domain)
assert bls.Verify(address_change.from_bls_pubkey, signing_root, signed_address_change.signature)
validator.withdrawal_credentials = (
ETH1_ADDRESS_WITHDRAWAL_PREFIX
+ b'\x00' * 11
+ address_change.to_execution_address
)
- 原文链接: github.com/ethereum/cons...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!