星期三 , 十二月 19 2018
首页 / 区块之心 / 以太坊2.0规范:Casper和分片

以太坊2.0规范:Casper和分片

eth2.0 以下为规范译文:

在以太坊2.0当中,有一个被称为“beacon链”的核心系统链,这个beacon链负责存储和管理当前活跃PoS验证者的集合。而最初成为验证者的唯一机制,是在现有的PoW主链发送一笔包含32 ETH 的交易。当你这样做时,一旦PoS链处理了该区块,你就会进入队列,并最终成为一名活跃验证者。当然,你也可以自愿注销验证者身份,或者因为自己的不当行为而被强行注销身份。

beacon链的主要负载来源是证明(attestation)。这些证明会同时确认一个分片区块,以及相对应的beacon链区块。对于相同的分片区块,足够数量的证明就创建了一个“交联”(crosslink)。“交联”用于“确认”分片链的片段进入了主链,并且这也是不同分片之间互相通信的主要方式。

注:项目的python代码库地址为:https://github.com/ethereum/beacon_chain

 

一、术语

 

1、验证者(Validator):参与Casper/分片 共识系统的参与者。你可以通过将32 ETH存入这个Casper机制而成为一名验证者。

2、活跃验证者集(Active validator set):指那些正在参与的验证者,Casper机制希望产生并证明区块、“交叉链接”以及其它共识对象;

3、委员会(Committee):活跃验证者集的一个(伪)随机抽样子集。当一个委员会被集体选出时,正如“这个委员会证明了X”一样,这就意味着,该委员会的一些子集,包含了足够的验证者,以致协议承认它代表着该委员会。

4、提出者(Proposer):创建区块的验证者;

5、证明者(Attester):它是委员会的验证成员,其需要在一个区块上进行签名操作;

6、Beacon链(Beacon chain):分片系统的基础,即核心PoS链;

7、分片链(Shard chain):交易所发生的链之一,并用于存储账户数据;

8、交联(Crosslink):一组来自委员会的签名,其可证明一个分片链中的区块,它们可以被包含在beacon链当中。交联是beacon链“了解”分片链更新状态的主要手段;

9、Slot:SLOT_DURATION周期时间,在此期间,一个提出者有能力创建一个区块,而某些证明者能够进行证明工作;

10、朝代变迁(Dynasty transition):验证者集的变化;

11、朝代(Dynasty):自创世以来,在给定链中发生的朝代变迁的数量;

12、周期(Cycle):在这个时期内,所有验证者都有一次投票的机会(除非一个朝代的转变发生在内部)

13、完成区块及合理区块(Finalized, justified),见Casper FFG定稿:https://arxiv.org/abs/1710.09437

14、取款周期(Withdrawal period):验证者退出与验证者余额可取款之间的slot数量;

15、创始时间(Genesis time):beacon链在slot 为0时的创始区块UNIX时间;

二、常量

P1

验证者状态码:

P1

特殊记录类型:

p2

验证者集增量标志:

p3

 

三、PoW主链注册合约

 

以太坊2.0的初始部署阶段,是不需要对PoW链进行共识更改的。相反的是,我们会向PoW链添加一个注册合约,以存入ETH。这个合约有一个注册函数,它采用了pubkeywithdrawal_shardwithdrawal_addressrandao_commitment 这些参数,正如下面的ValidatorRecord中所定义。

这个注册合约会通过beacon链发出一个带有各种参数的日志。它不会进行验证,而是把注册逻辑发送给beacon链。需要注意的是,注册合约不会去验证占有证明(基于BLS12-381曲线)。

 

四、Beacon 链数据结构

 

Beacon链是PoS系统的“主链”,beacon链的主要职责是:

  1. 存储并维护活跃、列队等待以及退出验证者的集合;
  2. 处理交联(见上文);
  3. 处理逐块一致性,以及最终小工具(finality gadget);

 

4、1   Beacon 链区块

 

一个BeaconBlock具有以下字段:


