中继语义
本文档旨在帮助开发者实现替代的 Peggy 中继器。Orchestrator
的两个主要组件与 Ethereum 进行交互。Peggy 桥接的设计侧重于提高效率,而非易用性。这意味着,外部二进制文件有许多隐含的要求,本文档尽力将这些要求明确化。
Peggy Orchestrator
结合了在 Peggy 桥接中需要由外部二进制文件执行的三个不同角色。本文档重点介绍了作为 Orchestrator
一部分的中继器角色的要求。
验证者集更新中继的语义
验证者集和签名的排序与顺序
在更新 Peggy 合约中的验证者集时,必须提供旧验证者集的副本。这个副本 只能 从 Ethereum 链上的最后一个 ValsetUpdated
事件中获取。
提供旧验证者集是存储优化的一部分,代替将整个验证者集存储在 Ethereum 存储中,它由每个调用者提供并存储在更便宜的 Ethereum 事件队列中。Peggy 合约中不执行任何排序操作,这意味着验证者列表及其新签名必须以与上次调用完全相同的顺序提交。
为了正常操作,此要求可以简化为“按降序排序验证者的权重,并在权重相等时按 Ethereum 地址字节排序”。由于 peggy
模块生成验证者集,因此它们应该始终按顺序排列。中继器无法更改此顺序,因为它是签名的一部分。但如果 peggy
模块侧的排序方法发生变化,将会停止验证者集更新,并本质上使桥接断开,除非您的实现足够智能,能够查看最后提交的顺序,而不是盲目遵循排序。
决定中继哪个验证者集
Injective Chain 仅生成一系列的验证者集,并不对它们如何被中继做出任何判断。由中继器实现决定如何优化此中继操作的 gas 成本。
例如,假设我们有验证者集 A、B、C 和 D,每个验证者集是在 peggy
验证者集存储中的最后一个快照与当前激活的验证者集之间存在 5% 权重差异时创建的。
5% 是一个任意常数。这里选择的具体值是链在 Ethereum 验证者集更新的实时性和保持其更新的成本之间做出的折中。这个值越高,投票验证者集所需的比例越低,以在最坏情况下劫持桥接。如果每个区块都进行新的验证者集更新,那么 66% 的验证者需要合谋,而 5% 的变化阈值意味着,在给定的验证者集中,61% 的总投票权合谋可能会窃取桥接中的资金。
中继器应当遍历 Peggy Ethereum 合约的事件历史,确定验证者集 A 当前位于 Peggy 桥接中。它可以选择中继验证者集 B、C,然后是 D,或者仅提交验证者集 D。只要所有验证者都已签署 D,并且它的投票权超过 66%,它就能独立通过,而无需为中继中间集支付可能数百美元的额外 Ethereum gas 费用。
在提交交易之前在本地执行此检查是实现成本效益中继器的关键。您可以使用本地的 Ethereum 签名实现并自行计算权重和签名,或者可以简单地使用 eth_call()
Ethereum RPC 在您的 Ethereum 节点上模拟该调用。
请注意,eth_call()
经常会有一些陷阱。如果没有 Ethereum 来支付 gas,基于 Geth 的实现中的所有调用都会失败,而基于 Parity 的实现则通常会忽略您的 gas 输入,并返回准确的 gas 使用量。
交易批次中继的语义
为了提交交易批次,您还需要提交最后一组验证者及其质押权重。这是为了实现前面提到的相同存储优化。
决定中继哪个批次
决定中继哪个批次与决定中继哪个验证者集非常不同。批次中继主要是由费用驱动,而不是为了维护桥接的完整性。因此,这一决策主要依赖于费用计算,而这一点又被“批次请求”的概念进一步复杂化。批次请求是一个无权限的事务,请求 peggy
模块为特定的代币类型生成一个新的批次。
批次请求的设计目的是允许用户随时从发送到 Ethereum 的交易池中提取他们的代币,直到中继者有兴趣实际中继这些交易为止。当交易仍在池中时,如果用户通过发送 MsgCancelSendToEth
被允许撤回交易,则不存在双重支付的风险。一旦交易因“请求批次”而进入批次,情况就不一样了,用户的资金必须保持锁定,直到 Oracle 通知 peggy
模块,包含用户代币的批次已经变得无效或者已经在 Ethereum 上执行。
中继者使用查询端点 BatchFees
来遍历每个代币类型的发送到 Ethereum 交易池,然后中继者可以观察正在中继的 ERC-20 代币在去中心化交易所(DEX)上的价格,并计算执行该批次的 gas 费用(通过 eth_call()
)以及如果需要的话,在 DEX 上清算收益的 gas 费用。一旦中继者确定一个批次是合适且有利可图的,它可以发送 MsgRequestBatch
,然后该批次会被创建,供中继者中继。
对于现有的批次,中继者也应该评估其盈利性,并使用类似的方法尝试中继。
Last updated