干货

以太坊 2.0 Phase 0 V0.8.0 技术规范详解

Ajian   |     |   1531 次阅读

以太坊 2.0 Phase 0 V0.8.0 技术规范详解

目录


资源

概览

信标链(Beacon chain)是居于以太坊 2.0 系统核心的一条链。叫这个名字是因为这条链会充当随机性的信标,但也可以就叫做 “系统链” 或者 “脊柱链”,等等。这条链也是验证者 “所在” 的链,也就是说,验证者的 责任 会在这条链上得到分配、验证者会在这个共识环境中运行协议层的随机数生成器、验证者也在这条链上为链顶端的区块投票并 形成确定性检查点;这里也是验证者引用分片链状态(crosslink)、用作诸分片链的根并协助跨分片通信的地方。信标链既是系统运作背后的大脑,也是后续分片系统据以搭建的框架。

信标链的状态( BeaconState )乃是技术规范所围绕的核心对象。 BeaconState 涵盖了所有有关的信息:验证者有哪些人、他们分别处在什么状态中、这个状态属于区块树上的哪条链,以及对 Eth1 链的哈希值引用。

从创世状态开始,每当有一个区块能够满足状态转换函数所设的所有条件,该块处理完成后的状态就被认为是有效状态。这样一来,一个区块的前提条件就可以被递归地定义为在前一个区块(及其状态)上运行状态转换函数所得的有效后置条件,这样一路回溯到创世状态。

分叉选择规则

分叉选择规则的含义是:给定一棵区块树,总是能够根据这样的规则以及近期来自验证者的消息,选出单一一条链(即 canonical chain,主链)以及终局状态。分叉选择规则接受该区块树以及相应的来自验证者集合的最新 attestation,然后返回一个区块作为当前的链顶端区块。LMD GHOST(最新消息驱动型 GHOST 算法),Eth2.0 所用的分叉选择规则,仅考虑每一个验证者最新的 attestation(“见证” 或者说 “证明”)所指向的区块,并以此来计算递归地附加在树上每一区块的总见证数量。也就是说,区块树上的一个节点(即一个 “区块”)的 “重量”,乃是将最新见证指向该区块或该区块的子孙区块的所有验证者的数量总和。GHOST 算法会从区块树的底部开始,每到一个节点便选择子链中最重的,直至到达叶子节点(即区块树末端的区块)。该叶子便是链的顶端,并递归地定义出了整条主链。

具体而言,在一个时段(epoch)中的每一个被指定的时隙(slot)中,验证者都有机会产生一个 attestation。提交 attestation.data.beacon_block_root 就是一次分叉选择意义上的投票了。在计算分叉选择结果时,算法会将来自近期活跃验证者所有投票都考虑在内

Finality

分叉选择规则让我们可以在一棵区块树中选出一条主链,而 “Finality”(“确定性”)则给了我们一种保证:特定的一些区块会一直保持在主链上。信标链使用改进版的 Casper FFG 来实现确定性。Casper 提供了 “可追责的安全性”,特定的一些区块会一直保持在主链上,除非一定比例的验证者烧掉他们锁定的资本。这就是我们认为有别于传统共识算法中的传统 “安全性” 定义的、“密码经济学” 意义上的 “安全性”。

具体而言,验证者们产生 attestation 的机会是以时隙(slot)为单位,在被分配到的时隙中,才有机会产生 attestation。提交 attestation.data.source 会作为 FFG 的 source pair,而提交 attestation.data.target 则会作为 FFG 的 target pair,前者在 “Combining GHOST and Casper” 处有更深入的讨论。

Crosslink(“交联”)即是在信标链上保存的、对分片链近期 状态/区块 的引用。这些引用既是分片链在做分叉选择时候的树根,也是分片链之间异步通信的工具。在正常情况下,每一个分片每一个时段都可以交联到信标链一次(如果验证者数量少,有时候也会是每 N 个时段一次)。

虽然在 Phase 1 之前我们不会加入分片链,但 Phase 0 中系统还是会给交联委员会分配一个分片并尝试每个时段生成一个交联。在 Pahse 0 中,交联中的数据根会简单地存根为 0x0000000000000000000000000000000000000000000000000000000000000000(32 bytes)。

验证者职责

关于 Phase 0 中的验证者职责,更详细的讨论可以看此处

