Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
vik
7 лет назад

🤘 BlockSnobbery (JS Разработчикам) - решение для безотказного анализа блоков GOLOS/STEEM в реальном времени без пропусков и задержек

Если вы используете JS приложения которые подразумевают подробный анализ блокчейна голоса в реальном времени - этот пост для вас

BlockSnobbery (JS Разработчикам)

Исходный код 📦 GitHub/vikxx/bots


За последний месяц значительно прибавилось новых пользователей у ботов. К ним подключились разнообразные инициативы в том числе топовые держатели "силы голоса", в связи с этим я решил сделать максимальный упор на надежность работы сервисов, чтобы "каждый голос был услышан" :)

Задача и ее решение

Ранее я уже писал о том, что для решения низкой пропускной способности API нод я использую redis:
🚀 [Кеширование API golos]
Блоки в реальном времени собирает и кеширует один единственный скрипт, а все остальные боты и приложения берут данные о последнем блоке из кеша, таким образом удается запустить несколько сотен независимых сессий ботов при этом не создавать никакой нагрузки на ноду голоса. Этот способ решил вопрос масштабируемости нод, однако сам процесс кеширования блоков оказался не идеальным и время от времени в силу разных технических причин случались пропуски. Но еще более назойливой проблемой был рост задержки при длительной постоянной работе и если случался рестарт - терялись все блоки в диапазоне задержки.

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

BlockSnobbery.js - в реальном времени получает блоки и транслирует их в redis кеш.

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

💽 Установка

Если не установлен - установите Redis: Quickstart

mkdir blocksnobbery

cd blocksnobbery

wget https://raw.githubusercontent.com/vikxx/bots/master/BlockSnobbery/BlockSnobbery.js

npm install redis

npm install golos-js*


🔌 Запуск

node BlockSnobbery.js

Запуск с параметрами
Запуск и синхронизация с указанного блока
node blocksnobbery.js 1234565

Запуск и синхронизация с самого свежего блока в блокчейн
node blocksnobbery.js now

Запуск и синхронизация с последнего обработанного скриптом блока.
node blocksnobbery.js

Для постоянной работы рекомендуется использовать pm2
npm install pm2 -g
pm2 start BlockSnobbery.js


pm2 stop BlockSnobbery - Остановка
pm2 restart BlockSnobbery - Рестарт
pm2 logs BlockSnobbery - Лог в реальном времени


*npm install steem для использования со steemit, требуется изменить адрес ноды в файле BlockSnobbery.js


📡 Использованиe

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

Вам нужно только запустить скрипт в фоне. Далее вы можете подключиться к стриму любым удобным образом и получать поток данных с блокчейна.

Пример получения блоков на JS


  // При каждом обновлении блока вызывается функция

  sub.on("message", (channel, message) => {
         
   // Переменная message всегда содержит актуальные операции из блока!
  
   });

   sub.subscribe("golosblocks");

Принципы работы и исходный код

Исходный код 📦 GitHub/vikxx/bots

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

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

В динамическом интервале используются два API запроса

С помощью первого мы узнаем номер самого недавнего блока на голосе head_block_number*
С помощью второго мы получаем все операции из блока.

Каждый раз получая операции из блока скрипт сохраняет его номер как последний обработанный блок (lastblock), далее применяя сложную систему таймеров скрипт получает следующий блок. Если последовательность номеров блоков (так называемой "высоты") нарушена задержками в ПО, канале связи или по любым другим причинам - BlockSnobbery будет выстраивать правильную последовательность, чтобы обрабатывать блоки строго один за другим.

Кроме коррекции последовательности, алгоритм заложено так же и коррекция задержки. Если актуальный временной штамп и временной штамп последней операции в блоке больше 3 секунд (или любого указанного значения), включается форсированный режим перебора блоков по 40ms (можно уменьшить на мощном железе)

👨‍💻 Мониторинг

