跨链桥是如何工作的?以Wormhole为例(第一部分)

  • Sec3dev
  • 发布于 2023-01-10 15:28
  • 阅读 19

本文详细介绍了跨链桥的工作原理,以Wormhole为例,解释了其内部机制、操作流程和面临的挑战。分析了跨链信息的处理,包括消息的创建、签名验证、代币转账等重要步骤,展现了跨链技术的复杂性和解决方案。

我们读者可能会对加密黑客造成超过30亿美元的资金损失在2022年感到有些意外。然而,损失大部分发生在跨链桥上(例如,Ronin Network、Wormhole、Nomad、BNB Token Hub、Horizon、Qubit)。

跨链桥为何如此脆弱?难道它们不是经过细致设计或实施的吗?相反,由于其高价值,它们是由一些最好的工程师以尽可能高的标准开发的(例如,leoluk)。真正的原因是跨链桥实在太复杂,涉及太多技术细节。

在本系列文章中,我们将详细阐述跨链桥的内部结构、它们是如何实现的,以及从用户的角度来看它们的注意事项。我们将以一座现代化的桥梁Wormhole为例。

高层次上的跨链桥是什么?

跨链桥只是两个区块链之间的(虚拟)链接,用于消息通信。消息本质上可以是任何位序列(例如,将代币或NFT从链A转移到链B)。

假设你要将比特币从以太坊转移到Solana,你需要做至少两个操作:

  1. 从以太坊的源账户中扣除一个比特币
  2. 向Solana的目标账户充值一个比特币

然而,由于这两个链并不直接通信(用技术术语说:没有办法在单一交易中触碰到两个链),你需要一个中介,拥有这两个链上的比特币,并且可以帮助你完成两个步骤:

  1. 从你的源账户接收比特币到他们在以太坊上的账户
  2. 从他们在Solana上的账户向你的目标账户发送比特币(或等值代币)

跨链桥就是这样一个中介。这里有几个挑战:

  • 跨链桥如何确保这两个步骤原子性发生(即:要么都成功,要么都失败)?如果其中一个成功但另一个失败,那么要么是你,要么是桥会损失资金。
  • 跨链桥如何确保相同的消息被传递(即:只有一个比特币,而不是一个狗狗币或任何其它币,或两个比特币,且是发送到你的目标账户,而非任何其他人的账户)?
  • 跨链桥如何确保相同的消息仅传递一次(例如,他们在Solana上的账户绝不会重复向你的目标账户发送)?

Web3研究人员提出了多种不同的解决方案来应对这些挑战(有不同的权衡)。例如,多重签名验证者、多方计算(MPC)、rollup和乐观桥等。见互操作性三难题的精彩总结。

我们将重点解释一种基于守护者的代表性解决方案(即,一种多重签名验证者),它被Wormhole使用。

高层次上Wormhole是如何工作的?

截至2023年1月,Wormhole能够桥接包括以太坊、Solana、Binance Smart Chain、Polygon、Aptos等20条不同链。

它通过运营一个称为守护者的19节点网络(查看所有19个守护者地址),以及在每条链上部署的多个智能合约(包括核心桥合约、代币桥合约和NFT桥合约)。核心桥合约提供了发出消息、验证守护者签名等功能。代币和NFT桥合约分别负责转移代币和NFT。

这19个守护者不断观察Wormhole核心桥合约发出的消息,并对这些消息进行签名(例如,“Alice刚刚在以太坊上给Wormhole发送了一个比特币,她想让Wormhole把一个比特币发送给Solana的Bob”这样的消息)。

这些守护者的权重相等。当其中一个超大多数(2/3)的他们对某条消息签名时,守护者网络产生一个验证者行动批准VAA,这作为Wormhole在目标链上交付相同消息的证明(例如,将比特币发送到Solana的Bob)。

VAA:Wormhole的核心技术组件