验证者的两种主要职责是:(1)在每个时段中发出见证消息;(2)偶尔在被选中时产生信标链区块。每一个时段,验证者都会被分成不同的 “交联委员会”。每一个委员会都会被分配到一个时隙和一个分片。在给定时隙中,验证者为信标链顶端区块做 attestation(到 Phase 1 之后还要为分片链的最新数据做见证)。每一个时隙都会从被安排到该时隙的委员会中(通过 get_beacon_proposer_index)选出一个信标链区块提议者。

只要定期给信标链主链和分片链做见证,验证者就可以得到奖励;反之,如果不能完成职责,他们也会被惩罚。如果一个验证者违反了 Casper FFG 规则,或者他们在同一时段中创造了两个信标链区块,他们就会被 罚没(比惩罚要更加严厉)。更多关于罚没条件的细节请看此处

数据结构

注意

信标链内的数据结构以及数据结构的哈希值都被编码为 Simple SerialiZe (SSZ) 对象。使用 SSZ 哈希方法的一个好处是:在给底层数据生成默克尔树时,树的深度可以是不均匀的。这一点以及 SSZ 其余聪明设计的结果就是:一个 SSZ 对象,无论该对象的子对象是完整表现的还是仅由部分默克尔根值来表现的,该 SSZ 对象的哈希树根值都是一样的。

信标链操作

信标链操作就是一个区块提议者可以加入 BeaconBlock (信标链区块)的数据结构,包括在系统层 验证/构建 的多种消息。对信标链状态机而言,这些操作本质上都是验证者层级的事务。每一种操作在一个区块中都有数量上限,由 max operations per block 定义为常量。

ProposerSlashing

  • 如果一个信标链区块提议者在同一时段中提议了两个不同的信标链区块,TA 可以被罚没。
  • 这一数据结构包含了对可罚没事件已然发生的证明。
  • hash_tree_root(block) == hash_tree_root(block_header) ,因此,签名对所有数据结构来说都是有效的。 BeaconBlockHeader 因此可以用作证明来降低消息的大小。
  • 字段
    • proposer_index —— 即提议要惩罚的验证者的 ValidatorIndex
    • header_1 —— 两个需罚没信标链区块中第一个的区块头
    • header_2 —— 两个可罚没信标链区块中第二个的区块头

AttesterSlashing

  • 如果一个信标链见证者签署了两个相互冲突的见证(冲突情形由 is_slashable_attestation_data 来定义,后者会应用 Casper FFG 的 “双重投票” 和 “环绕” 投票条件来检查)
  • 字段
    • attestation_1 —— 两个需罚没 attestation 中的第一个,注意这个字段的形式也是索引形式的
    • attestation_2 —— 两个需罚没 attestation 中的第二个,注意这个字段的形式也是索引形式的

Attestation

  • 验证者为共识过程创建的最基本的消息形式。虽然每个时隙只有一个验证者可以创建信标链区块,但在一个时段中,每个验证者都有一次创建一个 attestation 的机会(译者注:虽然验证者每隔一个时段混洗一次,但一个委员会只负责一个时隙;在该时隙中,只有一名验证者能提议区块,其余验证者都只能见证区块;因此,在一个时段中,每个验证者都有一次(在 TA 所在的时隙)内创建见证的机会)。正常情况下,所有在线的验证者每逢一个时段都能创建一个 attestation,并且都有一个 attestation 被纳入区块中。
  • AttestationData 就是验证者签署的主要部分。
  • 外部的数据结构包含了聚合后的签名以及为了验证签名所必须的参与者字段。
  • 字段
    • aggregation_bits 为委员会的成员存储一个 bit,委员会会为每个参与该聚合签名的验证者赋值为 1。注意,这是按委员会的顺序来排列的。
    • data 就是该验证者或者验证者委员会签名的 AttestationData
    • beacon_block_root —— 在被指定的时隙处,被视为链顶端的信标链区块的区块根
    • source —— 在被指定的时隙处,最近在 BeaconState (信标链状态)中被确定的检查点(checkpoint)
    • target —— 试图敲定的检查点(当前时段以及 epoch boundary block)
    • crosslink —— 试图为指定分片构建的交联
    • custody_bitfield 表示每一个委员会成员的 “保管证明(proof of custody)” bit(如果没有参加,那就是 0)。在 Phase 0 阶段,该值必然为 0。(因为托管证明要到 Phase 1 才实现)。
    • signature 就是相关数据的 BLS 聚合签名。
  • AttestationDataAndCustodyBit 是验证者签署的实际消息。给定 Attestation ,验证者可能签署的消息有两种—— 带有 0 或 1 的 custody bit 的 AttestationDataAndCustodyBit 。根据 custody_bitfield,我们可以从每个参与的验证者处,恢复出需要的被签过名的消息(custody_bit 0/1)。在 Phase 0 中,所有的 custody bit 都是 0。

