Ядро нашего фреймворка для разработки приватных блокчейнов 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#, где сложнее с лицензиями и обязателен официальный Windows). Инструменты разработчика 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. Расскажут и помогут по мере возможности.
Автор: BitfuryRussia