Запустив скрипт вы можете следить за ходом работы в консоли.

  • В первой колонке номер обрабатываемого блока

  • Во второй, в данном состоянии, отображена надпись [1 Sequence ✔] - это нормальная последовательность, где 1 означает, что мы обрабатываемый самый свежий блок.

  • Третья колонка [⌛️ Age of last TX 0.736s] - это возраст последней транзакции в блоке. Вычислен он по принципу - серверное время минус временной штамп транзакции.

  • Четвертая колонка [🔴 Interval ~ < 3s ✂️ 68ms] сообщает о том, какой используется интервал и насколько он оптимизирован. Скрипт запускает таймер на 3 секунды для получения следующего блока, но поскольку до запуска таймера происходит взаимодействие с API - появляется задержка и чтобы соблюдать необходимый интервал в 3 секунды - отрезается рассчитанное время выполнения запросов от следующего таймера.

  • Пятая колонка вида [📝 Operations streamed: 11] отображает сколько операций было в блоке и сообщает, что они были успешно отправлены в redis стример для работы с PUB/SUB

Примеры поведения в стрессовых ситуациях

😈 В качесте тестов создавалась имитация разных проблем и неблагоприятных условий

Искусственное условие - "тормознутость" скрипта

overtake

Представим, что скрипт тормозит и долго обрабатывает блоки. Так долго, что растет разрыв между последним обработанным блоком и последним блоком в блокчейн. Разрыв устраняется автоматически когда начинает превышать указанный лимит. В примере максимально-допустимая задержка 7 секунд.
Обратите внимание на значение Age of last TX
Когда возраст транзакции превышает допустимый лимит в 6 секунд, во второй колонке отображается режим [2 Overtake 🏃], а в четвертой активируется высокая скорость интервала, что позволяет быстро "догонять" номер последнего блока соблюдая последовательность снова возвращаясь на режим, где возраст транзакции меньше 6 секунд.

Искусственное условие - тормознутость ноды или спешка скрипта

Outrunin'

Противоположный первому примеру случай.
В логах [🛠 Outrunning] 🚑 Return to sequence 1B
Когда скрипт пытается запросить еще не существующий блок - алгоритм корректирует его данные о последовательности и возвращает на правильную последовательность

Искусственное условие - Рэндомные торомза или спешка

overslow

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

Искусственное условие - Подсовываем якобы пустые блоки

Включим режим очень плохой ноды и попробуем обмануть скрипт якобы пустым блоком

Doublecheck

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

Искусственное условие - Остановка скрипта, ребут сервера, аварийный рестарт

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

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

Это может быть удобно для тех, кто будет использовать своих ботов не на сервере - а на обычных пк, которые нет смысла держать включенными 24\7. Вы просто запускаете скрипт когда вам угодно и ждете синхронизации.


Примеры параметров запуска

Запуск и синхронизация с указанного блока
Например
node blocksnobbery.js 10000000

Скрипт начнет работать с блоками начиная с 10000001 в ускоренном режиме

Запуск и синхронизация с самого свежего блока в блокчейн
node blocksnobbery.js now

Запуск и синхронизация с последнего обработанного скриптом блока.
node blocksnobbery.js

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

📡 Внешнее подключение

Все тесты проводились на сервере без ноды голоса, а скрипт подключался к блокчейну через мою паблик ноду wss://api.golos.cf то есть были созданы условия обычного пользователя без спец. софта блокчейна.
Кроме того, можно подписываться на стрим Redis с другого сервера или транслировать в браузер.

На изображении пример, где BlockSnobbery.js запущен на сервере 1 (справа)
А на сервере 2 (слева) показан результат подключения к redis сервера 1.

📌 NB*

head_block_number VS last_irreversible_block

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

Если вы хотите работать только с необратимыми транзакциями - вас следует выбрать last_irreversible_block. Но возраст последнего необратимого блока - около минуты и если ваше приложение подразумевает моментальную реакцию - это будет неудобно.

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


📚 Читайте также:

golos.cf/reg.html и golos.cf/steem - создание аккаунтов в стим и голос без верификации и ограничений
Установка ноды Golos с public API
Отчет делегата @vik
Обновление списка ботов и сервисов для голоса
Чатбот для рассылки бонусов подписчикам
Деградант и GolosChain

1
906.082 GOLOS
На Golos с January 2017
Комментарии (10)
Сортировать по:
Сначала старые