Deposit

  • 表示从 Eth1 链的保证金合约中即将到来的验证者保证金。
  • 字段
    • proof ——对 BeaconState 中的当前 eth1_data.root 的默克尔证据。 注意向量长度的 +1 是因为 SSZ 长度混合到了根中。
    • data —— DepositData 提交给保证金合约,以便被验证,验证时使用 deposit root 的证明。
    • pubkey ——验证者用以对消息签名的 BLS12-381 公钥
    • withdrawal_credentials —— 用于取出质押资金的离线公钥的哈希值。该密钥不会主动用于验证,可以保存在冷钱包中。
    • amount —— 存储的 Gwei 数量
    • signature —— 使用 pubkey 对应的 privkeyDepositData 的签名数据。这一数据也被用作一次性的 “proof of custody”,以保证安全地使用 BLS 秘钥。

VoluntaryExit

  • 消息类型,验证者可借发送此类消息而主动解除验证者职责
  • 字段
    • epoch —— 本次退出行动上链处理所需的最小时段数。这一字段可以防止在 链重组/分叉 时对本功能
    • validator_index —— 验证者退出活动的索引
    • signature —— 相关验证者用公钥对 VoluntaryExit 的签名(验证者身份由 validator_index 定义)。

Transfer

  • 让验证者可以转移余额。
  • 基本上就是为了让 Eth2 在 Phase 0 和 Phase 1 阶段(分片链承载状态之前)也能具有货币流动性。
  • 余额转移必须包括在准确指定的 slot 中,以避免重放攻击。
  • 正在承担职责的验证者不能转移余额,除非 TA 的余额高于 MAX_EFFECTIVE_BALANCE
  • MAX_TRANSFERS 在 Phase 0 启动阶段预计会被设置为 0,只有在 Phase 0 看起来已经稳定可用之后才会提高
  • 字段
    • sender —— 发送资金的验证者的索引
    • recipient —— 接收资金的验证者的索引
    • amount —— 发送的 Gwei 数量
    • fee —— 用 Gwei 为单位计算的、交给区块提议者的手续费
    • slot —— 这笔签名的 Transfer 可以上链的特定时隙。防止重放攻击
    • pubkey —— sender 取出的 pubkey 。该公钥的 hash 必须匹配 sender 的 withdrawal_credentials。
    • signature —— 对该 Transfer 的签名,来自 transfer.pubkey

信标链区块

  • BeaconBlock

    • 这个可以被认为是一个信标链区块的 主要容器/区块头。
    • 注意 hash_tree_root(BeaconBlock) == hash_tree_root(BeaconBlockHeader) 所以每一个签名都是等价的。
    • 字段
    • slot —— 该区块创建时候的 slot。必须比 parent_root 所定义的上一区块的时隙数更大
    • parent_root —— 父区块的区块根,以此形成一条区块链
    • state_root —— 使用当前区块运行完状态转换函数后的状态的哈希根
    • body —— 上述所有的信标链操作对象以及一些补充性字段都包含在这一字段中
    • signature —— 区块提议者对该区块的签名
  • BeaconBlockBody

    • randao_reveal —— (区块提议者)对当前时段(epoch)的签名,以及,当该字段与其他验证者揭示的值(reveal)混合在一起时,可以继续生成随机性种子
  • Eth1Data —— 一个对 Eth1 链上近期数据的投票。它维护着下列字段:

    • deposit_root —— 保证金合约中存储资金的 SSZ 列表 hash_tree_root
    • deposit_count —— 迄今为止已经发生的保证金笔数
    • block_hash —— 包含了 deposit_root 的 Eth1 区块哈希值。这一block_hash 可能在未来用于为 Eth1 链提供 Finality(类似于原来的用 FFG 合约来敲定 Eth1 链的计划)。
    • graffiti —— 这是一个验证者可以随意填写的空间。该字段没有协议层的用途。
  • proposer_slashings, attester_slashings, attestations, deposits, voluntary_exits, transfers

    • 即可以被包含到 BeaconBlockBody 中的操作类型的列表(有最大长度)