{
# Slot number
'slot': 'int64',
# Proposer RANDAO reveal
'randao_reveal': 'hash32',
# Recent PoW chain reference (block hash)
'pow_chain_reference': 'hash32',
# Skip list of ancestor block hashes (i'th item is 2**i'th ancestor (or zero) for i = 0, ..., 31)
'ancestor_hashes': ['hash32'],
# Active state root
'active_state_root': 'hash32',
# Crystallized state root
'crystallized_state_root': 'hash32',
# Attestations
'attestations': [AttestationRecord],
# Specials (e.g. logouts, penalties)
'specials': [SpecialRecord]
}

一个AttestationRecord具有以下字段:


{
    # Slot number
    'slot': 'int64',
    # Shard number
    'shard': 'int16',
    # Block hashes not part of the current chain, oldest to newest
    'oblique_parent_hashes': ['hash32'],
    # Shard block hash being attested to
    'shard_block_hash': 'hash32',
    # Attester participation bitfield (1 bit per attester)
    'attester_bitfield': 'bytes',
    # Slot of last justified block
    'justified_slot': 'int64',
    # Hash of last justified block
    'justified_block_hash': 'hash32',
    # BLS aggregate signature
    'aggregate_sig': ['int256']
}

一个AttestationSignedData具有以下字段:


{
    # Chain version
    'version': 'int64',
    # Slot number
    'slot': 'int64',
    # Shard number
    'shard': 'int16',
    # 31 parent hashes
    'parent_hashes': ['hash32'],
    # Shard block hash
    'shard_block_hash': 'hash32',
    # Slot of last justified block referenced in the attestation
    'justified_slot': 'int64'
}

一个SpecialRecord具有以下字段:


{
    # Kind
    'kind': 'int8',
    # Data
    'data': ['bytes']
}

4、2  Beacon链状态

beacon链状态分为了活跃状态(active state )和结晶状态(crystallized state)这两个部分;

下面是活跃状态ActiveState具有的字段:


{
    # Attestations not yet processed
    'pending_attestations': [AttestationRecord],
    # Specials not yet been processed
    'pending_specials': [SpecialRecord]
    # Most recent 2 * CYCLE_LENGTH block hashes, older to newer
    'recent_block_hashes': ['hash32'],
    # RANDAO state
    'randao_mix': 'hash32'
}

下面是结晶状态CrystallizedState具有的字段:


{
    # Dynasty number
    'dynasty': 'int64',
    # Dynasty seed (from randomness beacon)
    'dynasty_seed': 'hash32',
    # Dynasty start
    'dynasty_start_slot': 'int64',
    # List of validators
    'validators': [ValidatorRecord],
    # Most recent crosslink for each shard
    'crosslinks': [CrosslinkRecord],
    # Last crystallized state recalculation
    'last_state_recalculation_slot': 'int64',
    # Last finalized slot
    'last_finalized_slot': 'int64',
    # Last justified slot
    'last_justified_slot': 'int64',
    # Number of consecutive justified slots
    'justified_streak': 'int64',
    # Committee members and their assigned shard, per slot
    'shard_and_committee_for_slots': [[ShardAndCommittee]],
    # Total deposits penalized in the given withdrawal period
    'deposits_penalized_in_period': ['int32'],
    # Hash chain of validator set changes (for light clients to easily track deltas)
    'validator_set_delta_hash_chain': 'hash32'
    # Parameters relevant to hard forks / versioning.
    # Should be updated only by hard forks.
    'pre_fork_version': 'int32',
    'post_fork_version': 'int32',
    'fork_slot_number': 'int64',
}

一个ValidatorRecord具有以下字段:


{
    # BLS public key
    'pubkey': 'int256',
    # Withdrawal shard number
    'withdrawal_shard': 'int16',
    # Withdrawal address
    'withdrawal_address': 'address',
    # RANDAO commitment
    'randao_commitment': 'hash32',
    # Balance
    'balance': 'int64',
    # Status code
    'status': 'int8',
    # Slot when validator exited (or 0)
    'exit_slot': 'int64'
}

一个CrosslinkRecord具有以下字段:


