
В предыдущей статье мы представили Interchain Queries (ICQ) как новую функцию протокола Inter-Blockchain Communication Protocol (IBC), протокола прикладного уровня, который обеспечивает общую и стандартизированную связь между блокчейнами.
Некоторые из вас, космонавты, возможно, уже знакомы со стандартами IBC — они определяют космические линии связи, которые связывают в противном случае фрагментированные солнечные системы Космоса в узнаваемые созвездия, способные обмениваться активами и информацией.
Стандарт ICQ был разработан, чтобы позволить цепочкам с поддержкой IBC запрашивать друг у друга данные по цепочке, уменьшая потребность в оракулах общего назначения для сценариев использования по требованию. Внедрив специальный модуль ICQ, цепочки могут стать доступными для получения запросов запросов. Такие запросы запросов инициируются через пользовательский модуль или с помощью смарт-контрактов. Мы вернемся к реализации смарт-контракта позже (это будет рассмотрено в следующей статье этой серии). В этой статье мы рассмотрим реализацию ICQ с помощью модулей. Теперь давайте приступим к делу!
К концу этой статьи вы будете лучше понимать:
-
Дизайн модуля аськи
-
как инициировать запрос из пользовательского модуля Cosmos SDK
-
возможные варианты использования ICQ.
Во-первых, давайте быстро рассмотрим некоторые основы. Дело не в том, что мы не верим, что вы уже знаете немного о том, как работает IBC, мы просто хотим убедиться, что все основы покрыты. IBC — это решение для взаимодействия с блокчейном; конечно, у него будет несколько движущихся частей.
Основные стандарты IBC предоставляют определения для инфраструктуры, которая позволяет передавать сообщения на уровне приложений между двумя цепочками IBC. Компоненты, указанные в ядре IBC, включают соединения, каналы, порты и пакеты. Каналы заказывают и отправляют сообщения и связаны с соединениями, открытыми между IBC-цепочками. Порты используются для привязки модулей к каналам. Пакеты — это структуры данных, которые инкапсулируют сообщения и определяют логические соединения с кортежем канала и порта.
Транспортный уровень, иначе называемый уровнем транспорта, аутентификации и упорядочения (TAO), состоит из этих основных структур данных наряду с легкими клиентами (используемыми для отслеживания и проверки конечных автоматов на каждой стороне соединения) и ретрансляторами ( для фактической передачи сообщений). Стандарт ICQ (в настоящее время предлагаемый как ICS-32 на момент написания) расширяет обмен сообщениями на основе запроса-ответа протокола IBC и работает на этом транспортном уровне.
Напомним, что ретрансляторы — это назначенные субъекты вне сети, которые сканируют сообщения, готовые к передаче между цепями. Для функций IBC, таких как передача токенов (ICS-20) или межсетевые учетные записи (ICS-27), ретрансляторы сканируют исполнительные сообщения о состоянии отправляющей цепочки. В контексте ICQ ретрансляторы сканируют сообщения с запросами. Если ретранслятор находит сообщение с запросом, предназначенное для другой цепочки, он передает сообщение с запросом в запрошенную цепочку. Чтобы замкнуть цикл, запрошенная цепочка передает запрошенные данные о состоянии в форме сообщения подтверждения обратно в запрашивающую цепочку. Это подтверждение содержит ответ на запрос и также должно передаваться ретранслятором, хотя потенциально другим ретранслятором, чем первый.
Elements of ICQ
Вы можете думать о IBC как о межмодульном протоколе — обмен сообщениями между отдельными цепочками блоков осуществляется интерфейсными модулями. При разработке модуля для ICQ используется подход, аналогичный подходу при разработке модулей для других приложений IBC. Здесь мы углубимся в ключевые элементы дизайна любого модуля ICQ (примеры можно найти в репозитории Strangelove Ventures ibc-go ).
Цепные соединения
Модуль ICQ должен быть реализован на блокчейнах, ожидающих получения запросов запросов. ICQ спроектирован таким образом, что множество независимых подключений из запрашивающих цепочек (называемых клиентами) могут быть нацелены на одну запрашиваемую цепочку (называемую хостом), оснащенную модулем ICQ. Другими словами, топология соединений от клиента к хосту — это N к 1 в контексте ICQ.
Хост-порт
Состояние генезиса определяет начальное состояние модуля ICQ. Модуль имеет два поля генезиса: порт хоста и параметры модуля. Порт хоста — это фиксированное строковое значение, которое используется модулем ICQ (в цепочке хостов) для привязки владельца к имени порта (portID). Каждое сообщение запроса ICQ будет поступать на этот порт в цепочке хостов, а клиентские цепочки будут использовать имя порта хоста в качестве идентификатора порта контрагента. Порт хоста соединяется с динамически созданным идентификатором канала для создания кортежа порта канала, который служит конечной точкой на стороне хоста. Кортеж канала-порта может быть представлен как <portID, channelID>.
Параметры модуля ICQ
Второе поле состояния генезиса, которое необходимо определить, — это параметры модуля ICQ . Модуль ICQ имеет два параметра: HostEnabled и AllowQueries . HostEnabled используется запрашиваемой цепочкой (цепочкой узлов) для включения или отключения возможности обслуживания запроса запроса через модуль ICQ. Если цепочка хостов не хочет обслуживать запросы запросов, она отключит запросы, установив для параметра HostEnabled значение false. Разрешить запросы позволяет цепочке узлов внести в белый список определенные типы запросов (в цепочке узлов обычно доступны различные запросы gRPC, а уникальные или специфичные для цепочки модули могут использовать свои собственные типы запросов). По умолчанию запрос не будет обслуживаться в цепочке хостов ICQ, если запросы его типа явно не включены в белый список, определяемый AllowQueries . AllowQueries по сути является фильтром, какие типы ICQ-запросов хочет получать цепочка хостов. Если этот параметр оставить пустым, запросы приниматься не будут.
ICQ-сообщения
Запросы между цепочками выполняются с использованием механизмов запросов и типов сообщений в протоколе Tendermint ABCI. Пользовательский модуль в клиентской цепочке вызывает эти механизмы запроса ABCI для инициирования сообщения запроса ICQ. Сообщение запроса ICQ состоит из списка запросов Tendermint ABCI. Сообщения кодируются с использованием protobuf перед отправкой в канал и через соединение IBC.
ICQ-запрос
Для сообщения запроса ICQ список запросов Tendermint ABCI сначала будет протокодирован, а затем сохранен в поле данных InterchainQueryPacketData в виде необработанных байтов перед отправкой в цепочку хостов.
CosmosQuery — это структура данных, используемая для переноса списка запросов Tendermint ABCI
.
}
Ответ аськи
Ответное сообщение ICQ состоит из списка ответов Tendermint ABCI. Они возвращаются в запрашивающую (клиентскую) цепочку из запрашиваемой (хостовой) цепочки в том же порядке, в котором был отправлен список запросов. Список предварительно кодируется, а затем сохраняется в поле данных InterchainQueryPacketAck в виде необработанных байтов перед отправкой в качестве ответа на цепочку запросов.
сообщение InterchainQueryPacketAck {
байты данных = 1;
}
CosmosResponse — это структура данных, используемая для упаковки списка ответов на запросы Tendermint ABCI.
сообщение CosmosResponse {
повторные ответы тендерминта.abci.ResponseQuery = 1
[(gogoproto.nullable) = false];
}
Обратите внимание, что каждое сообщение ICQ имеет одинаковую структуру — список запросов ABCI (от клиента) или ответов ABCI (от хоста), закодированных и упакованных в пакет. Помните, что список ответов ABCI следует тому же порядку, что и список запросов ABCI, а это означает, что запрос с индексом N будет соответствовать ответу с индексом N в возвращенном пакете подтверждения.
Создание канала
Чтобы ICQ работала между двумя цепочками, клиентская цепочка должна установить пользовательский модуль, а хост-цепочка должна установить модуль ICQ (альтернативная реализация смарт-контракта обсуждается в следующей статье этой серии). Эти два модуля должны быть готовы с необходимой привязкой имени порта. Имя порта для модуля запроса клиентской цепочки не имеет ограничений по соглашению об именовании. Напротив, portID по умолчанию фиксируется как « icqhost » для модуля ICQ хоста.
После настройки соответствующей привязки имени порта и при условии, что обе цепочки активны, любой оператор ретранслятора может настроить свой ретранслятор для создания канала между двумя цепочками. Все сообщения о рукопожатии канала для выполнения ICQ будут обрабатываться ретранслятором с использованием основных стандартов протокола IBC.
Резюме
Цепочка узлов с модулем ICQ может получать запросы запросов от нескольких разных цепочек клиентов. Поля состояния Genesis для модуля ICQ включают идентификатор порта хост-порта и параметры для включения/отключения обслуживания входящих запросов и для фильтрации типов запросов. Сообщения ICQ создаются с использованием типов сообщений-запросов Tendermint ABCI и отправки списков запросов ABCI в закодированных пакетах данных в цепочку хостов через IBC. Подтверждения возвращаются в виде пакетов в той же форме, сохраняя порядок сообщений, чтобы соответствующие запросы и ответы имели идентичные значения индексов. Модуль ICQ на стороне хоста взаимодействует с модулем запросов на стороне клиента с соответствующим образом привязанными портами. Кортежи канала-порта на каждой стороне представляют собой логические связи между двумя цепочками. Ретрансляторы заботятся о транспортировке пакетов, открывая каналы, связывающие связанные порты.
Надеюсь, вы все это получили! Теперь подробнее рассмотрим интеграцию ICQ на стороне клиента и механизмы работы протокола между двумя взаимодействующими цепочками.
Реализация пользовательского модуля запросов для цепочки клиентов ICQ
Этот раздел проведет вас через пример настройки для оснащения цепочки пользовательским модулем запросов. Это необходимо для возможности построения и отправки ICQ-запросов из клиентской цепочки. В примере предполагается, что цепочка построена с использованием Cosmos SDK с модулями, написанными на Golang.
Очевидно, модуль должен быть предварительно включен в IBC. Чтобы включить функции IBC для рукопожатий, а также для отправки и получения сообщений, реализуйте пакет типов портов с интерфейсом IBCModule ( porttypes.IBCModule ) в типе AppModule запрашивающего модуля. module.go
_ porttypes.IBCModule = AppModule{}Мы предоставили пример интеграции ICQ на стороне клиента в демонстрационном репозитории межсетевых запросов Quasar Labs . Пользовательский модуль запросов называется interquery . Его AppModule будет реализовывать все необходимые интерфейсы и методы ICS-05 (порт) и интерфейс IBCModule в module_ibc.go..Демо реализовано с использованием ibc-go_v3.3.0-icq от форка ibc-go Strangelove Ventures. Справочные определения интерфейсов можно найти в репозитории Strangelove Ventures ibc-go . Ниже приведен список методов для реализации, где ( … ) представляет аргументы, написанные для простоты: OnChanOpenInit(…) (ошибка) OnChanOpenTry (
…) (строка, ошибка ) error OnChanCloseConfirm(…) error OnRecvPacket(…) ibcexported.Acknowledgement OnAcknowledgementPacket(…) error
OnTimeoutPacket(…) errorModule RegistrationКак и любой другой модуль Cosmos SDK, пользовательский модуль на стороне клиента необходимо зарегистрировать в реестре модулей приложения. Для хоста объект модуля ICQ также необходимо зарегистрировать в реестре модуля по аналогичному шаблону. Шаг 1 |Создайте ICQ keeper с ограниченной областью действия keeper.go
scopedICQKeeper :=
app.CapabilityKeeper.ScopeToModule(icqtypes.ModuleName) Шаг 2 |Создайте объекты ICQ keeper, ICQ module и ICQ IBC module в приложении app.go
app.ICQKeeper = icqkeeper. NewKeeper(
appCodec, keys[icqtypes.StoreKey], app.GetSubspace(icqtypes.ModuleName),
app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
scopedICQKeeper, app.BaseApp,
)
icqModule := icq.NewAppModule(app.ICQKeeper)
icqIBCModule := icq.NewIBCModule(app.ICQKeeper) Шаг 3 |Добавить модуль ICQ IBC в маршрутизатор IBC app.go
ibcRouter.AddRoute(icqtypes.ModuleName, icqIBCModule) Шаг 4 | Добавить модуль ICQ в диспетчер модулей app.go
app.mm = module.NewManager(
…
…
icqModule,
)
Поток пакетов ICQ
В ICQ, как и в IBC в целом, информация передается по цепочкам пакетами (зашифрованными и плотно завернутыми в виртуальную пузырчатую пленку) для безопасного перемещения между цепочками. Сообщения-запросы, каждое из которых состоит из списка запросов-запросов ABCI, входят в эти пакеты. Пакеты ICQ тщательно обрабатываются на каждой стороне соединения IBC — мы покажем вам, как это сделать.
Поток сообщений на стороне клиента
Логика приложения полностью зависит от типа задействованного приложения и его требований. Это означает, что решение о том, что запрашивать и когда запрашивать, определяется приложением клиентской цепочки. Однако общие этапы создания объектов сообщения запроса (главным образом кодирование и отправка) будут схожими. Эти шаги:
-
Создайте сообщение запроса целевого модуля
-
Создайте список запросов запросов ABCI для цепочки хостов.
-
Кодировать сообщение с помощью protobuf
-
Оберните закодированные байты в другую структуру данных
-
Создайте пакет IBC
-
Отправьте окончательный пакет IBC на предварительно установленный канал
Пример: создание простого сообщения о запросе банка. Написание запроса запроса ABCI выполняется путем создания объекта запроса из целевого модуля, а затем создания объекта abcitypes.RequestQuery с конечной точкой запроса и закодированным объектом запроса.
Ref: SendQueryAllBalances msg_server_send_query_all_balances.go
q := banktypes.QueryAllBalancesRequest{
Адрес: msg.Address, Разбивка на
страницы: msg.Pagination,
}
reqs := []abcitypes.RequestQuery{
{
Путь: "/cosmos.bank.v1beta1.Query/AllBalances" ,
Данные: k.cdc.MustMarshal(&q),
},
} Создание закодированного сообщения запроса ICQ
Типичный пример метода хранителя для подготовкиОбъект InterchainQueryPacketData из списка запросов ABCI можно записать следующим образом:
Ref: SendQuery relay.go
func (k Keeper) SendQuery(
ctx sdk.Context, sourcePort
,
sourceChannel string,
chanCap *capabilitytypes.Capability,
reqs []abci.RequestQuery,
timeoutHeight clienttypes.Height,
timeoutTimestamp uint64,
) (uint64, ошибка) {
sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel)
if !found {
return 0, sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "ID порта (%s) ID канала (%s)", sourcePort, sourceChannel)
}
destinationPort := sourceChannelEnd.GetCounterparty().GetPortID()
destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID()
data, err := icqtypes.SerializeCosmosQuery(reqs)
if err != nil {
return 0, sdkerrors.Wrap(err, "не удалось сериализовать запросы в космический запрос")
}
icqPacketData := icqtypes.InterchainQueryPacketData{
Данные: данные,
}
return k.createOutgoingPacket(ctx, sourcePort, sourceChannel, destinationPort, destinationChannel, chanCap, icqPacketData, timeoutTimestamp)
}
Отправка закодированного сообщения запроса ICQ
После подготовки InterchainQueryPacketData клиентскому модулю необходимо создать новый пакет для установленного канала с помощью метода packetvchanneltypes.NewPacket . Пакет должен быть отправлен с использованием метода хранителя оболочки ICS-04 k.ics4Wrapper.SendPacket . Типичный пример создания окончательных данных пакета из InterchainQueryPacketData может быть записан следующим образом
:
icqPacketData icqtypes.InterchainQueryPacketData,
timeoutTimestamp uint64,
) (uint64, ошибка) {
if err := icqPacketData.ValidateBasic(); err != nil {
return 0, sdkerrors.Wrap(err, "invalid interchain query package data")
}
// получаем следующую
найденную последовательность последовательностей := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel)
if !found {
вернуть 0, sdkerrors.Wrapf(channeltypes.ErrSequenceSendNotFound, «не удалось получить следующую последовательность, отправленную для канала %s через порт %s», sourceChannel, sourcePort)
}
package := channeltypes.NewPacket(
icqPacketData.GetBytes(),
sequence,
sourcePort,
исходный канал, порт
назначения, канал назначения
,
clienttypes.ZeroHeight(),
timeoutTimestamp,
)
if err := k.ics4Wrapper.SendPacket(ctx, chanCap, package); err != nil {
возврат 0, ошибка
}
return package.Sequence, nil
}
Поток сообщений на стороне хоста
Когда сообщение запроса получено в конечной точке кортежа <host portID, channelID>, будет вызван обработчик RecvPacket из протокола ibc-core. Это дополнительно вызывает обратный вызов метода OnRecvPacket модуля ICQ (см. точку обратного вызова ). Обработка сообщений с запросами прописывается в кипере модуля ICQ как executeQuery . Прежде чем выполнять дальнейшую обработку в рамках executeQuery , запрошенные запросы аутентифицируются с помощью authenticationQuery . Аутентификация здесь означает проверку запроса на соответствие запросам из белого списка, отслеживаемым сервисом AllowQueries.параметр модуля ICQ. После успешной проверки модуль ICQ вызовет метод запроса ABCI-Query интерфейса Queryable (см. вызов запроса ). Интерфейс Queryable извлекает запрошенное значение из соответствующего модуля и готовит подтверждение. Этот процесс можно свести к пяти этапам: Аутентификация запрошенных запросов по запросам из белого списка. Вызов ABCI-Query.
Подготовьте сообщение подтверждения запроса
Закодируйте сообщение с помощью protobuf и оберните его в ответный пакет. Отправьте ответный пакет по уже установленному каналу. Если вы пишете модуль запроса в своей IBC-цепочке, вам не нужно ничего делать на стороне хоста. Вышеуказанные шаги уже реализованы в модуле ICQ на цепочке хостов; если какая-либо цепочка хостов интегрирует и активирует ICQ, она просто будет работать. Варианты потенциального использования Вы можете решить широкий спектр проблем, используя ICQ для вашего следующего межсетевого проекта. Следующие примеры — лишь вершина айсберга. Или, скорее, чтобы сохранить астрономию, эти примеры являются лишь внешней атмосферой планеты возможностей, которые могут быть реализованы с помощью ICQ. Получение цен пула из DEX, такого как Osmosis, для построения сложной торговой стратегии. Извлечение состояния предложения токенов в цепочке для определения возможностей получения дохода. Извлечение балансов NFT для отображения портфеля пользователя на панели инструментов. Хранилища Quasar оснащены функциями ICQ. Если вас интересуют приложения DeFi, не ищите дальше 😉 Нам не терпится увидеть, что сообщество создаст с помощью инструментов, которые мы делаем доступными. Не стесняйтесь делиться с нами тем, что вы решили создать, на нашем канале Discord, где некоторые из нашего сообщества разработчиков могут протянуть руку помощи.
Что дальше? В следующей статье мы познакомим вас с реализацией ICQ в рамках экосистемы смарт-контрактов CosmWasm.
Увидимся там! Присоединяйтесь к нам, когда мы входим в Космос: Веб -сайт | Твиттер | Дискорд | Ссылки на Telegram 1. https://medium.com/@quasar.fi/introduction-interchain-queries-d6243e7b45cf 2. https://github.com/strangelove-ventures/ibc-go/tree/icq_implementation/modules/apps/ 32-icq