SmartMesh Developer Community

译文-Casper+Sharding chain v2.1

2018-08-31  本文已影响33人  cystone

Casper+Sharding chain v2.1

译者:程阳

原文:https://notes.ethereum.org/SCIg8AH5SA-O4C1G1LYZHQ

工作正在进行中!!!

这是描述Casper + Sharding链第2.1版规范的工作进度文档。

在这个协议中,有一条中心PoS链存储和管理当前活跃的PoS验证者们。成为一名初始验证者唯一可用的机制是在现有的PoW主链上发送一条包含32ETH的交易。当你这样做了,PoS链一处理区块,你将会处在一个队列中,并最终以一名活跃的验证者正式加入,直到你自愿退出,或者因异常行为被处罚而被强制注销。

PoS链上的主要负载源是认证(attestations)。一个认证包括两方面角色:

  1. 证实信标区块(beacon chain)中的一些父区块

  2. 证实一个区块在分片(shard)中的哈希(足够多这样的证明会创建一个交联(crosslink),来确保分片中的区块进入主链)

每个分片(总共可能有1024个分片)都是一个PoS链,分片链存储交易和账户信息。交联提供“确认”分片中的片段进入主链的服务,同时也是不同分片之间进行通信的主要方式。

值得一提的是,还可以考虑一种更简单的“最小切分算法”,其中交联只是提交的数据块的散列,这些数据块本身并不以任何方式相互链接。

注意: 在https://github.com/ethereum/beacon_chain 的python代码和 an ethresear.ch post没有反映最新的更改。如果有人么差异,这个文档很可能会反映出最新的变化。

术语:
常量:
PoW 主链的改变:

本PoS/分片提案可以独立于现存的PoW主链实施。主链只需要做两处变更(且第二个在技术上讲不是严格必要的)。

信标链

信标链是PoS系统中的“主链”。信标链的主要职责是:

fields = {
    # Hash of the parent block
    'parent_hash': 'hash32',
    # Slot number (for the PoS mechanism)
    'slot_number': 'int64',
    # Randao commitment reveal
    'randao_reveal': 'hash32',
    # Attestations
    'attestations': [AttestationRecord],
    # Reference to PoW chain block
    'pow_chain_ref': 'hash32',
    # Hash of the active state
    'active_state_root': 'hash32',
    # Hash of the crystallized state
    'crystallized_state_root': 'hash32',
}

信标链状态被分为两部分,活跃状态和结晶状态。
这是ActiveState