{
    # Dynasty number
    'dynasty': 'int64',
    # Slot number
    'slot': 'int64',
    # Beacon chain block hash
    'shard_block_hash': 'hash32'
}

一个ShardAndCommittee 对象具有以下字段:


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

 

4、3  Beacon链的处理

 

处理beacon链,在很多方面与处理PoW链有着相似之处。例如客户端下载、处理区块,维护当前的“权威链”,并终止于当前“头部”。然而,由于beacon链与现有PoW链之间的关系,并且beacon链是一种PoS链,两者还是有很大不同的。

对于beacon链上节点所处理的区块,必须要满足3个条件:

  1. ancestor_hashes[0]指向的父对象已被处理及接受。
  2. pow_chain_ref所指向的PoW链区块已被处理及接受;
  3. 节点的本地时间大于或等于由GENESIS_TIME + slot_number * SLOT_DURATION 计算得出的最小时间戳;

如果不满足这三个条件,则客户端应延迟处理区块,直到满足这几个条件为止。

在区块生产方面,由于PoS机制的原因,beacon链显然与PoW链存在着显著差异。客户端应检查权威链应该在什么时候创建区块,并查找它的slot(类似高度)数;当slot到达时,它会根据要求提出或证明一个区块;

4、4。Beacon链分叉选择规则

beacon链使用了Casper FFG分叉选择规则,即“支持包含最高合理检查点(highest-epoch justified checkpoint)的区块链”。为了从相同合理检查点派生而出的两条链之间进行选择,区块链会使用即时消息驱动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

下图展示了系统工作的一个例子(绿色是完成区块,黄色代表合理区块,灰色代表证明):

p5

 

五、Beacon链状态转移函数

 

我们现在定义一下状态转移函数。从高层次讲,状态转换由两个部分组成:

  1. 结晶状态重计算,这只有当block.slot_number >= last_state_recalc + CYCLE_LENGTH 时才会发生,而它会影响CrystallizedState以及ActiveState
  2. 每区块处理(per-block processing),它发生在每个区块,并且其只影响ActiveState

结晶状态重计算通常集中于对验证者集的更改,包括调整余额,添加和删除验证者,以及处理交联( crosslink)和设置FFG检查点,而每区块处理通常集中于验证聚合签名并保存与ActiveState区块内活动有关的临时记录。

 

5、1  辅助函数(Helper functions)

 

我们首先定义一些辅助算法。首先是,选择活跃验证者的函数:


def get_active_validator_indices(validators):
    return [i for i, v in enumerate(validators) if v.status == ACTIVE]
 

接下来是洗牌这个列表的函数:


def shuffle(lst, seed):
    # entropy is consumed in 3 byte chunks
    # rand_max is defined to remove the modulo bias from this entropy source
    rand_max = 2**24
    assert len(lst) <= rand_max

o = [x for x in lst] source = seed
i = 0
while i < len(lst):
source = hash(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 = rand_max - rand_max % 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, crosslinking_start_shard):
    active_validators = get_active_validator_indices(validators)
    if len(active_validators) >= CYCLE_LENGTH * MIN_COMMITTEE_SIZE:
        committees_per_slot = min(len(active_validators) // CYCLE_LENGTH // (MIN_COMMITTEE_SIZE * 2) + 1, SHARD_COUNT // CYCLE_LENGTH)
        slots_per_committee = 1
    else:
        committees_per_slot = 1
        slots_per_committee = 1
        while len(active_validators) * 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(active_validators, seed), CYCLE_LENGTH)):
        shard_indices = split(slot_indices, committees_per_slot)
        shard_start = crosslinking_start_shard + \
            i * committees_per_slot // slots_per_committee
        o.append([ShardAndCommittee(
            shard = (shard_start + j) % SHARD_COUNT,
            committee = indices
        ) for j, indices in enumerate(shard_indices)])
    return o

下面是一个关于正在发生的图解: p5

我们还定义了两个函数:


def get_shards_and_committees_for_slot(crystallized_state, slot):
    earliest_slot_in_array = crystallized_state.last_state_recalculation_slot - CYCLE_LENGTH
    assert earliest_slot_in_array <= slot < earliest_slot_in_array + CYCLE_LENGTH * 2
    return crystallized_state.shard_and_committee_for_slots[slot - earliest_slot_in_array]

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

其中get_block_hash(_, _, s)应该始终以slot s返回链中的区块,而get_shards_and_committees_for_slot(_, s)则不应该改变,除非朝代(dynasty)发生改变。

我们还定义了一个函数,为验证者哈希链“添加了一个link”,这在添加或移除一个验证者时使用:


def add_validator_set_change_record(crystallized_state, index, pubkey, flag):
    crystallized_state.validator_set_delta_hash_chain = \
        hash(crystallized_state.validator_set_delta_hash_chain +
             bytes1(flag) + bytes3(index) + bytes32(pubkey))

最后,我们抽象地将用于奖励/惩罚计算的int_sqrt(n)定义为最大整数k,使得k**2<=n:


def int_sqrt(n):
    x = n
    y = (x + 1) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

 

5、2 关于启动(On startup)

 

运行以下代码:

 
def on_startup(initial_validator_entries):
    # Induct validators
    validators = []
    for pubkey, proof_of_possession, withdrawal_shard, withdrawal_address, \
            randao_commitment in initial_validator_entries:
        add_validator(validators, pubkey, proof_of_possession,
                      withdrawal_shard, withdrawal_address, randao_commitment)
    # Setup crystallized state
    cs = CrystallizedState()
    x = get_new_shuffling(bytes([0] * 32), validators, 0)
    cs.shard_and_committee_for_slots = x + x
    cs.dynasty = 1
    cs.crosslinks = [CrosslinkRecord(dynasty=0, slot=0, hash=bytes([0] * 32))
                            for i in range(SHARD_COUNT)]
    # Setup active state
    as = ActiveState()
    as.recent_block_hashes = [bytes([0] * 32) for _ in range(CYCLE_LENGTH * 2)]

CrystallizedState()ActiveState()构造函数应根据上下文将所有值初始化为零字节、空值或空数组。add_validator程序定义如下:

 
def add_validator(validators, pubkey, proof_of_possession, withdrawal_shard,
                  withdrawal_address, randao_commitment):
    # if following assert fails, validator induction failed
    # move on to next validator registration log
    assert BLSVerify(pub=pubkey,
                     msg=hash(pubkey),
                     sig=proof_of_possession)
    rec = ValidatorRecord(
        pubkey=pubkey,
        withdrawal_shard=withdrawal_shard,
        withdrawal_address=withdrawal_address,
        randao_commitment=randao_commitment,
        balance=DEPOSIT_SIZE * GWEI_PER_ETH, # in Gwei
        status=PENDING_ACTIVATION,
        exit_slot=0
    )
    index = min_empty_validator(validators)
    if index is None:
        validators.append(rec)
        return len(validators) - 1
    else:
        validators[index] = rec
        return index

 

5、3 每区块处理(Per-block processing)

 

这个程序应该在每个区块上执行。

首先,将recent_block_hashes设置为以下输出,其中parent_hash是前一个区块的哈希:


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的输出不应该改变,除非它不再 throw for current_slot - 1,而是 throw for current_slot - CYCLE_LENGTH * 2 - 1

此外,使用以下算法检查区块的ancestor_hashes数组是否被正确更新:


def update_ancestor_hashes(parent_ancestor_hashes, parent_slot_number, parent_hash):
    new_ancestor_hashes = copy.copy(parent_ancestor_hashes)
    for i in range(32):
        if parent_slot_number % 2**i == 0:
            new_ancestor_hashes[i] = parent_hash
    return new_ancestor_hashes

区块可以有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',
    # The actual signature
    'aggregate_sig': ['int256']
}

