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 A≤B:即意味着 A < B A<B A<B 或 A = B A=B A=B。
- A ∼ B A\\sim B A∼B:即意味着 A < B A<B A<B 或 A = B A=B A=B 或 A > B A>B A>B。
- A ≁ B A\\nsim B A≁B:即为非 A ∼ B A\\sim B A∼B。
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)=B∣B≤T。对于任意的区块 A , B A,B A,B,当且仅当 A ∼ B A\\sim B A∼B时, 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 i≥2 的validator set和block height assignment信息会在epoch index为 i − 2 i-2 i−2的最后一个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 B≤T,意味着 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 T′≥T, 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_id
和signature
不同),因此, 存储所有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 None
if 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_height
s。计时器超时时间取决于俄最后固化区块的高度,该信息也会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 T≥B,要么 B = G B=G B=G,要么block X ≤ T X\\leq T X≤T 使得 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共识机制