CCIP Read ISM
使用CcipReadIsm
为开发人员验证链间消息提供了很大的灵活性。最终,每一种其他类型的ISM都可以实现为CCIP Read ISM,因此,当构建新的ISM时,我们鼓励构建CCIP Read ISM,因为所有中继集成工作已经完成。
对于CCIP Read ISM要记住的一个警告是,它们确实引入了对外部(到区块链)但自托管的API的依赖。如果这对您的用例来说是一个困难的障碍,您可能需要考虑其他消息验证技术。
在构建CCIP Read ISM之前,您有必要熟悉CCIP Read specification。该规范描述了一种通用协议,允许EVM兼容链上的智能合约查询和消费链下数据。
它是如何工作的
中继器会持续监听从Hyperlane Mailboxes发出的Dispatch
事件。当消息被中继器发送和接收时,中继器将向目的ISM查询如何处理该消息以及是否交付成功的信息。
正确的moduleType
变量需要在你的ISM上设置,以便中继知道这是一个CCIP Read ISM。为了确保正确配置,你可以从@hyperlane-xyz/core
中的AbstractCcipReadIsm
继承。
然后,中继器将在ISM上调用getOffchainVerifyInfo(bytes)
函数来传递消息的内容。当出现下面 interface部分描述的OffchainLookup
错误时,该函数应该恢复。
中继器将查询此还原消息中指定的端点,并将提供的响应和原始消息传递给目的地Mailbox
的process(bytes,bytes)
函数。
接口
CcipReadIsm
必须实现ICcipReadIsm
接口,并且应该扩展AbstractCcipReadIsm
,这是一个方便的协议,可以正确设置moduleType
。
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
import {IInterchainSecurityModule} from "../IInterchainSecurityModule.sol";
interface ICcipReadIsm is IInterchainSecurityModule {
/// @dev https://eips.ethereum.org/EIPS/eip-3668
/// @param sender the address of the contract making the call, usually address(this)
/// @param urls the URLs to query for offchain data
/// @param callData context needed for offchain service to service request
/// @param callbackFunction function selector to call with offchain information
/// @param extraData additional passthrough information to call callbackFunction with
error OffchainLookup(
address sender,
string[] urls,
bytes callData,
bytes4 callbackFunction,
bytes extraData
);
/**
* @notice Reverts with the data needed to query information offchain
* and be submitted via the origin mailbox
* @dev See https://eips.ethereum.org/EIPS/eip-3668 for more information
* @param _message data that will help construct the offchain query
*/
function getOffchainVerifyInfo(bytes calldata _message) external view;
}
配置
在开发CCIP Read ISM时,ChainlinkISM是一个很好的参考例子。ChainlinkISM
用一组Chainlink oracle初始化,并验证所提供的价格feed数据是否已经由部分签名者进行了签名。
API
根据CCIP Read,链下API需要返回带有表单的JSON数据,
{
"data": "..."
}
中继器会将这个data
属性作为metadata
参数传递给Mailbox.Process
(bytes metadata, bytes message)。
请注意,在链式ISM的情况下,数据的接收方也充当验证ISM,data
只是发送的原始交易,以提交具有相关签名的价格数据。message
属性有些多余。
合约
在设置ISM时,getOffchainVerifyInfo
和verify
函数是需要指定的重要函数。
-
getOffchainVerifyInfo
函数应该返回一个OffchainLookup
错误,指示中继器查询给定的API端点。OffchainLookup
错误允许提供一组API端点,因此你可以强制执行你想要的任何级别的冗余 -
verify
必须获取提供的metadata
并验证其合法性。同样,在为您自己的ISM开发此逻辑时,ChainlinkISM实现是一个非常棒的参考。
下面是CCIP Read ISM的示例,其中ISM也是消息的接收者,根据链链接ISM。
pragma solidity ^0.8.13;
import {AbstractCcipReadIsm} from "@hyperlane-xyz/core/contracts/isms/ccip-read/AbstractCcipReadIsm.sol";
import {IInterchainSecurityModule, ISpecifiesInterchainSecurityModule} from "@hyperlane-xyz/core/contracts/interfaces/IInterchainSecurityModule.sol";
import {IMailbox} from "@hyperlane-xyz/core/contracts/interfaces/IMailbox.sol";
import {Message} from "@hyperlane-xyz/core/contracts/libs/Message.sol";
contract MyCcipReadIsm is AbstractCcipReadIsm, ISpecifiesInterchainSecurityModule {
using Message for bytes;
IMailbox mailbox;
...
/**
* No-op, everything happens in the verify function
*/
function handle(uint32, bytes32, bytes calldata _report) public {}
/**
* @param _metadata ABI encoded module metadata
* @param _message Formatted Hyperlane message (see Message.sol).
*/
function verify(
bytes calldata _metadata,
bytes calldata _message
) external returns (bool) {
...
}
function interchainSecurityModule()
external
view
returns (IInterchainSecurityModule)
{
return IInterchainSecurityModule(address(this));
}
function getOffchainVerifyInfo(
bytes calldata _message
) external view override {
revert OffchainLookup(
address(this),
offchainUrls,
_message,
MyCcipReadIsm.process.selector,
_message
);
}
/**
* Provided for full CCIP Read specification compatibility. Relayers
* will call the Mailbox directly regardless of the selector specified
* in the `OffchainLookup` error
*/
function process(
bytes calldata _metadata,
bytes calldata _message
) external {
mailbox.process(_metadata, _message);
}
}