对于这些证明中的每一个:

  1. 验证slot <= parent.slot 以及slot >= max(parent.slot - CYCLE_LENGTH + 1, 0)
  2. 验证给定链中的justified_slot以及justified_block_hash等于或早于结晶状态的last_justified_slot
  3. 计算parent_hashes = [get_block_hash(crystallized_state, active_state, block, slot - CYCLE_LENGTH + i) for i in range(CYCLE_LENGTH - len(oblique_parent_hashes))] + oblique_parent_hashes
  4. 让 attestation_indices成为 get_indices_for_slot(crystallized_state, active_state, slot)[x],选择 x 那么 attestation_indices.shard_id 就等于 所提供的 shard值,以找到创建证明记录的验证者集;
  5. 验证len(attester_bitfield) == ceil_div8(len(attestation_indices)), 其中ceil_div8 = (x + 7) // 8. 验证位len(attestation_indices)…. 以及更高的, 如果出现的 (i.e. len(attestation_indices)结果不是8的倍数), 则所有为0
  6. 让 version = pre_fork_version if slot < fork_slot_number else post_fork_version.
  7. 使用生成的公钥组以及序列化形式的AttestationSignedData(version, slot, shard, parent_hashes, shard_block_hash, justified_slot) 验证 aggregate_sig

5、4 状态重计算

slot - last_state_recalc >= CYCLE_LENGTH时进行重复过程;

对于所有 last_state_recalc - CYCLE_LENGTH ... last_state_recalc - 1范围中的slot s

  1. 确定至少为该区块投票的验证者的总集合;
  2. 确定这些验证者的总余额,如果该值乘以3等于或超过所有活跃验证者乘以2的总余额,则设置 last_justified_slot = max(last_justified_slot, s) 以及 justified_streak += 1。否则,则设置justified_streak = 0;
  3. 如果justified_streak >= CYCLE_LENGTH + 1,则设置last_finalized_slot = max(last_finalized_slot, s – CYCLE_LENGTH – 1);
  4. 删除所有比 last_state_recalc slot更早的证明记录;

还有:

1、设置last_state_recalc += CYCLE_LENGTH; 2、设置indices_for_slots[:CYCLE_LENGTH] = indices_for_slots[CYCLE_LENGTH:];

对于所有(shard_id, shard_block_hash) 元组,计算为该分片区块哈希投票的验证者总存款大小。如果该值乘以3等于或超过委员会中所有验证者的总余额乘以2,并且当前朝代(dynasty)超过crosslink_records[shard_id].dynasty,则设置crosslink_records[shard_id] = CrosslinkRecord(dynasty=current_dynasty, hash=shard_block_hash);

待办事项:

  1. FFG参与奖励;
  2. 委员会参与奖励;

六、朝代变迁(Dynasty transition)

如果满足下列所有标准,则在状态重新计算之后发生了朝代变迁:

 

  1. block.slot - crystallized_state.dynasty_start_slot >= MIN_DYNASTY_LENGTH
  2. last_finalized_slot > dynasty_start_slot
  3. 对于shard_and_committee_for_slots中的每一个shard分片数,crosslinks[shard].slot > dynasty_start_slot

然后,运行下面的算法来更新验证者集合:

 
def change_validators(validators):
    # The active validator set
    active_validators = get_active_validator_indices(validators, dynasty)
    # The total balance of active validators
    total_balance = sum([v.balance for i, v in enumerate(validators) if i in active_validators])
    # The maximum total wei that can deposit+withdraw
    max_allowable_change = max(
        2 * DEPOSIT_SIZE GWEI_PER_ETH,
        total_balance // MAX_VALIDATOR_CHURN_QUOTIENT
    )
    # Go through the list start to end depositing+withdrawing as many as possible
    total_changed = 0
    for i in range(len(validators)):
        if validators[i].status == PENDING_ACTIVATION:
            validators[i].status = ACTIVE
            total_changed += DEPOSIT_SIZE
            add_validator_set_change_record(crystallized_state, i, validators[i].pubkey, ENTRY)
        if validators[i].status == PENDING_EXIT:
            validators[i].status = PENDING_WITHDRAW
            validators[i].exit_slot = current_slot
            total_changed += validators[i].balance
            add_validator_set_change_record(crystallized_state, i, validators[i].pubkey, EXIT)
        if total_changed >= max_allowable_change:
            break

