Это сообщение в блоге номер четыре в серии сообщений в блоге, показывающих, как создать приложение поверх Tendermint с помощью Cosmos-SDK. Он продолжит реализацию основной логики - модуля крестики-нолики. Предыдущий пост можно найти здесь.

Хранитель содержит основную логику модуля и, безусловно, является его самым большим компонентом, содержащим основную бизнес-логику.

Для краткости мы покажем здесь только часть его реализации, остальное будет доступно на Github: https://github.com/Sentrylink/tic_tac_toe/tree/basic/x/tic_tac_toe.

Это логика создания игры, запускаемая сообщением StartGame в транзакции пользователя и вызываемая обработчиком после базовой проверки и проверки подписи.

На этом этапе мы делаем следующие три вещи:

  1. Получение идентификатора следующей игры из хранилища ключ-значение посредством вызова метода getGameId
  2. Мы создаем структуру для представления новой игры в крестики-нолики.
  3. Мы храним следующую структуру внутри метода storeGame

Мы используем интерфейс Cosmos-SDK для доступа к хранилищу "ключ-значение". Если бы мы строили непосредственно поверх Tendermint, нам пришлось бы реализовать наш собственный уровень хранения со всеми вытекающими из него сложностями. Это выполняется следующим образом:

Из объекта контекста мы получаем ссылку на хранилище значения ключа, используя ключ, который мы передали хранителю во время первоначального создания экземпляра. Так настраивается уровень хранилища в Cosmos-SDK.

После этого мы кодируем состояние игры как JSON и сохраняем его с ключом, являющимся идентификатором игры. Простой. Cosmos-SDK предоставляет удобную реализацию хранилища значений ключей по умолчанию, которая идеально подходит для большинства приложений.

Способ, которым игра извлекается из уровня хранения, также довольно прост:

После получения ссылки на хранилище так же, как и раньше, мы пытаемся получить закодированное состояние игры для данного идентификатора. Если его нет, мы возвращаем ноль. Если он существует, мы декодируем его из представления JSON и возвращаем ссылку на структуру игры. Простой.

Следующей важной частью приложения является функция Play в компоненте Keeper. Он вызывается обработчиком после того, как сообщение Play было отправлено пользователем в транзакции. Выглядит это так:

Первая часть обеспечивает соблюдение бизнес-правил приложения:

  • Игра должна быть начата до начала игры. У каждой игры есть свой ID. Если такой игры в состоянии нет, возвращается ошибка
  • В игру можно играть, только если победителя еще нет.
  • Игрок может играть только в том случае, если настала его очередь
  • Игрок может выбрать только поле, которое еще не занято
  • Игрок может играть только в том случае, если он участвует в игре, то есть он либо отправитель сообщения StartGame, либо приглашенный внутри него.

После этого начинается основная логика. Поле помечается как занятое данным игроком, и мы проверяем, достаточно ли его для определения победителя игры. В этом случае поле Победитель игры будет изменено с 0 на 1 или 2, в зависимости от того, какой игрок выиграл.
После этого новое обновленное состояние игры кодируется и сохраняется в хранилище "ключ-значение" с помощью вызова метода storeGame.

Следующая важная часть - это запросчик. Для интеграции в структуру Cosmos-SDK нам необходимо реализовать запросчик, соответствующий определенному интерфейсу, который будет вызываться SDK для пользовательских запросов, путь которых начинается с нашего модуля. Все запросы имеют путь в формате

custom/<module_name>/<query_type>/<additional_data_1>/<additional_data_2>

Выглядит это так:

В этом случае мы поддерживаем только один запрос - ответ о состоянии игры на основе идентификатора игры, предоставленного пользователем в пути запроса. Этот запрос возвращает состояние игры, закодированное в JSON. Это реализовано следующим образом:

После получения идентификатора игры из пути запроса мы вызываем метод getGame из keeper и возвращаем соответствующий ответ клиенту.

