30 ноября 2020

Нода Waves на языке Go

Ошибка в коде

 

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

 

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

 

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

 

  • наличие криптографических библиотек
  • популярность в других крипто-проектах и в крипто-сообществе
  • простота языка для разработчиков.

 

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

 

Дополнительными бонусами при реализации ноды на Go были возможность попробовать новые подходы к реализации уже имеющихся алгоритмов и внесение в спецификации протокола Waves деталей реализации, скрытых в коде на Scala.

 

Путь к реализации

 

Проект разработки ноды Waves на языке Go был запущен осенью 2018 года. Команда всегда состояла из трех разработчиков, хотя ее состав несколько раз частично менялся.

 

План разработки был простым. Начать решили с базовых примитивов протокола Waves, включая криптографические функции, транзакции и сетевые сообщения. Затем, для пользы сообщества, была реализована клиентская библиотека к REST API ноды на Scala. Эта библиотека нашла применение в нескольких внутренних сервисах Waves. Далее для демонстрации возможностей клиентской библиотеки были разработаны утилита `chaincpm` и сервисы `Fork Detector`, `Retransmitter` и `Waves Market Data`.

 

Весной 2019 была начата разработка ноды. Перед разработчиками ставилась задача обеспечить высокую скорость работы ноды, ускорить импорт блоков. Алгоритмы консенсуса, проверки блоков и транзакций были реализованы в ходе разработки утилиты `importer`.

 

Тогда же сформировалась и концепция хранения блоков и состояния ноды. В реализации на Go решено было отказаться от хранения блоков в хранилище `leveldb`: новые блоки целиком добавляются к простому бинарному файлу, а мета-информация о них сохраняется в `leveldb`.

 

Еще одним новшеством, реализованным в ноде на Go, был адаптивный буфер применяемых блоков. Нода Scala применяет блоки одинаковыми пачками по 100 штук, а нода Go постоянно отслеживает размер блоков и изменяет их количество в буфере в зависимости от размера. То есть, если блоки пустые, то нода Go может применять их пачками по несколько тысяч, а если блоки содержат большое число транзакций, буфер может быть динамически уменьшен до нескольких десятков блоков. Такой механизм позволил значительно ускорить начальный импорт блокчейна Waves.

 

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

 

Разработка ноды на Go строилась по принципу “grey box”. Реализация какой-либо функциональности начиналась только на основе документированных сведений о ней. В качестве тестов использовались реальные данные из блокчейна, и только на последнем этапе реализации проводилось сравнение с реализацией на Scala.

 

В результате зимой 2019 года была создана полностью работающая реализация валидирующей ноды на языке Go. Единственным ограничением была неспособность ноды генерировать новые блоки. На этом и сосредоточились разработчики, и весной 2020 года в тестовой сети, а через несколько недель и в основной сети были запущены генерирующие ноды, реализованные на языке Go.

 

В это время разработчики на Scala активно развивали функциональность ноды и готовили релиз версии 1.2 Malibu, который увидел свет в августе 2020 года. А в октябре была реализована поддержка протокола Waves 1.2 Malibu и в версии ноды на Go.

 

В дальнейшем все крупные релизы протокола Waves будут выходить синхронно в реализации на Scala и Go.

 

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

 

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

 

Потенциал для улучшений

 

Реализация ноды Waves на Go — продукт достаточно молодой, и он не может похвастаться таким обилием пользовательских интерфейсов, как нода на Scala. В ноде Go полностью реализован новый gRPC интерфейс (gRPC API) для доступа к данным ноды и блокчейна, но поддержка оригинального REST API ноды реализована только частично. Это накладывает некоторые ограничения на использование ноды на Go.

 

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

 

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

 

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

 

Как запустить ноду на Go

 

Начать работать с нодой Go очень просто: достаточно зайти на [страницу релиза в Github](https://github.com/wavesplatform/gowaves/releases/tag/v0.8.2), скачать исполняемый файл под свою платформу и запустить его, следуя [короткой инструкции](https://github.com/wavesplatform/gowaves/blob/master/README.md).

 

Если у вас возникнут трудности, вопросы или предложения, создайте [Issue на Github](https://github.com/wavesplatform/gowaves/issues) или пообщайтесь с разработчиками в чате в [Telegram]() или [Discord]().

 

Обсудить в Discord!

Waves.Tech
  • Зарегистрирован: 22 мая 2012 г.
  • Локация:London/United Kingdom
  • Сайт:penroseisparty.com