Первый байндинг для Exonum: почему мы выбрали Java

    Ядро нашего фреймворка для разработки приватных блокчейнов Exonum написано на Rust, поскольку этот ЯП ориентирован на безопасность работы с памятью. Однако наряду со многими преимуществами, Rust имеет ряд особенностей, усложняющих «взаимодействие» с ним: его синтаксис непривычен для многих разработчиков, а порог вхождения довольно высок.

    Чтобы упростить работу с платформой Exonum и сделать её более доступной для аудитории, мы решили написать байндинг-библиотеку. Языком для байндинга стал Java.

    Почему мы выбрали Java, рассказываем под катом.


    / Exonum

    Пара слов об Exonum


    Exonum — это наш open source фреймворк для разработки приватных блокчейнов. Блокчейн на Exonum значительно быстрее публичных блокчейнов и способен обрабатывать до 5 тыс. транзакций в секунду. Для сравнения, в Ethereum этот показатель равняется нескольким десяткам, а у биткойна он и того меньше.

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

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

    В прошлом году с помощью платформы Exonum был реализован Государственный земельный кадастр Украины. А до этого на Exonum запустили проект по управлению земельным имуществом в Грузии. Еще мы ведем переговоры с десятками компаний из Fortune 500 и Евросоюзом о внедрении нашей системы в их бизнес-процессы.

    Ядро Exonum написано на Rust. Выбор обоснован тем, что этот ЯП фокусируется на безопасности и скорости — на некоторых задачах он работает быстрее, чем Java, Go, C и C++. При этом Rust гарантирует безопасность памяти и предотвращает гонки, когда два потока пытаются получить доступ к одним данным.

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

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

    fn use_vec() {
        let vec = make_vec();  // завладеть вектором
        print_vec(vec);        // передать его print_vec
    
        for i in vec.iter() {  // продолжить использовать vec
            println!("{}", i * 2)
        }
    }
    

    Если «скормить» его компилятору, то тот сгенерирует ошибку:

    
    error: use of moved value: `vec`
    
    for i in vec.iter() {
             ^~~
    

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

    Почему мы решили создать байндинг


    «Шумный» синтаксис

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

    Подобные возможности очень важны при работе со смарт-контрактами в Exonum. Благодаря им «умные» контракты нашего фреймворка имеют большую производительность и безопасность доступа к памяти, чем, например, решения Ethereum.

    В целом, Rust похож на другие императивные языки (в частности, синтаксис Rust напоминает C/C++), но представляет большое количество новаторских концепций. В нем есть циклы, условия, функции, но при этом появляются области владения и типажи. Поэтому тем, кто ни разу не работал с этим ЯП, может быть сложно читать программы на нем.

    Первое время они кажутся «инородными». «Боли» добавляет непривычное управление памятью (по сравнению с другими языками), которое делает Rust таким безопасным. Осенью прошлого года создатели Rust опубликовали результаты опроса среди 5 тыс. членов комьюнити. Почти четверть респондентов отметила, что с Rust сложно работать.

    Слишком «требовательный» компилятор

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

    Такой подход позволяет писать надежный код (что важно при работе с блокчейнами в целом), однако имеет и обратную сторону медали. Порой приходится писать программы на Rust так, чтобы компилятор «понял», что вы не выполняете запрещенных операций с памятью. А так как язык пока еще молод и продолжает развиваться, каких-либо устоявшихся практик может и не быть. Потому, как говорит разработчик Exonum Илья Богданов, многие паттерны приходится находить методом научного тыка.

    Небольшое комьюнити

    Третьей причиной создания байндинга стало маленькое Rust-комьюнити. Хотя сообщество этого ЯП довольно дружелюбное, а его члены всегда готовы ответить на вопросы, язык «страдает» от небольшого количества литературы и библиотек. Однако здесь будет справедливо отметить, что эта проблема постепенно решается.

    Последние годы Rust активно продвигают Mozilla и Samsung, что положительно сказывается на количестве разрабатываемых библиотек и новых «оберток» для уже существующих решений из мира C/C++. «Учебники» по языку также начинают постепенно появляться. Из тех, что уже есть, стоит выделить «Основы Rust» Иво Балберта (Ivo Balbaert), онлайн-руководство на официальном сайте и недавнюю книгу одного из разработчиков проекта Rust Стива Клабника (Steve Klabnik) «Язык программирования Rust».

    Почему выбрали Java


    Одной из главных причин, определивших выбор, стало огромнейшее комьюнити этого ЯП. По данным исследования, проводимого на площадке Stack Overflow в прошлом году, Java стоит на третьем месте по популярности (его обошли только JavaScript и SQL). Из 64 тыс. опрошенных разработчиков почти 40% пишет на Java.

    Из-за размеров сообщества этот ЯП обзавелся обширным набором инструментов. Сюда входят IDE, аналитические решения, бенчмарк-фреймворки и др. Их настолько много, что некоторые компании обязывают разработчиков использовать только определенные IDE и фреймворки, чтобы избежать «расщепления» рабочей среды.

    При этом у Java простой синтаксис и есть Java Native Interface (JNI), который может работать с C Application Binary Interface (ABI). К тому же Java дает возможность использовать другие языки на стеке JVM: Scala, Kotlin, Clojure.

    И, наконец, Java-машина кроссплатформенна: код Java выполняется в байт-код, который интерпретируется и запускается на Windows, MacOS, Linux-платформах. При этом язык Java сильнее завязан на open source (по сравнению, например, с C#). Инструменты разработчика Java в большинстве своем бесплатны: это и JDK, и основанные на нем интегрированные среды разработки — JDeveloper, NetBeans, Eclipse и др. При этом на специализированных ресурсах можно найти огромное количество открытых проектов (например, на GitHub). Также существует множество руководств по работе с open source технологиями.

    Основные вызовы при разработке Java Binding


    Разработка Java Binding была долгой и сложной (и она до сих пор ведется). Нам нужно было учесть все те особенности, которые делают языки Rust и Java такими разными.

    Например, одна из сложностей заключалась в организации менеджмента ресурсов. Дело в том, что в Java есть Garbage Collector, а в Rust — нет. Его убрали в одной из ранних версий, поскольку разработчики пришли к выводу, что смогут обеспечить такой же уровень надежности с помощью системы типов.

    Java GC, хотя и имеет повышенное ресурсопотребление (он заставляет все функции отдавать ему неиспользуемые объекты, чтобы избежать потенциальных утечек памяти), довольно удобен. Поэтому нам нужно было реализовать механизм очистки ресурсов, который бы понравился Java-разработчикам.

    Еще одна сложность оказалась связана со специфическими структурами данных, представленными в Exonum, — деревьями Меркла (Merkle trees). Exonum использует их, чтобы комбинировать состояния блокчейна в единый хеш. Это дает возможность доказывать подлинность транзакций без необходимости связываться с несколькими полными узлами сети. Эта функциональность важна для работы наших легких клиентов, потому её также было необходимо интерпретировать на Java.

    Java API практически полностью повторяет Rust API. Так сделано, чтобы нам было проще адаптировать документацию и упростить работу пользователям. Мы подготовили отдельное руководство по настройке и запуску узла Exonum с Java Binding App.

    Для создания сервисов на Java, можно использовать шаблонный генератор проектов. Нужно установить Maven 3 и запустить команду:

    $ mvn archetype:generate \
        -DinteractiveMode=false \
        -DarchetypeGroupId=com.exonum.binding \
        -DarchetypeArtifactId=exonum-java-binding-service-archetype \
        -DgroupId=com.example.myservice \
        -DartifactId=my-service \
        -Dversion=1.0
    

    Можно использовать интерактивный режим:

    $ mvn archetype:generate \
        -DarchetypeGroupId=com.exonum.binding \
        -DarchetypeArtifactId=exonum-java-binding-service-archetype
    

    Полное руководство с примерами по настройке Java-сервиса вы найдете в документации на официальном сайте проекта Exonum. Рекомендации по запуску узла Exonum есть в репозитории на GitHub.


    / Exonum

    Планы на будущее


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

    Также ведется работа над документацией, написанием example-проектов, SDK для упрощения интеграции с приложением на блокчейне и улучшением UX в целом. Полную дорожную карту проекта вы найдете в репозитории на GitHub.

    Там же вы можете взять все исходники, чтобы попробовать Java Binding и написать свой сервис на Java для Exonum. Если в процессе возникнут вопросы, то свяжитесь с нашей командой разработчиков в Gitter. Расскажут и помогут по мере возможности.

    Bitfury Group

    82,06

    Cофтверные и хардверные решения на Blockchain

    Поделиться публикацией
    Комментарии 11
      +2
      При этом язык Java сильнее завязан на open source (по сравнению, например, с C#, где сложнее с лицензиями и обязателен официальный Windows)

      Вот с этого места поподробнее, пожалуйста: какие сложности с лицензиями и, особенно, про «обязательный официальный Windows»? Очень интересно.
      +2
      оооочень долгое введение, а потом сразу статья закончилась :-(
      хотелось прочитать хотя бы про общую схему как вы туда java прикрутили
        +3

        Общая схема стара как мир — часть Rust-интерфейсов вынесена в C-API, которое цепляет Java через JNI. Для этого есть замечательная библиотека jni-rs (кстати сказать, недавно она перешла под крыло разработчиков Exonum Java Binding). Все, что нужно Java-сервису (мы так называем смарт-контракты) со стороны блокчейн-библиотеки — линкуется в виде динамической Rust-библиотеки.
        Для запуска всего этого есть отдельное небольшое приложение EJB App — оно стартует JVM, линкуется со всеми необходимыми библиотеками и заодно настраивает ноду Exonum.
        Общая схема получается такая (не умею рисовать, не бейте камнями):
        image

        +1
        Интересно, а с точки зрения производительности JVM версия сильно потеряла?
          +1

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

          +3
          Как мне кажется, Java не намного проще Rust, если вообще проще :)
            0

            Какие критерии рассматривали, когда выбирали язык для написания? Вы указали "безопасность работы с памятью, скорость, гонки", но наверное есть еще? Наличие разработчиков? Предыдущие наработки? Жесткое/мягкое время?
            Рассматривалась ли, например, Scala? Язык во многом похож на Rust:


            • компилируемый (в байт-код JVM)
            • такая же типобезопасность,
            • статическая типизация с генериками
            • безопасная работа с памятью
            • аналогичные Option, Result, match.

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


            Вот пишут, что Waves сделали блокчейн на Scala всего в ~20К строк (в коде bitcoin примерно 100К строк).
            Если не секрет, сколько у вас получилось строк?

              0
              el777 Критерии выбора Java в статье достаточно раскрыты, и вы все правильно подметили в своем комментарии.
              Почему первым языком был выбран Java, а не Scala — число разработчиков, широко используемая экосистема, большое количество legacy проектов на Java. Потенциально Scala тоже хороший вариант.

              Про количество строк не секрет. В ядре Exonum сейчас около 80К сейчас, включая тесты, дело, тесткит и стандартные сервисы. А в Java Binding 9K — это Java код и XML.

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

              Самое читаемое