Следующая важная часть - это регистрация наших пользовательских типов с помощью кодека Cosmos-SDK. Делая это, мы извлекаем выгоду из механизма SDK, позволяющего справляться со многими из основных тонкостей.

Выглядит это так:

Что мы сделали, так это зарегистрировали три наших типа, которые мы хотим кодировать:

  • MstStartGame
  • MsgPlay
  • Игра

При кодировании в двоичную форму или форму JSON Cosmos-SDK будет включать зарегистрированное имя, например tictactoe / StartGame, чтобы он знал, как выполнить обратную операцию.

Заключительная часть - интеграция нашего модуля в приложение Cosmos-SDK. Приложение является центральной частью, которая выполняет следующие важные части:

  • Подключает все модули через их Хранителей
  • Регистрирует запросчики и обработчики с соответствующими маршрутами, чтобы Cosmos-SDK мог правильно выполнять маршрутизацию.
  • Вызывает все функции регистрации кодеков для каждого модуля
  • Монтирует хранилище ключ-значение
  • Реализует различные хуки ABCI, если мы хотим перезаписать те, которые используются по умолчанию.

Поскольку наше приложение не является сложным, нам не нужно перезаписывать какие-либо реализации метода ABCI по умолчанию. Нам нужно только интегрировать наш модуль. Вот как это выглядит

Сначала мы создаем Keeper нашего собственного модуля, который будет содержаться внутри приложения.

Мы создаем субдомен в нашем хранилище ключей и значений, который будет содержать все состояние приложения для нашего приложения. Мы решили хранить его под ключом «tictactoe».

Затем мы даем информацию о маршрутизации приложения, которая будет использоваться при поступлении новых сообщений и запросов для обработки. На основе этой информации приложение Cosmos-SDK вызовет соответствующий обработчик и запросчик, реализацию которых мы уже видели.

Последняя часть - убедиться, что ключ хранения значения ключа для нашего модуля правильно смонтирован в качестве аргумента для вызова метода MountStores.

Резюме

После всего этого мы можем сделать несколько выводов.

Во-первых, без Tendermint, если бы мы хотели реализовать крестики-нолики на блокчейне, это либо должен был бы быть набор смарт-контрактов на Ethereum или на какой-либо другой платформе, либо нам нужно было бы реализовать весь блокчейн с нуля.
В первом случае нам нужно будет строго соответствовать интерфейсам и ограничениям на этой платформе, что может иметь свои недостатки.

В последнем случае ресурсы, которые нам пришлось бы потратить на реализацию основной цепочки блоков, были бы намного больше, чем ресурсы, потраченные на разработку логики приложения.

Во-вторых, с помощью Cosmos-SDK для создания приложений поверх Tendermint мы еще больше сократили эти усилия. Встраиваясь в предоставленную структуру и используя существующие утилиты в SDK, мы значительно сократили объем требуемой работы. Мы могли бы просто сосредоточиться на нашей бизнес-логике, не беспокоясь о деталях более низкого уровня.

В-третьих, Tendermint и Cosmos-SDK предлагают большую гибкость. Интерфейсы довольно общие и не содержат никаких ограничений, поэтому можно построить любую логику. Единственное ограничение, которое накладывает платформа, - это то, что набор валидаторов не может быть слишком большим и что все валидаторы должны быть известны в любое время, что определяется некоторой логикой приложения. Валидаторы не могут приходить и уходить как угодно, например, как это делают майнеры в Биткойне или Эфириуме.

На этом завершается четвертая часть данной серии статей. В следующем посте мы сосредоточимся на создании интерфейса командной строки и запуске приложения!

Подпишитесь на SentryLink на Medium, чтобы получать последние статьи и руководства!

https://medium.com/sentrylink

Если у вас есть какие-либо вопросы или идеи, которыми вы хотите поделиться, напишите нам по адресу [email protected]

Для получения дополнительной информации посетите: https://sentrylink.io