防御性示例模式

我们将要实现的另一个最佳实践称为防御性示例(Defensive Example),这是一种模式,它允许我们在不强制原始交易失败的情况下重新处理失败的消息。让我们解释一下它的工作原理。

接收和处理消息

当目标区块链接收到消息时,CCIP路由器会调用ccipReceive函数。此函数作为合约处理传入CCIP消息的入口点,通过onlyRouteronlyAllowlisted修饰符实施关键的安全检查。

以下是该过程的逐步分解:

  1. 通过ccipReceive进入:

    • ccipReceive函数被调用,传入一个包含待处理消息的Any2EVMMessage结构体。

    • 安全检查确保调用来自授权的路由器、已允许的源链和已允许的发送者。

  2. 处理消息:

    • ccipReceive调用processMessage函数,该函数是外部的,以利用Solidity的try/catch错误处理机制。注意onlySelf修饰符确保只有合约本身可以调用此函数。

    • processMessage内部,使用s_simRevert状态变量检查模拟回滚条件。这个模拟由只有合约所有者可调用的setSimRevert函数来切换。

    • 如果s_simRevert为假,processMessage调用_ccipReceive函数进行进一步的消息处理。

  3. _ccipReceive中的消息处理:

    • _ccipReceive从消息中提取并存储各种信息,如messageId、解码后的sender地址、代币数量和数据。

    • 然后发出一个MessageReceived事件,表示消息处理成功。

  4. 错误处理:

    • 如果在处理过程中发生错误(或触发了模拟回滚),ccipReceive内的catch块将被执行。

    • 失败消息的messageId被添加到s_failedMessages中,消息内容被存储在s_messageContents中。

    • 发出一个MessageFailed事件,允许以后识别和重处理失败的消息。

失败消息的重新处理

retryFailedMessage函数提供了一种机制,如果CCIP消息处理失败,可以用来恢复资产。它专门设计用来处理消息数据问题导致整个处理无法进行,但允许代币恢复的场景:

  1. 初始化:

    • 只有合约所有者可以调用此函数,提供失败消息的messageId和代币恢复用的tokenReceiver地址。

  2. 验证:

    • 使用s_failedMessages.get(messageId)检查消息是否已失败。如果没有,就回滚交易。

  3. 状态更新:

    • 将消息的错误代码更新为RESOLVED,以防止重复进入和多次重试。

  4. 代币恢复:

    • 使用s_messageContents[messageId]检索失败的消息内容。

    • 将与失败消息关联的锁定代币转移到指定的tokenReceiver,作为一个逃生舱口,而无需再次处理整个消息。

  5. 事件发出

    • 发出一个MessageRecovered事件,以信号代币已成功恢复。

这个函数展示了一个优雅的资产恢复解决方案,即使在消息处理遇到问题时也能保护用户的价值。

Last updated