本文深入探讨了 Wormhole 如何防止 VAA 重复攻击,确保每个 VAA 只能成功使用一次。文章详细介绍了在 Solana 和 Ethereum 上的实现机制,包括如何利用全球标记保持已完成的 VAA 的唯一性,从而防止恶意用户通过重复使用相同 VAA 来窃取代币。
继 第 1 部分 第 2 部分 第 3 部分 之后,本文着重解释 Wormhole 如何防止 VAA 重放攻击(即,同一消息在目标链上永远不能被交付两次)。
这是非常重要的,因为否则恶意用户可能通过多次以相同 VAA 赎回从而盗取代币。
本质上,每个成功赎回的 VAA 都必须在全局范围内被记录,方法是保持一个链上标志,指示该 VAA 已经被赎回。
任何尝试重用被 is_already_redeemed 标记的 VAA 的交易都会被拒绝。
接下来我们将解释这如何在 Solana 和以太坊上实现。
在 Solana 上,最终消息交付功能 (complete_native 和 complete_wrapped) 都采用输入 PDA 账户 claim,并利用它来防止 VAA 双重签名:
pub claim: Mut<Claim<’b>>,
在调用时,claim 账户必须未初始化:
pub type Claim<'a> = Data<'a, ClaimData, { Uninitialized }>;
// 未初始化
consume 函数被调用以初始化并检查 claim 账户的有效性:
claim 账户是由 emitter_address、emitter_chain 和 VAA 中的序列确定的 PDA:
claim 账户有一个标志 claimed,在初始化后被设置为真 ( line 87 ):
通过上述方法,Wormhole 确保每个具有唯一组合的 VAA(emitter_address、emitter_chain 和 sequence)创建一个唯一的 claim 账户,该账户只能成功使用一次。
在以太坊上,Wormhole 同样维护一个全局映射 completedTransfers,用于存储所有完成的 VAA 哈希:
mapping(bytes32 => bool) completedTransfers;
VAA 哈希是对 VAA 字节(不包括守护者签名)进行的 keccak256 哈希:
确保即使守护者不同,每个 VAA 哈希对同一消息都是唯一的。
在每次消息交付调用中,它会检查 VAA 哈希是否已经标记( isTransferCompleted line 497),如果是则中止,否则将传递该消息并标记哈希( setTransferCompleted line 498)。
在上述内容中,_state.completedTransfers 是全局存储中的映射,必须在每次成功的消息传输中更新:
// 消耗的代币转账的映射
mapping(bytes32 => bool) completedTransfers;
请注意,在以太坊上,全球存储操作 (SSTORE) 会产生最大的 Gas 成本。这解释了为何赎回代币是昂贵的。例如,在以下交易中,调用 completeTransfer 的费用为 $6.81 (270K gas):
- 原文链接: sec3.dev/blog/bridges4...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!