API коллекций — это пакет Golang, который улучшает абстракции, связанные с состоянием, в Cosmos-SDK. Здесь мы объясняем состояние блокчейна и преимущества NibiruChain/коллекций.
Недавно мы реализовали API коллекций для лучшего управления состоянием в Nibiru Chain и подумали, что этот инструмент будет полезен для более широкого сообщества Cosmos. После интеграции его с нашими основными модулями мы предложили запись архитектурного проекта (ADR) для Cosmos-SDK, которая была объединена в конце 2022 года. Было здорово увидеть такие положительные отзывы от основных участников SDK.
«Есть что-то приятное в простоте коллекций для более простых вариантов использования, и перспектива возможности переноса модулей в коллекции без необходимости миграции, безусловно, привлекательна». - Аарон Краелиус (открывает новое окно)в сети Regen (ааронк)
- Ссылка: Отчет об архитектурном проектировании Cosmos-SDK № 62: Коллекции, упрощенный уровень хранения для модулей Cosmos-SDK.(открывает новое окно)
- Архитектором/изобретателем и основным создателем коллекций был @testinginprod. (открывает новое окно).
- Первоначальная реализация API коллекций находится внутри NibiruChain/collections. (открывает новое окно). С тех пор он был включен как часть Cosmos-SDK и опубликован в пакете космоссдк.ио/коллекции. (открывает новое окно).
- Мы активно используем API в модулях Nibiru Chain. (открывает новое окно)такие как x/oracle, x/perp и x/vpool.
Остальная часть этого поста посвящена объяснению того, как работает «состояние» и где разработчики протоколов в цепочках приложений могут извлечь выгоду из использования API коллекций.
Что такое государство?
Блокчейн — это детерминированный конечный автомат, который переходит между состояниями на основе транзакций. «Состояние» — это то, как мы относимся к представлению этой системы в любой точке. Состояние включает в себя все, что отслеживает цепочка: остатки на счетах, позиции ликвидности, параметры обмена и многое другое.
Конечный автомат является детерминированным, потому что узел, который выполняет одни и те же транзакции, начиная с начального состояния (блока), окажется в том же конечном состоянии.
Состояние в Cosmos-SDK
Когда разработчики создают приложения, им необходимо указать, когда читать, обновлять или удалять состояние. Чтобы справиться с этим, Cosmos-SDK предоставляет специфичное для модуля хранилище ключей и значений ( KVStore
). Приложения могут читать и записывать байтовые данные с помощью этих KVStores
, а коллекции этих хранилищ составляют состояние.
Вот тут и всплывает первая проблема. В бизнес-логике мы часто имеем дело со «структурированными данными», в этом контексте имея в виду такие вещи, как structs
, классы, массивы, очереди, карты или JSON в языках программирования. Однако, когда мы имеем дело с хранилищем, нам приходится работать с битами и байтами, потому что программы используют этот формат для представления данных в памяти. Человекочитаемые строки хороши для разработки, но плохи для эффективности вычислений.
В случае цепочек приложений SDK механизм консенсуса (Tendermint Core) (открывает новое окно)не зависит от приложения и принимает транзакции только в виде необработанных байтов, которые обычно не читаются человеком.
По этой причине приложения SDK в конечном итоге создают множество функций для работы с типами хранилищ. Это многословно, подвержено ошибкам и увеличивает затраты на обслуживание в виде тестов. Мы рассмотрим конкретный пример, чтобы подчеркнуть это.
Примеры из модуля x/staking
Вам не нужно слишком внимательно читать эти блоки кода. Смысл их включения состоит в том, чтобы продемонстрировать, сколько работы уходит на получение поведения создания, чтения, обновления и удаления (CRUD), описанного в предыдущем разделе.
Чтобы использовать все возможности хранилища делегаций, SDK также должен был включать аналогичные функции для:
- Добавление предметов -
SetDelegation
- Удаление предметов -
RemoveDelegation
- Итерация по элементам -
IterateAllDelegations
- И читая все пункты -
GetAllDelegations
Это все только для одного типа ключа. Кроме того, определенная информация должна быть определена в types/keys.go. Это включает в себя:
1 — хранить префиксы для каждого типа ключа
Ключи хранят префиксы в файле keys.go модуля x/staking Ключи хранят префиксы | с keys.go в модуле x/staking
2 — Функции кодировщика ключей для каждого типа ключей
Для каждого из 14 типов ключей в x/staking
, мы должны определить минимум 4 функции (всего более 50) только для базового CRUD. Этот процесс оказывается чрезвычайно повторяющимся для модулей и типов хранилищ.
Определение того, как кодировать и декодировать между ключами и байтами, является одной из самых подверженных ошибкам задач даже для опытных разработчиков Cosmos.
Этот процесс добавляет требования к сопровождению с тестами и имеет тенденцию становиться неприятным при работе с объектами, сопоставленными с составными ключами.
Например, вечный Position
на Nibi-Perps однозначно отображается (идентифицируется) комбинацией AssetPair
и Trader
адресом, которому принадлежит позиция. Мы можем захотеть получить доступ к коллекции Positions
разными способами, не проходя исчерпывающим образом каждую позицию, например
- «получить все
Positions
по заданномуAssetPair
» - «получить все
Positions
по заданномуTrader
» - «получить все то длинное
Positions
, что находится под водой на любомAssetPair
»
Все эти данные очень полезны для доступа и обновления для таких вариантов использования, как торговля, ликвидация позиций и создание рынка. Но ключи, состоящие из нескольких частей, становятся чрезвычайно сложными, когда мы хотим добавить более сложную функциональность.
Войдите в API коллекций(открывает новое окно)
API коллекций — это пакет Golang, который улучшает абстракции хранения в Cosmos-SDK, предоставляя разработчику возможности, аналогичные CosmWasm/cw-storage-plus. (открывает новое окно), основная библиотека для абстракций хранения в смарт-контрактах CosmWasm.
API collections
имеет следующие преимущества
- Он не требует специальных инструментов и имеет мало зависимостей. Коллекции просто полагаются на дженерики.
- Разработчики протоколов могут сосредоточиться на бизнес-логике . Скрывая сложность ключей кодирования и декодирования, операции CRUD (создание-чтение-обновление-удаление) становятся намного проще для понимания.
- Составные ключи легко управляются
collections.Join
и имеют средства доступа для итераций в разных представлениях одного и того же хранилища. - Обрабатывает сложные структуры : привет, Голанг
IndexedMap
!
Спасибо за чтение! Не стесняйтесь присылать любые вопросы или комментарии в Twitter, Discord, GitHub или сюда.
🔮 Документы (открывает новое окно)| 👾 Дискорд (открывает новое окно)| 🐦 Твиттер (открывает новое окно)| 🔥 Веб-приложение (открывает новое окно)⛓️ ️Исследователь (открывает новое окно)| 🌴 Дерево ссылок (открывает новое окно)| 👨💻 Код(открывает новое окно)
Новости о нашей децентрализованной сети оракулов, программе амбассадоров, сборе семян и многоэтапной поощрительной тестовой сети появятся в течение следующих нескольких недель.
Приложение для разработчиков: Коллекции
Определение типов хранения
В collections
, типы хранения определяются в Keeper
структуре. Поскольку Keeper является королем бизнес-логики модуля, определения состояний должны быть там, а не разбросаны по нескольким файлам. Давайте посмотрим, как мы создаем экземпляры всех этих новых типов коллекций.
Итак, чтобы создать экземпляр a collections.Map
, нам нужны четыре вещи:
- Ключ хранилища модуля (необходим для получения
KVStore
) - Номер пространства имен в диапазоне от 0 до 255. По сути, это зарезервированный байт пространства имен для всех объектов, связанных с этой коллекцией. Это означает, что максимальное количество типов коллекций, которые мы можем иметь в одном модуле, равно 256, чего должно быть достаточно.
- ,
KeyEncoder
который указывает,collections.Map
как кодировать и декодировать ключи. В API коллекций уже определено большинство полезных кодировщиков ключей, которые могут вам понадобиться. - ,
ValueEncoder
который указываетcollections.Map
, как кодировать и декодировать его значения. Как и вKeyEncoder
, в библиотеку встроены наиболее часто используемые кодировщики значений.
Что вы получаете от этого?
- Типобезопасный API. Ключи и значения типобезопасны. Вам больше не нужно иметь дело с байтами.
- Безопасные кодировщики ключей, которые заботятся о:
- правильный порядок
- безопасный префикс
- Больше не нужно определять
Get/Set/Delete/Iterate
методы для вашего хранителя, специфичные для каждого объекта. - Приятное
Iterate API
использованиеcollections.Ranger
. - Другие мощные API коллекций для изучения:
KeySet
,Item
,Sequence
,IndexedMap
.
Вот как некоторые из примеров из предыдущего поста выглядят с коллекциями.
Теперь давайте посмотрим на случай с позициями (примечание: collections.Pair
это тип, который определяет ключ, состоящий из двух других ключей, collections.PairRange
реализует интерфейс с более удобным API для работы с collections.Pair
ключами):
Дополнительные инструкции и примеры приведены в репозитории коллекций. (открывает новое окно).
Спасибо!