NEAR共识机制

Posted mutourend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NEAR共识机制相关的知识,希望对你有一定的参考价值。

1. 引言

NEAR采用PoS共识机制,使用名为NighShade的分片设计,采用名为DoomSlug的区块生成机制。

2. 相关定义及符号

为了维护共识,交易会打包进区块。存在一个preconfigured block G G G,称为genesis block。除 G G G之外,每个block都有a link pointing to the previous block p r e v ( B ) prev(B) prev(B),其中 B B B为block,通过该link最终可连接到 G G G(不存在cycles)。

  • A < B A<B A<B:即意味着 A ≠ B A\\neq B A=B,且 B B B可通过previous block link连接到 A A A
  • A ≤ B A\\leq B AB:即意味着 A < B A<B A<B A = B A=B A=B
  • A ∼ B A\\sim B AB:即意味着 A < B A<B A<B A = B A=B A=B A > B A>B A>B
  • A ≁ B A\\nsim B AB:即为非 A ∼ B A\\sim B AB

chain c h a i n ( T ) chain(T) chain(T):是指a set of blocks reachable from block T T T,称为tips,即 c h a i n ( T ) = B ∣ B ≤ T chain(T)=\\B|B\\leq T\\ chain(T)=BBT。对于任意的区块 A , B A,B A,B,当且仅当 A ∼ B A\\sim B AB时, A , B A,B A,B之间存在a chain。此时,可成 A , B A,B A,B在同一链上。

每个区块都有一个整数height h ( B ) h(B) h(B)。区块高度是单调递增的,即对于任意的区块 B ≠ G B\\neq G B=G,有 h ( B ) > h ( p r e v ( B ) ) h(B)>h(prev(B)) h(B)>h(prev(B))。但不要求区块高度是连续的,如 h ( G ) h(G) h(G)可不为0。每个节点keep track of a valid block with the largest height it knows about, which is called its head。

区块会打包进epoch。在链上,属于同一epoch的一组区块形成连续的范围:若区块 A < B A<B A<B都属于同一epoch,则每个满足 A < X < B A<X<B A<X<B的区块 X X X都属于该epoch。epoch可 以sequential indices来标记: G G G属于index为0的epoch;对于每个block B B B,其所属epoch index要么等于 p r e v ( B ) prev(B) prev(B)的epoch index,要么大于。

每个epoch关联 a set of block producers that are validating blocks in that epoch, as well as an assignment of block heights to block producers that are responsible for producing a block at that height。

负责生产高度为 h h h区块的block producer称为block proposer at h h h

epoch index i ≥ 2 i\\geq 2 i2 的validator set和block height assignment信息会在epoch index为 i − 2 i-2 i2的最后一个block确定。对于epoch index为0和1的情况,其validator set和block height assignment为preconfigured的。因此,若2链共享某epoch的最后一个区块,则其后续2个epoch具有相同的validator set和相同的block height assignment,但是对于再更后的epoch则无法保证。

固化:若block B B B固化了,则任何未来的固化区块都是仅能基于 B B B构建的。因此,在 B B B及之前区块的交易将永远不会被reverse。 f i n a l ( B , T ) final(B,T) final(B,T),其中 B ≤ T B\\leq T BT,意味着 B B B c h a i n ( T ) chain(T) chain(T)上固化了。若 f i n a l ( B , T ) final(B,T) final(B,T)为真,则对于所有的 T ′ ≥ T T'\\geq T TT f i n a l ( B , T ′ ) final(B,T') final(B,T)均为真。

2. Data structures

NEAR区块头中与共识相关的字段有:

struct BlockHeader 
    ...
    prev_hash: BlockHash,
    height: BlockHeight,
    epoch_id: EpochId,
    last_final_block_hash: BlockHash,
    approvals: Vec<Option<Signature>>
    ...

在特定epoch的block producers会交换多种类型的消息,与共识相关的消息有2种:

  • Blocks
  • Approvals

具体包含了以下字段:

enum ApprovalInner 
    Endorsement(BlockHash),//为the hash of the approved block
    Skip(BlockHeight),//为the height of the approved block 


struct Approval 
    inner: ApprovalInner,
    target_height: BlockHeight,//为the specific height at which the approval can be used (an approval with a particular `target_height` can be only included in the `approvals` of a block that has `height = target_height`)
    signature: Signature,//为对`(inner, target_height)`的签名
    account_id: AccountId //为the account of the block producer who created the approval

3. Approvals Requirements

除genesis block之外的每个区块 B B B中,都必须逻辑上包含来自于block producers的approvals,这些block producers的累计stake必须超过该epoch中总stake的2/3。在epoch切换时,要求block producers的累计stake需超过下一epoch总stake的2/3。

