Terminology:
@H_403_9@Consensus
Proposer 必须在每个 round中连续不断的为consensus 生成 block prorosal。
istanbul BFT 包括 3 个阶段的共识:PRE-PREPARE,PREPARE,COMMIT。
容错机制: N = 3F +1 ;N表示验证节点,F表示错误节点。
在每轮之前将会以循环的方式选择一个 validator 作为 proposer. 接着 proposer将会提出一个新的 block proposal 并且广播通过 pre-prepare 消息。一旦接受到 pre-prepare消息 ,validators将会进入到 pre-prepared 阶段并且广播 prepare 消息。这个步骤是为了确保 validators 运行在相同的 sequence 和相同的 round 中。当接收到2F+1 的Prepare消息时,validators 进入到 prepared并且广播 commit 消息。此步骤是通知其它节点接受建议的块并将块插入链。 最后,validator等待2F + 1 COMMIT消息进入COMMITTED状态,然后将块插入链。
注意:Istanbul中 的块是最终的,没有分叉,任何有效的块必须位于主链的某个位置。
为了防止故障节点从主链生成完全不同的链,每个验证器将2F + 1个接收到的COMMIT签名附加到标头中的extraData字段,然后将其插入链中, 因此,块是可自我验证的,并且也可以支持轻客户端。但是,动态extraData会导致块哈希计算出现问题。由于来自不同验证器的相同块可以具有不同的COMMIT签名集,因此同一块也可以具有不同的块散列。 为了解决这个问题,我们通过排除COMMIT签名部分来计算块哈希。 因此,我们仍然可以保持块/块哈希一致性,并将共识证明放在块头中。
Consensus states
Istanbul BFT是一种状态机复制算法。 每个验证器都维护一个状态机副本,以达到块一致性。
States:
@H_403_9@NEW ROUND
: Proposer发送新的 block proposal。 Validator等待PRE-PREPARE消息。PRE-PREPARED
:验证器已收到PRE-PREPARE消息并广播PREPARE消息。 然后它等待2F + 1 个PREFARE或COMMIT消息。PREPARED
: 验证器已收到2F + 1个PREPARE消息并广播COMMIT消息。 然后它等待2F + 1 COMMIT消息。COMMITTED
:验证器已收到2F + 1个COMMIT消息,并能够将建议的块插入区块链。FINAL COMMITTED
:新块已成功插入区块链,validator 已准备好进入下一轮。ROUND CHANGE
:验证器正在等待同一个建议的轮数上的2F + 1个ROUND CHANGE消息。State transitions
NEW ROUND
-> PRE-PREPARED
:
@H_403_9@
PREPARE
消息给其他validatorsPRE-PREPARED
-> PREPARED
:
@H_403_9@
COMMITTED
-> FINAL COMMITTED
:
@H_403_9@
FINAL COMMITTED
-> NEW ROUND
:
@H_403_9@
Round change flow
@H_403_9@PREPREPARE
消息Proposer selection
目前我们支持两种策略:round robin 和 sticky proposer.。
@H_403_9@Validator list voting
我们使用与Clique类似的验证器投票机制,并复制Clique EIP的大部分内容。 每个epoch交易都会重置验证器投票,这意味着如果授权或取消授权投票仍在进行中,则投票过程将被终止。
对于所有交易块:
@H_403_9@Future message and backlog
在异步网络环境中,可以接收将来无法在当前状态下处理的消息。 例如,验证器可以在NEW ROUND上接收COMMIT消息。 我们将此类消息称为“未来消息”。 当验证程序收到将来的消息时,它会将消息放入其待办事项中,并尽可能在稍后尝试处理。
Optimization
为了加速共识过程,在接收PREFARE消息的2F + 1之前接收到2F + 1 COMMIT消息的验证器将跳转到COMMITTED状态,这样就不必等待进一步的PREPARE消息。
@H_911_301@Constants我们定义以下常量:
@H_403_9@EPOCH_LENGTH
:检查点和重置待处理投票之后的块数。
@H_403_9@
REQUEST_TIMEOUT
: 在以毫秒为单位进行轮次更改之前,每个达成一致的超时。BLOCK_PERIOD
: 两个连续块之间的最小时间戳差异(秒)。PROPOSER_POLICY
:提议者选择策略,默认为round robin.。ISTANBUL_DIGEST
:固定的 magic number, 0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365用于Istanbul块识别的块头中的mixDigest。DEFAULT_DIFFICULTY
: 默认块难度,设置为0x0000000000000001。EXTRA_VANITY
: 固定数量的额外数据前缀字节预留给提议者。
@H_403_9@
NONCE_AUTH
: magic nonce number 0xffffffffffffffff投票添加验证器。NONCE_DROP
:magic nonce number 0x0000000000000000 投票移除验证器UNCLE_HASH
:总是Keccak256(RLP([]))作为叔叔在PoW之外没有意义。PREPREPARE_MSG_CODE
: 固定编号0. PREPREPARE消息的消息代码。COMMIT_MSG_CODE
: 固定编号1. COMMIT消息的消息代码。ROUND_CHANGE_MSG_CODE
:固定号码2. ROUND CHANGE消息的消息代码。我们还定义了以下每块常量:
@H_403_9@BLOCK_NUMBER
: 链中的块高度,其中生成块的高度为0。N
: 授权验证人数。F
:允许的错误验证器数量。VALIDATOR_INDEX
:当前授权验证器的排序列表中的块验证器的索引。VALIDATOR_LIMIT
: 传递授权或取消授权提议的验证者数量。
@H_403_9@
Block header
我们没有为伊斯坦布尔BFT发明新的块头。 相反,我们跟随Clique重新调整ethash标头字段,如下所示:
@H_403_9@beneficiary
: 建议修改验证器列表的地址。
nonce
:关于受益人领域定义的帐户的提议者提案。
mixHash
: 固定 magic number 0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365 用于伊斯坦布尔区块识别
ommersHash
:必须是UNCLE_HASH,因为在PoW之外,叔叔没有意义。
timestamp
:必须至少是父时间戳+ BLOCK_PERIOD
difficulty
:必须填写0x0000000000000001。
extraData
: 签名者和RLP编码的伊斯坦布尔额外数据的组合字段,其中伊斯坦布尔额外数据包含验证器列表,proposer seal和 commit seal。 伊斯坦布尔的额外数据定义如下:
type IstanbulExtra struct {
Validators []common.Address //Validator addresses
Seal []byte //Proposer seal 65 bytes
CommittedSeal [][]byte //Committed seal,65 * len(Validators) bytes
}
因此extraData将采用EXTRA_VANITY |的形式 ISTANBUL_EXTRA其中| 表示用于分隔vanity和伊斯坦布尔额外数据的固定索引(不是分隔符的实际字符)。
@H_403_9@Validators
: 验证器列表,必须按升序排序。Seal
: 提议者的header seal 签名。CommittedSeal
:提交的签名列表作为共识证明Block hash,and committed seals
由于以下原因,Istanbul块哈希计算与ethash块哈希计算不同:
- 提议者需要将提议者密封在extraData中以证明该块由所选提议者签名。
- 验证者需要将2F + 1个已提交的密封作为extraData中的共识证明,以证明该块已经达成共识。
计算仍然类似于ethash块哈希计算,但我们需要处理extraData。 我们按如下方式计算字段:
Proposer seal calculation
在提议者密封计算时,committed的密封仍然是未知的,因此我们计算密封与那些未知的密封空。 计算如下:
@H_403_9@Proposer seal
: SignECDSA(Keccak256(RLP(Header)),PrivateKey)
PrivateKey
: Proposer's的私钥Header
: 和ethash 的header一样,只不过extradata不一样extraData
: vanity | RLP(IstanbulExtra)
,在IstanbulExtra,
CommittedSealand
Seal` 是空数组.Block hash calculation
在计算块哈希时,我们需要排除已提交的密封,因为该数据在不同的验证器之间是动态的。 因此,我们在计算哈希时使CommittedSeal为空数组。 计算如下:
@H_403_9@Header
: 和ethash 的header一样,只不过extradata不一样extraData
: vanity | RLP(IstanbulExtra)
,CommittedSealand
Seal` 是空数组.Consensus proof
在将块插入区块链之前,每个验证器需要从其他验证器收集2F + 1个已提交的密封以构成共识证明。 一旦它收到足够的提交密封,它将填充IstanbulExtra中的CommittedSeal,重新计算extraData,然后将块插入区块链。 请注意,由于已提交的密封可能因不同的来源而不同,因此我们会在计算块哈希时排除该部分,如上一节所述。
Committed seal calculation:
committed seal由每个签名哈希的验证器以及其私钥的COMMIT_MSG_CODE消息代码计算。 计算如下:
@H_403_9@Committed seal
: SignECDSA(Keccak256(CONCAT(Hash,COMMIT_MSG_CODE)),PrivateKey)
.CONCAT(Hash,COMMIT_MSG_CODE)
: 连接 block hash and COMMIT_MSG_CODE
bytes.PrivateKey
: 签署验证者的私钥。Block locking mechanism
引入锁定机制以解决安全问题。 通常,当提议者用块B锁定在某个高度H时,它只能为高度H提出B.另一方面,当验证器被锁定时,它只能在B上投票选择高度H.
Lock
锁定锁(B,H)包含一个块及其高度,这意味着它的所有验证器当前被锁定在某个块B和高度H.在下面,我们还使用+表示多于和 - 表示小于。 例如,+ 2/3验证器表示超过三分之二的验证器,而-1/3验证器表示不到三分之一的验证器。
Lock and unlock
@H_403_9@Protocol (+2/3
validators are locked with Lock(B,H)
)
@H_403_9@
PRE-PREPARE
:
Proposer:
@H_403_9@情况1,提议者被锁定:在B上广播PRE-PREPARE,并进入PREPARED状态。
情况2,提议者未被锁定:在块B'上广播PRE-PREPARE。
Validator:
@H_403_9@PREPARE
:
+2/3
validators are locked on B
and which would lead to round change.COMMIT
:
Locking cases
@H_403_9@+2/3
are locked:
@H_403_9@
+1/3 ~ 2/3
are locked:
@H_403_9@
-1/3
are locked:
@H_403_9@
Gossip network
传统上,验证者需要紧密连接才能达到稳定的共识结果,这意味着所有验证者需要彼此直接连接; 但是,在实际的网络环境中,很难实现稳定和恒定的p2p连接。 为了解决这个问题,伊斯坦布尔BFT实施了八卦网络来克服这种限制。 在八卦网络环境中,所有验证器只需要弱连接,这意味着当它们直接连接或者它们之间连接有一个或多个验证器时,任何两个验证器都会被连接。 共识消息将在验证器之间中继。