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

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

Мы шаг за шагом объясним, как собрать все приложение. Чтобы сообщение в блоге было достаточно коротким, здесь будут показаны только самые важные части, а весь код будет доступен на Github: https://github.com/Sentrylink/tic_tac_toe/tree/basic

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

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

Как мы уже говорили, модули, созданные с помощью Cosmos-SDK, обычно делятся на следующие части:

  • Хранитель - это центральный компонент модуля, который должен содержать основную бизнес-логику. Специфичное для блокчейна приложение состоит из набора хранителей, которые взаимодействуют друг с другом, каждый из которых обрабатывает логику своего собственного модуля.
  • Сообщения - определяет сообщения, которые существуют в этом модуле. Сообщения - это то, что пользователи отправляют, упакованные в транзакции, когда они хотят взаимодействовать с цепочкой блоков путем записи в нее. Эта часть модуля содержит структуру сообщений, их базовую проверку, информацию о маршрутизации и т. Д.
  • Обработчик - служит для приема входящих сообщений, запуска произвольной логики предварительной обработки и передачи их хранителю, который должен выполнять основную бизнес-логику модуля.
  • Querier - служит для обработки запросов на чтение состояния приложения. Мы можем реализовать произвольные запросы состояния нашего приложения, которые будут вызываться со стороны клиента.
  • Кодек - регистрирует все типы, принадлежащие модулю, которые будут кодироваться с помощью утилит Cosmos-SDK (go-amino).

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

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

  • Бесплатно
  • Снято игроком 1
  • Снято игроком 2

Вот как состояние игры представлено в Go:

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

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

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

  • Начать игру - это сообщение создает новую игру для двух игроков, указанную в качестве адресов в сообщении. Первый игрок подписывает сообщение, и он сделает первый ход в игре.
  • Игра - это сообщение обозначает один ход в игре. Необходимо обеспечить соблюдение правил игры: игрок может играть только в том случае, если его ход, игрок может выбрать только поле и то, которое еще не занято.

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

Давайте посмотрим, как мы можем вписаться в структуру Cosmos-SDK.

Сообщение для начала игры:

Сообщение для розыгрыша хода:

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

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

Он только проверяет, что игрок не пустой, и что поле от 0 до 8.

Дело не в том, что если сообщение успешно проходит эту логику проверки, это еще не означает, что его обработка приложением будет проходить правильно, поскольку это касается только основных правил проверки, без учета состояния приложения. Например, игра может быть уже закончена.

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

Другой важной частью реализации интерфейса сообщений является способ его кодирования и подписи. Эти методы называются GetSignBytes, где реализована кодировка, и GetSigners, которые решают, кто подписывает это сообщение. Реализация доступна здесь: https://github.com/Sentrylink/tic_tac_toe/blob/basic/x/tic_tac_toe/msgs.go

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

Это центральная часть нашего обработчика:

Это простой оператор switch, который вызывает соответствующую функцию для каждого сообщения и имеет предложение по умолчанию для обработки всех неизвестных сообщений.

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

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

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

На этом завершается публикация в блоге номер три. Следующее сообщение в блоге будет содержать остальную часть реализации модуля.

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

https://medium.com/sentrylink

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

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