VAAs是所有Wormhole技术细节的核心。有一些疑问,热心的读者可能会想了解:

  • 一个VAA包含什么信息?VAA的格式到底是什么?
  • VAAs是如何使用的?它们存储在哪里?如何获取它们?
  • 从用户的角度来看,跨链消息的端到端工作流程是什么?完成一条消息需要多少交易(即:从源链发送到目标链接收)?
  • 如何验证守护者签名(以防假VAA)?如果一个(恶意)守护者对相同消息多次签名并产生多个签名怎么办?
  • 如何确保桥接的两个链上的代币是相同(或等值)的?如果Wormhole在目标链上没有与用户在源链上发送的相同代币(或足够数量)怎么办?
  • 谁将在目标链上执行消息交付步骤(因为这需要支付交易费用)?
  • 如何防止相同的VAA在目标链上被使用两次?

接下来,我们将逐一回答这些问题(必要时附上代码示例)。

VAA的格式和内部结构

每个VAA被编码为一个字节数组,包含两部分 - 头部和主体。

  • 头部. 头部包含关于守护者及其签名的信息:
类型 字段 描述
byte version VAA版本
u32 guardian_set_index 指示哪个守护者组在签名
u8 len_signatures 存储的签名数量
[][66]byte signatures ecdsa签名集合
  • 主体. 主体包含关于消息的详细信息(例如,源交易的时间戳、emitter_chainemitter_addresssequence以及消息的payload):
类型 字段 描述
u32 timestamp 发生源交易的区块时间戳
u32 nonce 一个分组编号
u16 emitter_chain 触发合约的Wormhole ChainId
[32]byte emitter_address 触发合约地址,以Wormhole格式
u64 sequence 与触发地址和链关联的严格递增序列
u8 consistency_level 在发出此消息之前达到的最终性水平
[]byte payload VAA消息内容

特别是,sequence是确保每个VAA对于消息都是唯一的重要信息(即:两个不同的消息即使消息内容相同也会有不同的VAA)。

sequence数字在每次publishMessage调用中由useSequence函数增加1

这是保证相同消息永远不会被双重交付的关键。我们将在下一部分中进一步详细说明这一点。

payload字节数组包含消息内容。例如,对于一个代币Transfer,它包括转移金额、代币地址、代币链、收件人地址、目标链ID、转移费等:

struct Transfer {
    // PayloadID uint8 = 1
    uint8 payloadID;
    // Amount being transferred (big-endian uint256)
    uint256 amount;
    // Address of the token. Left-zero-padded if shorter than 32 bytes
    bytes32 tokenAddress;
    // Chain ID of the token
    uint16 tokenChain;
    // Address of the recipient. Left-zero-padded if shorter than 32 bytes
    bytes32 to;
    // Chain ID of the recipient
    uint16 toChain;
    // Amount of tokens (big-endian uint256) that the user is willing to pay as relayer fee. Must be <= Amount.
    uint256 fee;
}

VAAs是如何使用的?它们存储在哪里?

一旦产生了VAA(即,一条消息经过2/3守护者的签名),它将存储在守护者网络中(可能会存放很长时间或甚至永久)。

每个VAA通过其emitterChainemittedAddresssequence唯一索引,并可以通过此信息查询守护者节点(通过RPC API)来获取:

// 从Wormhole网络获取signedVAA(这可能需要重试以等待确认)
const { signedVAA } = await getSignedVAA(
  WORMHOLE_RPC_HOST,
  CHAIN_ID_ETH,
  emitterAddress,
  sequence
);
b, err := s.db.GetSignedVAABytes(db.VAAID{
  EmitterChain:   vaa.ChainID(req.MessageId.EmitterChain.Number()),
  EmitterAddress: addr,
  Sequence:       req.MessageId.Sequence,
})

例如,一个RPC查询https://wormhole-v2-mainnet-api.certus.one/v1/signed_vaa/2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/99139

{
  "EmitterChain": "ethereum",
  "EmitterAddress": "0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585",
  "Sequence": "99139",
}

将返回以下VAA字节:

{"vaaBytes":"AQAAAAINAAOuz9Ep03HIS1T2ypAoahT/BO2UBHpRWxiA1CfnlUUKVvMnPyR+E4Eusb1JkHivpoi6mBcEUvDkGW/bOThL7hoAArNvvcthq87MTGsQHjReeIIL0o3G0Epg/kT438O3GzDtZki5wlZ5YpRbuISJlT3nB7x8fYsxNUpJFAhO1DOyHj8BA3XfOUc2I0oIbQF8waRjl27BQQJsexBmNvXyT9XWJEwoXqq5hSQ+tf/0AUuGwHQ9ae84ENBpxyQhgfLxjqm3YAoBBAlFk8Rj/3Am5ULZUZGpGuoghigwNpCH8/OQLq9KEpxYXgTVecr9yznjvlw8PeerhjSUvgjjEuoT6bMV9WWHhPYBBaJOC3wrK3Lp6fbTcLlkRxJqjLPWeu6I33a3BKSAbJtcRAdm40CWwX5t0Kgt5EadmrvIRLIiKu0w037ok9nZUdIABocfns7u1MOoYaUdozFdyd2yJauIXNtAHrhHWE7QXq2XCITt6LK3qSGex9kwZhVeQVxfbplphKDS4ecDEo3l7/UBDLx+py+3KJWOByFPE5ZSBvimJ3GL3KOARgXM13+FvZxDL4tbeil+im9nVEb2J0J7dFBSPAnIP6+6QXkGtMK2Tx8BDTItV66QzmT4wQ9Io6Is+X7xjjhWIThkoPkUVHxqcLQjId1fOs69sd1KuXRt7Fi7TTVb7+OcPh15Uwkx1U5gAH8BDkJ4qZNL3y0gd7hFBLs57NxUPMljmdgbADS2uv5M7i0icdW9AUYxkY3mJXhUlKeS40VFMBAONKnwiIxfAgO/MXsAD/U/vytJGBHNrXO/OSC/Kkc8rH9h57pzUD2gBRULRjTUW4hL9iOULd6HbjYTW9F/U+jqh1SLktILvXS70c+gQnUAEB6M8654Oi/bCoChGFc1/vfDed0n5e9geecJvXz9fIHgMQG561i9aYmhoYtaAPrwW0NV0WweUJBZr3sgD9Yxm0YBEekZvilyWm03vf1/1WiOU6HO15FBQGb8xKyUIEp9BtuWTHAEy3rRe7KfC2grX8XvxBiUK8RDw2kc3M3udKt6nv4AEjivx2qzCoyUcvDJ2GaotcyiWRbZSYfd67PdeNDtlQhyOtD3eGxqKDC8UfxdS/LiTpLVY6sTG7P3TmXm6RBzko0BY7o2y1grAQAAAgAAAAAAAAAAAAAAAD7hiyIUr/lwANl0z2R+fDR+j6WFAAAAAAABg0MBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmwGdAAAAAAAAAAAAAAAAwCqqObIj/o0KDlxPJ+rZCDx1bMIAAv3Kt+tcG5vAryvnKh9emBXjIeGPLemctNwQfsx3bVQvAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJrHQ=="}

对应从以太坊到Solana的0.1 WETH的转移($128.15):

图1:从以太坊到Solana的0.1 WETH的代币转账,见Wormhole交易

跨链消息的端到端工作流程

任何人都可以查询守护者节点,返回的VAA字节可以由任何人提交到目标链以完成消息(例如,向VAA中编码的接收地址铸造比特币)。

考虑图1中的消息“从以太坊到Solana的0.1 WETH的代币转账”。从用户的角度来看,实际上涉及五个链上交易(在以太坊上一个,在Solana上四个),顺序如下:

Tx1 (0x6539) wrapAndTransferETH在以太坊

用户0x4f98通过调用wrapAndTransferETH,将0.1 WETH发送到Wormhole代币桥0x3ee1,并带有指定接收链(Solana 0x01)、接收者(0xfdca,在Solana上以base58编码为7vfC)、仲介费(即,如果使用则为中继费用)和nonce的参数:

Tx1 0x6539 在以太坊上调用了wrapAndTransferETH