fields = {
    # Attestations that have not yet been processed
    'pending_attestations': [AttestationRecord],
    # Most recent 2 * CYCLE_LENGTH block hashes, older to newer
    'recent_block_hashes': ['hash32']

这是CrystallizedState

fields = {
    # List of validators
    'validators': [ValidatorRecord],
    # Last CrystallizedState recalculation
    'last_state_recalc': 'int64',
    # What active validators are part of the attester set
    # at what slot, and in what shard. Starts at slot
    # last_state_recalc - CYCLE_LENGTH
    'indices_for_slots': [[ShardAndCommittee]],
    # The last justified slot
    'last_justified_slot': 'int64',
    # Number of consecutive justified slots ending at this one
    'justified_streak': 'int64',
    # The last finalized slot
    'last_finalized_slot': 'int64',
    # The current dynasty
    'current_dynasty': 'int64',
    # The next shard that crosslinking assignment will start from
    'crosslinking_start_shard': 'int16',
    # Records about the most recent crosslink `for each shard
    'crosslink_records': [CrosslinkRecord],
    # Total balance of deposits
    'total_deposits': 'int256',
    # Used to select the committees for each shard
    'dynasty_seed': 'hash32',
    # Last time the crosslink seed was reset
    'dynasty_seed_last_reset': 'int64'
}

ShardAndCommittee 对象的形式:

fields = {
    # The shard ID
    'shard_id': 'int16',
    # Validator indices
    'committee': ['int24']
}

每一个ValidatorRecord都包含了一个验证者(validator)的信息:

fields = {
    # The validator's public key
    'pubkey': 'int256',
    # What shard the validator's balance will be sent to
    # after withdrawal
    'withdrawal_shard': 'int16',
    # And what address
    'withdrawal_address': 'address',
    # The validator's current RANDAO beacon commitment
    'randao_commitment': 'hash32',
    # Current balance
    'balance': 'int64',
    # Dynasty where the validator  is inducted
    'start_dynasty': 'int64',
    # Dynasty where the validator leaves
    'end_dynasty': 'int64'
}

CrosslinkRecord 包含了上一个被提交到链上的完整的交联信息:

fields = {
    # What dynasty the crosslink was submitted in
    'dynasty': 'int64',
    # The block hash
    'hash': 'hash32'
}
信标链处理

在很多方面,处理信标链基本上与处理一条PoW的链很相似。客户端下载和处理区块,并维护当前“权威链”的一个视图,在当前“块头”终止。然而,由于信标链与现有的PoW链的关系,并且因为它是一个PoS链,因此还是有一些区别。

对于信标链上的区块想要被一个node处理,得满足三个条件:

如果不满足这三个条件,客户端应该会延迟处理该区块直到三个条件全部满足。

因为权益证明机制区块生产稍有不同。客户端要创建一个区块的时候,会简单的检查它认为权威的链,而且会查看他的slot numbner;当该时间槽(slot)到来时,它根据需要选择提案或者验证一个区块。

信标链分叉选择规则

信标链使用 Casper FFG 的“热衷于包含(slot number)得分最高的合法区块的链”作为分叉选择规则。为了选择从同一合法区块派生的链,该链使用了“即时消息驱动GHOST(immediate message driven GHOST)”(IMD GHOST)来选择链头。

详细信息参见:https://ethresear.ch/t/beacon-chain-casper-ffg-rpj-mini-spec/2760

对于具有网络仿真器的实现,请参见:https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py

这里有一个它的工作示例(绿色的是终结区块,黄色的是合法区块,灰色的是证明)

信标链状态转移函数

我们现在定义状态转移函数。从比较高的层面讲,状态转移由2部分组成:

  1. 结晶状态重计算(crystallized state recalculation),只发生在block.slot_number >= last_state_recalc + CYCLE_LENGTH,并且影响CrystallizedState(结晶状态)和ActiveState(活跃状态)。
  2. 处理每个块(per-block processing),这发生在每个块(如果是在结晶状态重计算期间,它发生在结晶状态重计算之后)并且只影响ActiveState(活跃状态)。

结晶状态重计算一般侧重验证人集合的改变上,包括调整余额,添加和移除验证者,以及处理交联和管理区块校验,而处理每个块一般侧重验证聚合签名和在活跃状态中保存相关区块内活动的临时记录。

辅助函数

我们通过定义一些辅助算法开始。首先,该函数会选择以ixe活跃的验证者:

def get_active_validator_indices(validators, dynasty):
    o = []
    for i in range(len(validators)):
        if validators[i].start_dynasty <= dynasty < \
                validators[i].end_dynasty:
            o.append(i)
    return o

现在,一个函数把这个列表打乱:

def shuffle(lst, seed):
    assert len(lst) <= 16777216
    o = [x for x in lst]
    source = seed
    i = 0
    while i < len(lst):
        source = blake(source)
        for pos in range(0, 30, 3):
            m = int.from_bytes(source[pos:pos+3], 'big')
            remaining = len(lst) - i
            if remaining == 0:
                break
            rand_max = 16777216 - 16777216 % remaining
            if m < rand_max:
                replacement_pos = (m % remaining) + i
                o[i], o[replacement_pos] = o[replacement_pos], o[i]
                i += 1
    return o

然后,把这个列表分成N个片段:

def split(lst, N):
    return [lst[len(lst)*i//N: len(lst)*(i+1)//N] for i in range(N)]

现在,把这些辅助方法集合到一起:

def get_new_shuffling(seed, validators, dynasty, crosslinking_start_shard):
    avs = get_active_validator_indices(validators, dynasty)
    if len(avs) >= CYCLE_LENGTH * MIN_COMMITTEE_SIZE:
        committees_per_slot = len(avs) // CYCLE_LENGTH // (MIN_COMMITTEE_SIZE * 2) + 1
        slots_per_committee = 1
    else:
        committees_per_slot = 1
        slots_per_committee = 1
        while len(avs) * slots_per_committee < CYCLE_LENGTH * MIN_COMMITTEE_SIZE \
                and slots_per_committee < CYCLE_LENGTH:
            slots_per_committee *= 2
    o = []
    for i, slot_indices in enumerate(split(shuffle(avs, seed), CYCLE_LENGTH)):
        shard_indices = split(slot_indices, committees_per_slot)
        shard_id_start = crosslinking_start_shard + \
            i * committees_per_slot // slots_per_committee
        o.append([ShardAndCommittee(
            shard_id = (shard_id_start + j) % SHARD_COUNT,
            committee = indices
        ) for j, indices in enumerate(shard_indices)])
    return o

下边是一张工作流程示意图:

同时,我们定义

def get_indices_for_slot(crystallized_state, slot):
    ifh_start = crystallized_state.last_state_recalc - CYCLE_LENGTH
    assert ifh_start <= slot < ifh_start + CYCLE_LENGTH * 2
    return crystallized_state.indices_for_slots[slot - ifh_start]

def get_block_hash(active_state, curblock, slot):
    sback = curblock.slot_number - CYCLE_LENGTH * 2
    assert sback <= slot < sback + CYCLE_LENGTH * 2
    return active_state.recent_block_hashes[slot - sback]

get_block_hash(*, *, h) 应该总是在时间 h 的时候返回一个区块,get_indices_for_slot(*, h) 在朝代(dynasty)变更之前不应该有变化。

启动时

其他在活动或者终结状态的值可以根据上下文设为0或者空。

处理每个块

首先,将recent_block_hashes设置为下边输出的样子:

def get_new_recent_block_hashes(old_block_hashes, parent_slot,
                                current_slot, parent_hash):
    d = current_slot - parent_slot
    return old_block_hashes[d:] + [parent_hash] * min(d, len(old_block_hashes))

get_block_hash 的输出不应该改变,除非他不再抛出 current_slot - 1````, 而抛出current_slot - CYCLE_LENGTH * 2 - 1```

一个区块可以有0个或者多个 AttestationRecord,每一个 AttestationRecord 对象结构如下:

fields = {
    # Slot number
    'slot': 'int64',
    # Shard ID
    'shard_id': 'int16',
    # List of block hashes that this signature is signing over that
    # are NOT part of the current chain, in order of oldest to newest
    'oblique_parent_hashes': ['hash32'],
    # Block hash in the shard that we are attesting to
    'shard_block_hash': 'hash32',
    # Who is participating
    'attester_bitfield': 'bytes',
    # Last justified block
    'justified_slot': 'int256',
    'justified_block_hash': 'hash32',
    # The actual signature
    'aggregate_sig': ['int256']
}

每个证明需要作一下验证:

active_state 中扩展 AttestationRecord 对象的列表,按照块中新添加的顺序排列。

确认 get_indices_for_slot(crystallized_state, slot)[0] 中的第 slot % len(get_indices_for_slot(crystallized_state, slot)[0]) 个验证者在至少一个AttestationRecord对象中;然后这个验证者就可以创建区块提案了。

状态重计算

重复 slot - last_state_recalc >= CYCLE_LENGTH

所有 last_state_recalc - CYCLE_LENGTH ... last_state_recalc - 1 中的时间槽 s

同时:

对于所有的(shard_id, shard_block_hash)元组,计算证实分片上那个区块哈希的验证者的总存款。如果这个值乘以3等于或者大于委员会中所有验证者总余额的2倍,而且但前朝代超过了 crosslink_records[shard_id].dynasty,就令crosslink_records[shard_id] = CrosslinkRecord(dynasty=current_dynasty, hash=shard_block_hash)

TODO:

改朝换代

TODO。正在完成中。


备注: 完成度大约70%。缺失的主要章节是:

削减条件可能包括:

Casper FFG slot equivocation
Casper FFG surround
Beacon chain proposal equivocation
Shard chain proposal equivocation
Proof of custody secret leak
Proof of custody wrong custody bit
Proof of custody no secret reveal
RANDAO leak
上一篇 下一篇

猜你喜欢

热点阅读