背景

  • 交易TPS的限制
  • 存储数据的浪费
  • 缺乏并行能力

核心目标

增强区块链的处理能力,首先降低数据的存储压力,其次增强区块链的处理能力

技术分类

  • Layer 2,在线下处理,仅将结果上链
  • 对共识等做修改,分片即为此类方式

分片的整体思路

shard

分片可以认为包含两个链,一个是主链(mainnet chain),一个是各个分块链(shard chain)

两者之间的关系可以这么认为,基本的交易是最底层的数据,分块链是存储的各种交易内容,然后主链存储的是分块链中的核心数据(后面提到的collation header)。

在上图中,还有个Period的概念,这个的目标是为了在一定时间后更新分片中的验证节点。目前定义一个period_length(周期长度)是5个区块,即每5个区块就会更新下分片的验证节点。

对比图如下:

cmp

校对块

每个分块的数据叫做collation(有些人翻译成校对块),其中校对块是由一些collator(校对人)进行校验,判断正确后,将相关的collation header(校对块头)写入到主网链中。

校对块的结构如下所示

structure

  • shard_id就是分片的id序号,目前以太坊准备设计100个分片
  • expected_period_number是collation(校验块)期待被包含的进的周期序号。如分片所说,一个period=floor(block.number/period_length)
  • Period_start_prevhash指的是上一个周期的最后一个区块hash
  • parent_collation_hash指的是上一个collation的hash(一个周期中的同一个分片可能会有多个collation,当然也有可能是前一个周器中的本分片的collation的hash。总之就是本分片的最后一个打包进去的collation的hash)
  • tx_list_root就是指的本collation所有交易树的根。
  • coinbase本collation生成者的地址。
  • post_state_root指执行完本collation的所有交易之后,最新的状态树的根,和之前的区块链的状态根含义是一致的。
  • Receipt_root指收据树的根hash
  • sig签名
  • Transaction List 就是打包进本分片的交易内容

此外,根据分片doc文档所描述,在collation header中有个number,指的是collation number,含义根据理解,应当等同于blockchain中的number或者height,也就是分片中校验块的高度。根据官网描述,本含义也是在进行分叉选择规则时所需要参考的数值(后叙会提到)。

打包入主网链

目前以太坊的分片使用一个VMC(validator manager contract),功能是用来进行分片管理的,暂时不进行详细描述。将校验块打包入主网时,会有一系列流程。

首先会调用VMC的一个addHeader方法。会做以下判断:

  • shard_id符合要求,不能超过总的数目,目前定义是最多100个分片
  • Ecpected_period_number符合要求,满足前面提到的计算公式
  • parent_collation_hash和Period_start_prevhash都已经验证通过了,换句话描述就是这两个都已经被接受了。(目前PoW实际不是最终显示一致性的,但是以太坊的Casper声称已经结合PoS以及BFT做到了一致性,论文需要后续研读)
  • 本collation不能重复(和以太坊1.0验证是一样的)
  • 本collation的提交者,或者叫collator是属于本分片的。(如何为每个分片选择合理的集合很重要)

其次,会判断本校验块结果是否正确。由于在验证校验块头(collation header)时验证了parent_collation_hash已经存在并默认正确,本步会验证parent_collation_hash所对应的state_root和receipt_root执行本collation里面的交易得到的结果,是否会和本collation header中的state_root和receipt_root是否一致

最后会验证是否符gas要求。

以上验证通过,会将本collation header写入主网的区块中。

合法链选择原则

以太坊1.0存在分叉,2.0也不可避免的会存在分叉。因此,需要考虑在存在分片的情况下,如何选择最合理的链。

最基本的原则是依赖最长主链,但是有一定的改动。

如下图所示:

img

毫无疑问,选择的是B3这条链,选择的也是里面的分片数据。

假设现在有一个B3'连接到了B2'

img

此时,假设B3'的分数没有B3所在的链大(分数指的是校验块的分数,即上面提到的number)

现在假设有了一个最新的区块B4'连接到了B3',如下所示

img

很明显,B4'所在的链虽然分片的总分数不是最大,但是主链长度最长,所以依然选择B2'的分片为合理的分片数据。

综上,选择合理的链的时候,优先看链的长度,在长度一致的时候,优先选择分数最大的链。

collator选择

在全网进行数据共识时,PoW的攻击者需要51%的算力才能攻击成功,现在进行分片后,如果没有设计合理的分片方法,有可能会将恶意节点分到同一个分片中或者恶意节点提前准备,进入同一个分片,系统的安全性会大大降低。也就是1%攻击

img

为了防止此类问题,一个不可提前预知的,人为难以干预的,可以被验证的分片校验验证节点选取算法非常有必要。

在sharding doc上,提出了一个简单的节点选取算法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def getEligibleProposer(shardId: num, period: num) -> address:
    assert period >= LOOKAHEAD_LENGTH
    assert (period - LOOKAHEAD_LENGTH) * PERIOD_LENGTH < block.number
    assert self.num_validators > 0

    h = as_num256(
        sha3(
            concat(
                blockhash((period - LOOKAHEAD_LENGTH) * PERIOD_LENGTH),
                as_bytes32(shardId)
            )
        )
    )
    return self.validators[
        as_num128(
            num256_mod(
                h,
                as_num256(self.num_validators)
            )
        )
    ].addr

可以看到,大体的算法是使用区块哈希+分片ID生成基本数据,然后从节点集合里面取模计算,获取合理的节点。可以看到,这个方式能够防止提前计算,还可以被合理验证。

同步

根据前面的了解,我们知道每个分片的验证节点每隔一个period是会变化的,所以在period_1的shard_1的节点集合V_1经过验证,进入period_2后,shard_1的节点集合是V_2,V_2并没有之前的数据(这个更新节点集合流程叫做reshuffling),需要考虑怎么验证数据正确性。在2.0的设计上,此类节点叫做无状态客户端。(需要进一步阅读,确定这一理解是否正确)

img

现在矿工发送了一个新的交易区块B,验证者存有在这个区块之前的state_root。为了让验证者不需要存储所有的以往交易数据,旷工在发送交易区块B时,附带一个证据W,这个证据的内容是区块B中修改的数据的merkle证明。这样验证者验证证据的合法性,然后通过证据验证区块的合法性,最终区块通过。

只是,这个流程存在一定的问题:

  1. 证据谁来生成?而且,在发布交易时的merkle树和在打包交易时可能不一致,已经发生了变化。为了解决这个问题,可以让矿工保存过去24小时的数据,然后可以修改证据W,这样就解决了交易的问题。
  2. 状态谁来存储?以为最后,为了完整的验证,还是需要节点去判断交易的正确性,需要同步数据来判断结果。官方research提出有几种解决办法:
    1. 由全节点提供,默认保存一定时间;
    2. 用户掏钱,让别的节点来存;
    3. 用户自己存;
    4. 设计专门的存档节点;

对于问题1,有些建议矿工不需要存储24小时,因为会影响默克尔根的时间,只有从发布交易到交易入块这段时间。作者考虑到在一些极端场景下,如果交易延迟比较大,会失去内容,所以不建议过短。

其他

根据目前在网上的了解,以太坊2.0的进展目前在phase 1,还在做基本的分片,对于更新的分片之间的通信,暂时还没有新的进展。

后续的内容包括双向锚定、collation header的处理方式、数据可用性证明等等。