信标链状态

BeaconState 即是从创世区块开始、用一系列区块运行状态转换函数后所得的结果。它包含了验证者注册器、关于随机数的信息、关于 Finality 的信息、相关的缓存,以及 eth1 链的数据。

  • Versioning
    • genesis_time —— 跟踪创世事件发生的事件。这一数据让客户端可以根据经过的时间计算现在该是哪个 slot 了
    • slot —— 时间被划分为固定长度的 slot(“时隙”),所有行动和状态转换都在具体的时隙中发生。这一字段追踪相应状态的时隙
    • fork —— 一种处理信标链上分叉(升级)的机制。该字段的主要用意在于处理签名的版本控制,并处理分叉前后不同的签名对象。
  • 历史(History)
    • latest_block_header —— 存储所看到最新区块头。在一个区块所在的 slot 中,区块头会不带状态根保存起来;等到下一个时隙开始的时候,状态根才会加入到区块头中。这是为了消除嵌入区块头中的状态根所导致的循环依赖性
    • block_roots —— 逐 slot 存储的近期区块根。一个时隙的区块根在下一个时隙开始时才会加入,以避免因为状态根嵌入区块而导致的循环依赖性。至于那些被跳过的时隙(即在给定时间内没有产生区块),就存储前一个有效的区块根
    • state_roots —— 逐 slot 存储的近期状态根。一个时隙的状态根在下一个时隙开始时才会加入
    • historical_roots —— 一个双批次的最新区块和状态根默克尔累加器来产生对 XXX 的历史性默克尔证明
  • Eth1
    • eth1_data —— 验证者达成共识并存储在状态中的 Eth1Data
    • eth1_data_votes —— 存储在状态中的 Eth1Data 的实时列表。任何 Eth1Data 只要在一个投票期中拿到了 > 50% 的提议者投票,数据就会存进状态中,而新的准备金也可以得到处理
    • eth1_deposit_index —— 新的要被处理的准备金的索引。只要 eth1_data.deposit_count > eth1_deposit_index,准备金就必须被添加到下一个区块中
  • 注册表(Registry)
    • validators —— 一个 Validator 记录的列表,用来跟踪完整的当前注册表。每个验证者都保存着与之相关的数据,比如公钥、有效余额,还有 status(pending、活跃、已退出,等等)
    • balances —— 一个与 validator_registry 一一对应的列表。频繁且颗粒式变化的余额被抽取出来,以减少每个时段所需执行的重哈希数量的。
  • 混洗(Shuffling)
    • start_shard —— 跟踪当前时段的 “启动分片”,作为基础去计算一个时段中为各委员会安排哪个分片 —— (shard_shard + committee_offset) % SHARD_COUNT
    • randao_mixes —— 每一时段中的 Randao 混合值(mix)。每一时段开始的时候,上一时段的 randao_mix 会复制下来用作新一时段的计算基础。每个区块中, block.randao_revealhash 会跟实时的混合值(running mix)进行异或运算(XOR)。
    • active_index_roots —— 逐时段储存的活跃验证者索引的哈希根。主要是为了更好地服务轻客户端
    • compact_committee_roots —— 逐时段存储的当前时段的 CompactCommittee 列表的哈希根。这也是委员会的简洁代表,用来更好地服务轻客户端。预计会在 Phase 1 把常设委员会加入这个根中。
  • 罚没(Slashing)
    • slashings —— 逐时段存储的该时段内被罚没的总额。任意时间点,一个列表的总和都给出了 “近期被罚没的余额”,并被用于计算相关验证者需要被罚没的余额比例
  • 见证(Attestation)
    • 来自区块的 Attestations 被转化为 PendingAttestations 并存储在状态中,用于跨越时段边界时候的批量记账(bulk accounting)。我们储存了两个独立的列表
    • previous_epoch_attesations —— 上一时段的各时隙的 PendingAttestations 的列表。注意:这些乃是在上一时段各时隙中发出的见证,并不必然就是那些在上一时段中被打包到区块中的见证
    • current_epoch_attesations —— 当前时段的各时隙中的 PendingAttestations 列表。在当前时段处理结束后被转移到 previous_epoch_attestations
  • 交联(Crosslink)
    • 我们存储过往和当前时段的交联,因为交联必须形成一条链,所以 Attestation 要在创建过程中原样引用交联。要在当前时段验证来自以往时段的见证中的交联引用,我们使用 previous_crosslinks
    • current_crosslinks —— 当前时段的交联列表(每个分片一个交联)
    • previous_crosslinks —— 以往时段的交联列表(保持原样不变)
  • Finality
    • justification_bits —— 4 个 bit 的、用来跟踪最新 4 个时段中的确定性辩护(justification),以帮助确定性计算
    • previous_justified_checkpoint —— 以往时段最新被合理化(justified)的 Checkpoint ,保持它在以往时段中的原样。用来验证以往时段的见证
    • current_justified_checkpoint —— 当前时段最新被合理化的 Checkpoint 。用来验证当前时段的见证,并用于分叉选择
    • finalized_checkpoint —— 最新被敲定的 Checkpoint ,该点以前的区块将永远保持在主链上,不会被重组

