1 简介
bsc-relayer 是一个独立进程,可单独运行,运行时首先会向 BSC 查询是否注册过,如果没有,则会自动在 BSC 上注册,需要 deposit 100 BNB(目前合计约 22 大不溜多软妹币......),注册成功后,该 bsc-relayer 的信息被记录在 BSC 上名叫 RelayerHub.sol
的 solidity 系统合约中,之后就可以执行中继的服务了。
bsc-relayer 主要有两个功能:
- 拉取 BC 的块头,并同步给 BSC
- 拉取 BC 的跨链数据包,并同步跨链数据包给 BSC
BSC 上存在 solidity 两个系统合约(除了这两个还有其它的系统合约),分别为 TendermintLightClient.sol
和 CrossChain.sol
,bsc-relayer “同步块头” 的操作会调用 BSC 的 TendermintLightClient.sol
,“同步跨链数据包” 的操作会调用 BSC 的 CrossChain.sol
。
除此之外,bsc-relayer 还有部分其它的功能,例如本地查询状态,tx 追踪等,这边暂时不进行详细介绍了。
2 bsc-relayer 与 BC、BSC 的连接通道
bsc-relayer 与 BC、BSC 均通过 RPC 进行通信,RPC 的信息记录在 config/config.json 文件下。
-
bsc-relayer <-----> BC
bsc-relayer 通过发送不同的请求信息获取 BC 上的数据,例如abci_info
、block
等。 -
bsc-relayer <-----> BSC
bsc-relayer 直接使用了 Etheruem 提供的 RPC 模块,可直接调用发送数据或者请求,其中最常用的是eth_sendRawTransaction
进行交易的发送(用来调用前文提到的两个合约TendermintLightClient.sol
和CrossChain.sol
)。
3 拉取、同步跨链数据包
3.1 拉取跨链事件 info
bsc-relayer 会一直轮询每个高度的 BC 块的所有 跨链事件,事件的格式如下:
{
"type": "IBCPackage",
"attributes":
[
{
"key": "IBCPackageInfo",
"value": "96::8::19"
}
]
}
其中:
- type 为 "IBCPackage",表示跨链包;
- key 为 "IBCPackageInfo",表示跨链包的信息;
-
value 通过“::”分隔为3个字段,分别为
CrossChainID of destination chain
、channel id
、sequence
;
-
CrossChainID
对于 bsc-relayer 来说,srcCrossChainID 为 BC 的 ChainID,destCrossChainID 为 BSC 的 ChainID。 -
channel id
channel id 为跨链调用 BSC 系统合约(solidity)的 id,bsc-relayer 中包含有以下 4 个 id:
channel | id | contract | address |
---|---|---|---|
BIND_CHANNELID | 0x01 | TokenManager.sol | 0x0000000000000000000000000000000000001008 |
TRANSFER_IN_CHANNELID | 0x02 | TokenHub.sol | 0x0000000000000000000000000000000000001004 |
TRANSFER_OUT_CHANNELID | 0x02 | TokenHub.sol | 0x0000000000000000000000000000000000001004 |
STAKING_CHANNELID | 0x08 | BSCValidatorSet.sol | 0x0000000000000000000000000000000000001000 |
-
sequence
每个 channel id 都对应有一个 sequence,用来计数。
(BSC 相关系统合约逻辑将在后续章节中进行介绍)
3.2 拉取跨链事件 payload
bsc-relayer 根据 channel id
和 sequence
组合生成唯一标识,通过 RPC 向 BC 请求对应的 payload
,这些 payload
以 bytes 的形式传到 bsc-relayer。
3.3 同步
bsc-relayer 将上述的 payload 生成调用 CrossChain.sol
的 tx ,通过 RPC 发送到 BSC。
4 拉取、同步 BC 块头
bsc-relayer 拉取的是 BC 的块头,BC 的块头本质上是 Tendermint 块头,这里就不得不先介绍一下 Tendermint 的相关特性了:
In Tendermint, validators agree on a block before processing it. This means that the signatures and state root for that block aren't included until the next block. Thus, each block contains a field called LastCommit, which contains the votes responsible for committing the previous block, and a field in the block header called AppHash, which refers to the Merkle root hash of the application after processing the transactions from the previous block. So, if we want to verify the AppHash from height H, we need the signatures from LastCommit at height H+1. (And remember that this AppHash only contains the results from all transactions up to and including block H-1)
上文的大概意思是说,一个块的 状态 和 签名 等数据需要至少等到下一个块才能得到,所以如果需要验证高度为 H 的块,需要等到高度为 H+1 的块的 LastCommit
信息(声明一下,本人不是很了解 Tendermint 的算法,如果某些地方说的不正确请及时指明)。
bsc-relayer 拉取 BC 块头的行为完全是 自身驱动 的,当出现以下两种情况时进行触发:
-
BC validator 集合更新
BC 本地会定期更新 bc-validator 集合,BSC 需要获取每一轮的 bc-validator 集合信息,用于验证跨链数据,bc-validator 集合信息包括所有 bc-validator 的账号、公钥、投票(VotingPower)等。
bsc-relayer 会一直轮询每个高度的 BC 块的 bc-validator 集合是否发生变化(包括当前正在工作的 bc-validator 集合和下一轮即将更新的 bc-validator 集合),如果发生变化,则会打包 当前工作的 bc-validator 集合信息、下一轮更新的 bc-validator 集合信息、当前查询的 BC 高度的块头,将其生成调用TendermintLightClient.sol
的 tx,并发送到 BSC。 -
查到跨链数据包
bsc-relayer 会一直轮询每个高度的 BC 块是否有跨链数据包,如果在高度 H 查到了跨链数据包,如前文所述,则会先打包高度为 H+1 的块头 和 validator 集合信息,将其生成调用TendermintLightClient.sol
的 tx,并发送到 BSC。
5 gas 问题
上述可知 bsc-relayer 会不停向 BSC 发送交易,相当于中继自己出 gas 进行工作。为了弥补这一损失,BSC 会在 RelayerIncentivize.sol
系统合约中向 bsc-relayer 发放系统 reward,reward 应该会远高于扣掉的 gas,否则就亏本 gg 了。
6 总结
bsc-relayer 作为中继,不参与处理具体的数据结构,只是作为数据的监控者和搬运工。