approval有2种类型:

  • 当且仅当 h ( B ) = h ( p r e v ( B ) ) + 1 h(B)=h(prev(B))+1 h(B)=h(prev(B))+1时,为Endorsement
  • 否则为Skip with the height of p r e v ( B ) prev(B) prev(B)

存储在区块中的每个approval逻辑上对于每个block producer都是相同的(除了account_idsignature不同),因此, 存储所有approvals是冗余的。事实物理上值存储了signatures of the approvals,具体的存储方式为:

  • 获取当前epoch的block producers ordered set。

若某block在epoch边界,也需要包含approvals form the next epoch,因此需要add new accounts from the new epoch:

def get_accounts_for_block_ordered(h, prev_block):
    cur_epoch = get_next_block_epoch(prev_block)
    next_epoch = get_next_block_next_epoch(prev_block)

    account_ids = get_epoch_block_producers_ordered(cur_epoch)
    if next_block_needs_approvals_from_next_epoch(prev_block):
        for account_id in get_epoch_block_producers_ordered(next_epoch):
            if account_id not in account_ids:
                account_ids.append(account_id)

    return account_ids

因此,该边界block中包含了a vector of optional signatures of the same or smaller size than the resulting set of account_ids, with each element being Noneif the approval for such account is absent, or the signature on the approval message if it is present。因此,很容易根据区块中的信息重构出签名approvals的block producers,并验证相应的签名。若the vector of signature短于account_ids的长度,则剩余的signatures均假设为None

4. Messages

当收到approval消息,参与者仅将其存入the collection of approval messages中:

def on_approval(self, approval):
    self.approvals.append(approval)

当参与者收到一个block,与共识相关的操作有:

  • 更新head
  • 初始化a timer来开始发送该block的approvals给the block producers at the consecutive target_heights。计时器超时时间取决于俄最后固化区块的高度,该信息也会persisted。
def on_block(self, block):
    header = block.header

    if header.height <= self.head_height:
        return

    last_final_block = store.get_block(header.last_final_block_hash)

    self.head_height = header.height
    self.head_hash = block.hash()
    self.largest_final_height = last_final_block.height

    self.timer_height = self.head_height + 1
    self.timer_started = time.time()

    self.endorsement_pending = True

定时器会定期检查如下逻辑:

def get_delay(n):
    min(MAX_DELAY, MIN_DELAY + DELAY_STEP * (n-2))

def process_timer(self):
    now = time.time()

    skip_delay = get_delay(self.timer_height - self.largest_final_height)

    if self.endorsement_pending and now > self.timer_started + ENDORSEMENT_DELAY:

        if self.head_height >= self.largest_target_height:
            self.largest_target_height = self.head_height + 1
            self.send_approval(head_height + 1)

        self.endorsement_pending = False

    if now > self.timer_started + skip_delay:
        assert not self.endorsement_pending

        self.largest_target_height = max(self.largest_target_height, self.timer_height + 1)
        self.send_approval(self.timer_height + 1)

        self.timer_started = now
        self.timer_height += 1

def send_approval(self, target_height):
    if target_height == self.head_height + 1:
        inner = Endorsement(self.head_hash)
    else:
        inner = Skip(self.head_height)

    approval = Approval(inner, target_height)
    send(approval, to_whom = get_block_proposer(self.head_hash, target_height))

其中get_block_proposer返回的下一block proposer。

同时要求ENDORSEMENT_DELAY < MIN_DELAY,尽管不影响正确性,NEAR中要求ENDORSEMENT_DELAY * 2 <= MIN_DELAY

5. Block Production

定义了获取特定高度区块中approvals的函数:

def get_approvals(self, target_height):
    return [approval for approval
                     in self.approvals
                     if approval.target_height == target_height and
                        (isinstance(approval.inner, Skip) and approval.prev_height == self.head_height or
                         isinstance(approval.inner, Endorsement) and approval.prev_hash == self.head_hash)]

只要get_approvals返回的approvals中对应的block producers的累计质押量超过了总质押量的2/3,被指定该高度的产块者即可产块。

6. 固化条件

block B B B固化在 c h a i n ( T ) chain(T) chain(T),其中 T ≥ B T\\geq B TB,要么 B = G B=G B=G,要么block X ≤ T X\\leq T XT 使得 B = p r e v ( p r e v ( X ) ) 且 h ( X ) = h ( p r e v ( X ) ) + 1 = h ( B ) + 2 B=prev(prev(X)) 且 h(X)=h(prev(X))+1=h(B)+2 B=prev(prev(X共识机制

共识机制比较

什么是共识机制?NGK的DPoSS有什么优点?

共识机制是什么?

NEAR Rainbow Bridge代码解析

MEXC Global分享:一文读懂区块链共识机制