状态转换

  • state_transition
    • 这是状态转换的顶层函数。它以一个旧状态和一个信标链区块为输入,然后输出一个新状态
  • process_slots
    • 状态转换函数的第一个组件,处理所有发生在时隙中的操作(无论属于哪个区块)。如果在运行状态转换函数的区块与其父块之间存在被跳过的 slot,那么区块所在时隙前的多个时隙都会在 process_slots 期间得到处理
    • 在见证区块或者产生区块的时候,参与共识的客户端有时候调用这个函数来转换状态,以跳过空的时隙
    • 每个时隙要缓存近期数据的时候都要调用 process_slot
    • 只有跨越时段边界的时候才需要调用 process_epoch 。注意,因为 state.slot 尚未增加,调用会在 slot % SLOTS_PER_EPOCH == 0 开始的那个时段的状态转换中发生
  • process_slot
    • 每个时隙都要执行一些对上一时隙的簿记工作。注意,因为 state 还未更新,所以仍表示着上一时隙完成后的状态。同样地, state.slot 仍等于上一时隙( process_slotprocess_slots 内完成之后 state.slot += 1 )。
    • 前一时隙的完成后状态根会在下一时隙中插入到状态中,以避免循环依赖性
    • 缓存状态根
    • 上一时隙的状态根会缓存在状态中。注意 hash_tree_root(state) == root_of_previous_state ,因为 state 还是上一时隙完成后的状态,还没有改变过来。
    • 缓存最新的区块头状态根
    • 如果上一时隙产生了一个区块(既并非被跳过的空时隙),那么我们将 previous_state_root 插入到缓存的区块头中。如果遇到空时隙,这个区块头会一直保存在状态中,直到产生下一个区块。
    • 缓存区块根
    • 我们会在每个时隙中将最新的区块缓存入 latest_block_roots 。如果该时隙被跳过了,那就会缓存来自最新的没有被跳过的时隙的区块。

时段处理

时段处理过程在每个时段的第 0 个时隙(slot % EPOCH_LENGTH == 0)开始的时候开始。注意,运行 process_epoch 的时候 state.slot 仍旧等于上一时隙(slot % EPOCH_LENGTH == EPOCH_LENGTH - 1),只在前者完成后,后者才增加。

process_epoch 主要是个容器函数,会调用其它的时段处理的次级函数。

辩护与确定性(Justification and Finalization)

  • process_justification_and_finalization
    • Justification 的更新首先要估计有多少验证者(用余额来加权)投票给上一个时段作为辩护的目标。只要超过 2/3 的活跃余额给相同时段做了见证,而该时段是上一时段,那就将 justification 的状态更新为上一时段。然后考虑当前时段,如果超过 2/3 的活跃余额都给当前时段做了见证,则当前时段也被合理化。
    • 只有最近的 2 个、3 个、4 个时段可以被敲定。实现方式是检查最近的 justification 用作来源的那个时段,以及被近期合理化时段用作来源的最新被合理化的时段(在过去 4 个时段以内),是否已被敲定。我们只考虑在草案的 5.5 中讨论的 k=1k=2 确定性规则。

交联(Crosslink)

  • process_crosslinks
    • 对每一个分片,只要至少 2/3 的委员会成员见证了相同的交联,就将该分片(在信标链视角中)的最新交联更新为该胜出的交联。信标链会检查上一时段和当前时段,以防止上一时段加入了更多交联。
    • 交联必须通过 crosslink.parent_root 形成一条链;只有那些符合链标准的交联才会在 get_winning_crosslink_and_attesting_indices 中被考虑。