Tx1内部会调用Wormhole核心桥0x98f3,发出包含sequencenoncepayloadconsistencyLevel等信息的消息,如下所示:

守护者观察到上面所示的消息,并产生一个VAA(AQAA…),如图1所示。

接下来,从守护者网络获取VAA并用于调用Solana的Wormhole核心桥合约。

Tx2 (5CVY)Tx3 (46tG) VerifySignatures在Solana上

SolanaWormhole核心桥上通过签名者HZBb调用VerifySignatures函数,使用VAA创建SignatureSet58Ui

该交易还调用预编译的Secp256k1 SigVerify程序验证VAA中的守护者签名。

VAA总共包含13个签名。由于在Solana上的计算限制,Wormhole将这些签名的验证分成两次交易。

  • Tx25CVY)验证七个签名:
00 ff 01 02 03 04 05 ff ff ff ff ff 06 ff ff ff ff ff ff
  • Tx346tG)通过验证其他六个签名更新SignatureSet58Ui
ff ff ff ff ff ff ff ff ff ff ff ff ff 00 01 02 03 04 05

Tx45AoD)PostVAA在Solana上

在验证了VAA中的所有签名之后,便可以调用PostVAA函数来创建消息账户31Np,该账户唯一标识转移的消息:

pub message: Mut<PostedVAA<’b, { AccountState::MaybeInitialized }>>,

另外两笔交易3goiZpYN也成功调用了PostVAA,但是,因为消息账户是PDA,所以它只会在Tx45AoD)中首次初始化。

PostVAA函数中会检查2/3的法定人数:

signature_count > 2/3 guardian_set.keys.size

Tx54p4q)CompleteWrapped在Solana上

最后,在Wormhole代币桥(wormDTUJ)上调用了CompleteWrapped函数以完成转移。

接收者0xfdca实际上是Solana上由4Kt8拥有的一个关联代币账户(PDA)以接收相应的WETH代币(ETH — Ether (Portal) 7vfC)。如果接收者尚不存在,则必须在Tx5之前创建该接收者账户。账户0xfdca是在Solana上的Tx sSjG中创建的。

如何验证守护者签名(以防假VAA)?

验证守护者签名对任何跨链桥的安全性至关重要,这并不奇怪,这是一个复杂的任务。我们将在第二部分中详细阐述。

谁在目标链上执行后续交易?

任何人都可以检索VAA并执行后续交易。这让消息发送者(例如,在源链上发起代币转账的用户)这样做变得很简单。可是,如果用户在目标链上没有账户或者用户的余额不足以支付交易费用,怎么办?

为了解决这个问题,Wormhole允许bridgerelayers传送消息并赚取费用。费用可以在源交易中指定,并编码到VAA负载中:

如何确保桥接代币和金额是正确的?

在目标链上转移的代币必须与在源链上转移的代币相同或等值。例如,两个都是USDC,或一个是在以太坊上的Wrapped Ether (WETH),另一个是在Solana上的ETH — Ether (Portal)。但不可能是以太坊上的WETH和Solana上的USDC。我们将在第三部分讨论这个部分。

如何防止同一消息的双重交付(VAA重放)?

这是一个微妙的点,并涉及到对目标链的仔细设计。本质上,需要一个全局状态来标记每条已交付的消息,并拒绝尝试重复交付相同消息的交易。我们将在第四部分进一步解释这部分。


关于sec3(前身为Soteria)

sec3是一家安全研究公司,旨在为数百万用户的Solana项目提供准备。sec3的启动审核是一项严格的,由研究人员主导的代码检查,调查并验证主网级智能合约;sec3的持续审核软件平台X-ray与Github集成,逐步扫描拉取请求,帮助项目在部署之前加固代码;而sec3的后部署安全解决方案WatchTower则确保资金安全。sec3正在为Web3项目构建基于技术的可扩展解决方案,以确保协议在扩展时保持安全。

要了解更多关于sec3的信息,请访问https://www.sec3.dev

  • 原文链接: sec3.dev/blog/bridge1...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Sec3dev
Sec3dev
https://www.sec3.dev/