Основной задачей блокчейн-эксплорера является сбор данных сети для дальнейшего анализа и вывода информации в более доступном для человека формате с возможностью поиска, фильтрации и просмотра сущностей сети, таких как блоки, транзакции и валидаторы.
Мы так же, как и большинство блокчейн-сетей, нуждались в этом. Не всегда эти данные можно получить из ноды, да и не ее это забота, ведь лишние задачи могут привести к замедлению сети. Было принято решение разработать Minter Explorer, но вскоре требования к проекту увеличились, и проводник перерос в шлюз для общения блокчейн-сети с нашими приложениями.
Альфа (прототип)
Первая версия была скорее прототипом, а активное развитие самой блокчейн-сети не всегда позволяло заглядывать далеко и предусматривать некоторые шаги.
Изначально проект был монолитным, написанным на PHP-версии 7.2 с использованием фреймворка Lumen (Laravel) для API; в качестве базы данных мы использовали PostgreSQL версии 9.6, RabbitMQ для очередей и Redis для кэширования. В качестве фронта — сайт на Vue.js.
Работало все так:
- Консольная команда в бесконечном цикле делала запрос к ноде с тайм-аутом 5 сек.;
- Полученная информация отдавалась воркерам для дальнейшего сохранения.
В общем, ничего сверхъестественного. :)
Но из-за большого количества запросов и не всегда стабильной работы ноды тех версий было необходимо обеспечить отказоустойчивость работы сервиса.
Это было реализовано еще одной консольной командой, которая в цикле с тайм-аутом перебирала пул нод, проверяя доступность и актуальность данных на ней и помечая ее как активную или нет. Таким образом, при получении ошибки система переходила к следующей ноде.
Также по этой причине было принято решение перевести работу кошельков, разрабатываемых нашей командой, на отправку транзакций через Explorer.
Подключение кошельков в качестве клиентов проекта добавило новые требования. Основным из них стала необходимость проксирования сформированных транзакций в блокчейн-сеть и отправки результата клиенту. В то же время необходимо было хранить балансы адресов, чтобы не перегружать ноду запросами, а также собирать информацию о монетах сети для удобства пользователей. В старых версиях нод проксирование транзакций на них было довольно простым, так как нода брала на себя проверку попадания транзакции в сеть и только после этого возвращала результат.
Но не стоит забывать, что основным из достоинств сети Minter являются мгновенные переводы большого количества транзакций. Поэтому, чтобы не нагружать ноды необязательной для них работой, проверка наличия перешла на Explorer.
Впоследствии, с целью не перегружать проект и разделить ответственность между сервисами, было принято решение выделить эту часть в отдельный подпроект. Так появился Minter Gate.
Minter Gate
Minter Gate — это сервис, задачей которого является помощь в формировании и отправке транзакции в сеть Minter.
Сервис имеет API, который позволяет:
- Оценить комиссию за транзакцию;
- Узнать количество монет, которое вы получите при продаже;
- Узнать количество монет, которое необходимо для покупки другой монеты;
- Получить количество транзакций по адресу;
- Отправить сформированную транзакцию в сеть.
Для написания сервиса был выбран язык Go и фреймворк Gin, благодаря чему он получился легким и нагрузоустойчивым.
Дальнейшее разделение сервисов
Через несколько месяцев работы Explorer был выявлен ряд слабых мест в проектировании системы. PHP не справлялся с блоками, в которых было большое количество транзакций (>600), за время генерации нового блока, что приводило к отставанию от сети. Таблица с транзакциями разрослась, появились новые сущности. База данных требовала серьезной переработки. В итоге для увеличения скорости обработки данных было принято решение переписать часть, отвечающую за наполнение базы данных, и вынести ее в отдельный сервис.
Minter Explorer Extender
Extender — сервис, отвечающий за наполнение системы данными из блокчейн-сети. Для этого сервиса также был выбран язык Go, что позволило нам обрабатывать информацию в несколько потоков, что в свою очередь значительно увеличило производительность.
При работе с базой сервис выполняет минимальное количество запросов на чтение, кэшируя необходимые данные. Это позволило существенно снизить нагрузку на базу данных и «закрыть» одно из слабых мест.
Гибкая настройка — например, количества воркеров, обрабатывающих сущности сети (транзакции, события и т. д.), или размеров чанков, обрабатываемых этими воркерами, — позволяет добиться высокой производительности на разных конфигурациях.
Minter Explorer API
Последним был переписан API. Чтобы не разводить «зоопарк» технологий, эта часть также была переписана на Go. В качестве HTTP-фреймворка мы используем GIN. Для работы с базой мы выбрали ORM — Go-Pg, так как используем PostgreSQL, а этот проект заточен именно под нее. ORM генерирует оптимальные запросы, в отличие от аналогов, что также позволяет сократить количество обращений к базе.
Оповещения клиентов в реальном времени
В свою очередь необходимо сократить запросы к БД от Minter Explorer API, для этого мы добавили оповещение клиентов с помощью WebSocket — появление новых блоков и транзакций транслируется в момент их сохранения.
В качестве real-time messaging server мы выбрали Centrifugo. Проект заявляет поддержку большой нагрузки, а также имеет клиентские библиотеки под необходимые нам платформы: JS, iOS и Android.
Архитектура
Explorer Extender получает данные от ноды и сохраняет их в БД, параллельно отправляя эти данные сокет-серверу, который в свою очередь оповещает всех заинтересованных клиентов.
Minter Gate работает напрямую с нодой, получая от нее данные, которые необходимы клиенту для создания новой или отправки уже сформированной транзакции.
В итоге мы получили архитектуру из минимально связанных сервисов, отвечающих за узкие направления, выполняющую все поставленные перед ней задачи и способную подключиться к сети в любой момент и синхронизироваться с ней в довольно короткие сроки.
Однако прогресс не стоит на месте — так же, как и мы — и, возможно, в дальнейшем перед Minter Explorer будут поставлены новые задачи.