奖励和惩罚(Rewards and Penalties)

  • process_rewards_and_penalties
    • 所有最后一个时段对验证者余额的奖励和罚没都用这个函数来收集。奖励和惩罚从 get_crosslink_deltasget_attestation_deltas 处收集,后两者会以列表的元组(tuples of lists)的形式返回每一个验证者所得的奖励和惩罚。奖励和惩罚是分开的,以避免出现 signed integer。
  • get_base_reward
    • 所有奖励都会乘以 $\frac{1}{(TotalBalance)^{1/2}}$ 。想理解为什么,请看设计哲学
  • get_attestation_deltas
    • 根据每个验证者在上一时段的见证行为的函数来决定验证者的余额如何更改
    • 对每一个活跃的验证者来说:
    • FFG 的 Source 、Target 和 Head 奖励 —— 如果一个验证者的 source、target 或者 head 见证与上一时段当时的 source、target 以及 head 相匹配,那就为他发放奖励,否则就发放惩罚。
    • 以见证被接受的速度进行奖励 —— 找出每个验证者的最快被打包的 attestation,并给相应的区块提议者一小笔奖励、给相应被打包的验证者一笔与其见证被打包的速度成比例的奖励
    • 怠惰惩罚 —— 如果链不能敲定,那就惩罚所有人,尤其是那些不参与的验证者。注意,怠惰惩罚不会降临到那些完全参与的验证者头上
  • get_crosslink_deltas
    • 每一个为(在他们的委员会中)胜出的交联做见证的验证者都可以收到一个与参与程度成比例的奖励,反之就会受到惩罚

注册表更新(Registry updates)

  • process_registry_updates
    • 余额足以激活验证者身份,但还没有被添加队列中的,将被添加到激活队列中
    • 余额太低的验证者将被 “弹出”,放到 “取款队列” 中
    • 激活队列中的验证者会在一段时间内(within the churn limit)激活

罚没(Slashings)

  • process_slashings
    • 验证者被罚没的力度会与在一定时间内被罚没的验证者数量成比例。这一点与验证者被罚没的顺序是相互独立的。process_slashings 会遍历近期的罚没事件,并成比例地罚没验证者。

最终更新(Final updates)

  • process_final_updates
    • 该方程处理需要随时段运作的各种功能,即:
    • 在新一轮投票期开始的时候,重置 eth1 数据投票
    • 重新计算有效余额(使用 husteresis)
    • 确定下一时段开始的新分片
    • 给众所周知索引要确定下来的最近一个时段设定索引根 (next_epoch + ACTIVATION_EXIT_DELAY)
    • 为下一个时段设定委员会根
    • 将下一个时段的被罚没余额设定为 0
    • 将当前时段的 randao 混合值结果设定为下一时段的基本 randao 混合值
    • (潜在地)将状态追加到历史根
    • current_epoch_attestations 移动到 previous ,然后将 current 设为空值

区块处理

process_block 是调用区块处理流程的次级函数的主函数。如果在块处理中抛出了任何断言或者异常,该块就会被视为无效的,并被丢弃。

区块头

(抽象来说)process_block_header 决定了一个区块是否有效。验证方式有:

  • 该区块是从合适的时隙中产生的
  • 父区块的哈希值是正确的
  • 区块提议者没有被罚没
  • 相应提议者对区块的签名是有效的

process_block_header 也会在 state 中存储区块头,以便后续用于状态转变函数。注意, state_root 会被设为空值,以避免循环依赖。状态根会在下一个时隙开始的时候通过 process_slot 添加进去。

RANDAO

process_randao 验证该区块的 RANDAO 揭示值是当前时段区块提议者的有效签名,并且,若然,则将它混合进当前时段的混合值中。

Eth1 data

process_eth1_data 把该区块的 eth1-data 添加到状态的 eth1-data-vote 中。如果该投票期中超过半数的票都投给了相同的 eth1-data,就更新 state.eth1_data

操作

process_operations 保证罚没、见证、保证金存入、保证金退出、保证金转移的数量都如后续部分的函数定义的那样发生。这是通过处理 ProposerSlashing, AttesterSlashingAttestationDepositVoluntaryExitTransfer 对象来实现的。


原文链接: https://notes.ethereum.org/jDcuUp3-T8CeFTv0YpAsHw?view#Beacon-state
作者: Danny Ryan
翻译: 阿剑

 
0 人喜欢