# Calculate the total ETH that has been penalized in the last ~2-3 withdrawal periods period_index = current_slot // WITHDRAWAL_PERIOD total_penalties = ( (crystallized_state.deposits_penalized_in_period[period_index]) + (crystallized_state.deposits_penalized_in_period[period_index – 1] if period_index >= 1 else 0) + (crystallized_state.deposits_penalized_in_period[period_index – 2] if period_index >= 2 else 0) ) # Separate loop to withdraw validators that have been logged out for long enough, and # calculate their penalties if they were slashed for i in range(len(validators)): if validators[i].status in (PENDING_WITHDRAW, PENALIZED) and current_slot >= validators[i].exit_slot + WITHDRAWAL_PERIOD: if validators[i].status == PENALIZED: validators[i].balance -= validators[i].balance * min(total_penalties * 3, total_balance) // total_balance validators[i].status = WITHDRAWN

withdraw_amount = validators[i].balance
...
# STUB: withdraw to shard chain

最后:

  1. 设置 last_dynasty_start_slot = crystallized_state.last_state_recalculation_slot
  2. 设置 crystallized_state.dynasty += 1
  3. 设置 next_start_shard = (shard_and_committee_for_slots[-1][-1].shard + 1) % SHARD_COUNT
  4. 设置 shard_and_committee_for_slots[CYCLE_LENGTH:] = get_new_shuffling(active_state.randao_mix, validators, next_start_shard)

 

七、尚未完成的工作

 

注:这个项目的完成度大约为60%,所缺少的主要部分为:

  1. 具体如何构造 crystallized_state_root以及active_state_root,包括用于轻客户端的默克尔化证明;
  2. 关于pow_chain_reference可接受值的具体规则;
  3. 关于分片链区块、提出者等具体规则;
  4. 关于强制撤销登记的具体规则;
  5. 关于(全局时钟、网络延迟、验证者诚实、验证者活跃度等)问题的各种假设;
  6. 关于监护证明的逻辑,包括削减条件;
  7. 添加BLS12-381曲线的附录;
  8. 添加gossip网络以及链外签名聚合逻辑的附录;
  9. 添加一个词汇表(在单独的词汇表中),以全面而准确地定义所有术语;
  10. 进行同行评审、安全审核和形式验证;

可能的修订/增补 工作

  1. 用LMD替换IMD分叉选择规则;
  2. crystallized_state_root 以及 active_state_root 默克尔化成一个单独的根;
  3. 用一个对STARK友好的哈希函数替换掉Blake;
  4. 去掉朝代(dynasties)的概念;
  5. 将slot直接换成8秒;
  6. 允许延迟聚合签名的包含;
  7. 引入一种RANDAO削减条件;
  8. 对于占有证明,使用一种单独的哈希函数;
  9. 修改ShardAndCommittee数据结构;
  10. 为历史beacon链区块添加一个双批(double-batched)的默克尔累加器;
  11. 允许存款大于32ETH,并设置存款上限;
  12. 对于存款低于32ETH(或其它阈值)的情况,设置一个罚金;
  13. 为寄存器添加一个SpecialRecord
  14. 重写文档可读性;
  15. 清楚地记录各种边缘情况,例如委员会的大小;

 

附录

 

附录A -哈希函数

我们的目标是在推出beacon链时,拥有一个对STARK友好的哈希函数hash(x)。这个哈希函数的标准化过程,是由STARKware主导的,他们将制定详细的报告说明。我们会使用BLAKE2b-512作为占位符。明确地说,我们设置了hash(x) := BLAKE2b-512(x)[0:32] ,其中BLAKE2b-512算法是在RFC 7693中定义的。

关于 冯先生失眠中

冯先生失眠中
卷而怀之

检查

比特币钱包开发:比特币转账交易与交易记录

课程目标 理解交易的输入、输出 …

发表评论

电子邮件地址不会被公开。 必填项已用*标注