1 系统合约
BSC 的核心在于 系统合约(solidity),在 【BSC详解】2——bsc relayer
分析可知,所有的跨链行为都是通过调用系统合约实现的,所以首先介绍一下部署在 BSC 上的系统合约。
system contract name | solidity | Address |
---|---|---|
ValidatorContract | BSCValidatorSet.sol | 0x0000000000000000000000000000000000001000 |
SlashContract | SlashIndicator.sol | 0x0000000000000000000000000000000000001001 |
SystemRewardContract | SystemReward.sol | 0x0000000000000000000000000000000000001002 |
LightClientContract | TendermintLightClient.sol | 0x0000000000000000000000000000000000001003 |
TokenHubContract | TokenHub.sol | 0x0000000000000000000000000000000000001004 |
RelayerIncentivizeContract | RelayerIncentivize.sol | 0x0000000000000000000000000000000000001005 |
RelayerHubContract | RelayerHub.sol | 0x0000000000000000000000000000000000001006 |
GovHubContract | GovHub.sol | 0x0000000000000000000000000000000000001007 |
TokenManagerContract | TokenManager.sol | 0x0000000000000000000000000000000000001008 |
CrossChainContract | CrossChain.sol | 0x0000000000000000000000000000000000001009 |
在 BSC 中系统合约直接通过 solidity 的 Hex code 进行部署。
1.1 预编译合约
在介绍上述系统合约之前,首先需要介绍一下 预编译合约。
预编译合约是 EVM 中用于提供更复杂库函数(通常用于加密、散列等复杂操作)的一种折衷方法,这些函数不适合编写操作码。 它们适用于简单但经常调用的合约,或逻辑上固定但计算量很大的合约。预编译合约是在使用节点客户端代码实现的,因为它们不需要 EVM,所以运行速度很快。 与使用直接在 EVM 中运行的函数相比,它对开发人员来说成本也更低。
在 Etheruem 中已经实现了不少预编译合约了,比如下面这些:
Precompiled contract name | Features | Address |
---|---|---|
ecrecover() | Recovery of ECDSA signature | 0x1 |
sha256hash() | Hash function SHA256 | 0x2 |
ripemd160hash() | Hash function RIPEMD160 | 0x3 |
dataCopy() | Identify | 0x4 |
bigModeExp() | Modular exponentiation | 0x5 |
bn256Add() | Addition on elliptic curve alt_bn128 | 0x6 |
bn256ScalarMul() | Scalar multiplication on elliptic curve alt_bn128 | 0x7 |
bn256Pairing() | Checking a pairing equation on curve alt_bn128 | 0x8 |
在代码层面,所谓的地址实际上是合约数组的索引,每一个索引唯一对应一个预编一个合约。在智能合约代码中,可以像普通合约一样在合约文件中直接调用预编译合约,但调用方式有所不同:
assembly {
if iszero(call(gasLimit, contractAddress, value, input, inputLength, output, outputLength)) {
revert(0, 0)
}
}
总结来说,预编译合约效率更高,成本更低,它们是无状态的,而 solidity 智能合约是有状态的,所以 BSC 使用智能合约保存数据,使用预编译合约进行数据的处理和计算。
BSC 中的预编译合约定义如下:
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
// contracts used in the Istanbul release.
var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{100}): &tmHeaderValidate{},
common.BytesToAddress([]byte{101}): &iavlMerkleProofValidate{},
}
BSC 新增了 tmHeaderValidate
合约和 iavlMerkleProofValidate
合约。
1.1.1 tmHeaderValidate
该合约主要用于验证 BC 块头是否合法,被 LightClientContract
系统合约调用,在后文一同进行讲解。
1.1.2 iavlMerkleProofValidate
该合约主要用于验证 BC 跨链数据包是否合法,被 CrossChainContract
系统合约调用,在后文一同进行讲解。
1.2 系统合约
1.2.1 LightClientContract(TendermintLightClient.sol)
负责执行 bsc-relayer 发送过来的“同步块头”的交易,和 tmHeaderValidate
预编译合约一同工作:
-
LightClientContract
用于保存状态数据
状态数据如下,其中,appHash
字段即为 BC 的根哈希。
type ConsensusState struct {
chainID string
height int64
appHash []byte
curValidatorSetHash []byte
nextValidatorSet *tmtypes.ValidatorSet
}
-
tmHeaderValidate
用于块头的校验
LightClientContract
调用tmHeaderValidate
时,将ConsensusState
和块头作为参数(这里的块头包括块头、当前工作的 bc-validator 集合信息、下一轮更新的 bc
-validator 集合信息,可参考 【BSC详解】2——bsc relayer),tmHeaderValidate
通过ConsensusState
中的nextValidatorSet
校验块头中的 BLS 签名以及投票是否正确,若正确则使用块头的数据更新ConsensusState
,返回给LightClientContract
进行更新保存。
1.2.2 CrossChainContract(CrossChain.sol)
负责执行 bsc-relayer 发送过来的“同步跨链数据包”的交易,和 iavlMerkleProofValidate
预编译合约一同工作:
iavlMerkleProofValidate
用于跨链数据包的校验
跨链数据包中包含两个内容:msg
和merkle proof
,CrossChainContract
调用iavlMerkleProofValidate
时,将 1.2.1 中的appHash
、msg
、merkle proof
,通过默克尔证明算法验证这个msg
时合法的。
这里也说通了为什么在 【BSC详解】2——bsc relayer
中同步跨链数据包前需要先同步块头,因为需要更新appHash
,只有高度 H+1的appHash
才能进行完成高度 H 的msg
的默克尔证明。CrossChainContract
用于调用相关的业务合约
在校验完成后,根据msg
的类型,分别进行其它不同的系统合约的调用,完成相应的业务。
1.2.3 ValidatorContract(BSCValidatorSet.sol)
用于 BC 更新 bsc-validator 集合。
1.2.4 SlashContract(SlashIndicator.sol)
用于惩罚违规操作的 bsc-validator。
1.2.5 SystemRewardContract(SystemReward.sol)
记录 bsc-relayer 的 reward 数据。
1.2.6 TokenHubContract(TokenHub.sol)
用于 BC 与 BSC 的跨链 token transfer。
1.2.7 RelayerIncentivizeContract(RelayerIncentivize.sol)
用于 bsc-relayer claim reward。而 bsc-validator 的 reward 为打包出块的 tx 的 gas。
1.2.8 RelayerHubContract(RelayerHub.sol)
用于记录 bsc-relayer 的注册信息。
1.2.9 GovHubContract(GovHub.sol)
处理来自 BC 上的链上治理数据。
1.2.10 TokenManagerContract(TokenManager.sol)
用于 BC 和 BSC 两边 token 的绑定。
1.2.11 总结
- 对于跨链来说只需要
LightClientContract
和CrossChainContract
两个合约的调用即可,其它的业务操作都是通过CrossChainContract
调用其它的合约实现的。 -
BSC 完全受 BC 管理,bsc-relayer 完全受 BSC 管理。
2 共识
2.1 Parlia
BSC 采用的 PoSA(Proof of Stake Authority) 共识算法。bsc-validator 节点轮流出块,如果出块时间不符合预期或者不符合出块顺序,则相应的节点将会被惩罚。
对于安全性的考量,官方解释如下
Given there are more than 1/2*N+1 validators are honest, PoA based networks usually work securely and properly. However, there are still cases where certain amount Byzantine validators may still manage to attack the network, e.g. through the “Clone Attack”. To secure as much as BC, BSC users are encouraged to wait until receiving blocks sealed by more than 2/3*N+1 different validators. In that way, the BSC can be trusted at a similar security level to BC and can tolerate less than 1/3*N Byzantine validators.
With 21 validators, if the block time is 5 seconds, the 2/3*N+1 different validator seals will need a time period of (2/3*21+1)*5 = 75 seconds. Any critical applications for BSC may have to wait for 2/3*N+1 to ensure a relatively secure finality. However, besides such an arrangement, BSC does introduce Slashing logic to penalize Byzantine validators for double signing or instability. This Slashing logic will expose the malicious validators in a very short time and make the Clone Attack very hard or extremely non-economic to execute. With this enhancement, 1/2*N+1 or even fewer blocks are enough as confirmation for most transactions.
总结来说,对于 轻客户端 无法验证执行块的验证操作,只能被动接收 全节点 的数据,为了避免遭受攻击,只有当一个块后面的 2/3*N+1 个块都接收到了(N 为 bsc-validator 的数量),才能基本保证当前这个块是被确认的、有效的,而 全节点 可以对块进行计算验证,并选择正确的最长链进行延申出块。这个实质上就是 PoW 的最长合法链原则。
2.2 Epoch
Epoch 为更换共识节点的间隔,当前值为 200,也就是说每 200 个 block 会生成 1 个 epoch block。每个 epoch block 出块时,会查询保存在 1.2.3 中 ValidatorContract
合约最新的 bsc-validator 集合信息,并写入 bsc 块头中的 extra_data
字段中。
与 2.1 中对于安全性的考量类似,需要等待一段时间,直到 Epoch block 确认后,才会真正更新全局的 bsc-validator 集合。在 BSC 中,这个等待为 epoch+N/2 个 blocks(N 为 bsc-validator 的数量),在此之后,epoch block 中新的 bsc-validator 集合才会正式变更生效。
参考
https://github.com/bnb-chain/bsc
https://github.com/bnb-chain/bsc-genesis-contract