Недавно меня с головой захватил волшебный мир биткоин. Жажде знаний не было предела, и утолить её помогла замечательная книга «Mastering Bitcoin» Андреаса Антонопулоса и полное погружение в биткоин-разработку. Книга подробно освещает технические основы биткоин, но ничто так не помогает в изучении нового дела, как практика. Простенькое приложение на Эликсире для управления полной биткоин-нодой и связи с ней через интерфейс JSON-RPC, по-моему, – отличный «Hello, World!». Поехали! Чтобы установить соединение с полной нодой Bitcoin Core, нужно сначала где-то её раздобыть. Достаточно просто запустить свою ноду локально, ведь общедоступные ноды с открытым JSON-RPC интерфейсом можно пересчитать по пальцам. Установим демона bitcoind и настроим его в файле bitcoin.config: Определяемые значения <username> и <password> будем использовать для аутентификации при отправке запросов к биткоин-ноде. По завершении настройки самое время запустить полную ноду: Запустившись, демон полной ноды начнёт подключаться к пирам, загружать и верифицировать транзакции в блоках. Убедимся, что всё работает как нужно: Данная команда возвратит основную информацию о ноде, включая её версию и количество полученных и верифицированных блоков. Загрузка и верификация всего блокчейна может занять несколько дней, ну а мы пока продолжим работать над нашим проектом. Биткоин-нода работает через интерфейс JSON-RPC, который можно использовать для извлечения информации о блокчейне и взаимодействия с нодой. Любопытно, что инструмент bitcoin-cli, который мы использовали ранее для получения информации о ноде работает поверх JSON-RPC API. Список всех возможных RPC-команд ноды можно увидеть, вызвав bitcoin-cli help или полистав Bitcoin Wiki. Протокол JSON-RPC получает входящие команды через HTTP-сервер, а значит, можно обойтись без bitcoin-cli и прописать эти RPC-команды самостоятельно. Например, запустим getinfo вручную с помощьюcurl`: Аналогичным образом можно выполнять такие команды в любой среде программирования с HTTP-клиентом, например, в Эликсире! Продумав стратегию взаимодействия с полной биткоин-нодой, займёмся Эликсир-приложением. Создадим новый проект и обновим mix.exs, чтобы добавить в зависимости библиотеку poison, которая понадобится для шифрования и расшифровки JSON-объектов, и httpoison – один из лучших HTTP-клиентов для Эликсира. Теперь, когда мы закончили с частью, отвечающей за кодогенерацию, перейдём к реализации взаимодействия с биткоин-нодой. Начнём работать с модулем HelloBitcoin и первым делом поставим заглушку для функции getinfo: Для простоты будем взаимодействовать с этим модулем через iex -S mix. Прежде чем приступить к следующему шагу, давайте убедимся, что всё работает правильно. Вызов заглушки HelloBitcoin.getinfo должен повлечь за собой исключение времени выполнения: Отлично. Ошибка. Как и должно быть. Теперь наполним функцию getinfo содержимым. Повторюсь: нам необходимо послать HTTP-запрос методом POST к HTTP-серверу биткоин-ноды (обычно слушающему по http://localhost:8332) и передать JSON-объект, содержащий команду GetInfo и необходимые параметры. Оказалось, что httpoison справляется с таким заданием в два счёта: Сначала получим url из ключа bitcoin_url в конфигурации приложения. Адрес должен находиться в файле config/config.exs и указывать на локальную ноду: Далее, создадим словарь, представляющий нашу JSON-RPC-команду. В данном случае в поле method прописываем "getinfo", а поле params оставляем пустым. И последнее, сформируем тело запроса, преобразовав команду в формат JSON с помощью Poison.encode!. Вызов HelloBitcoin.getinfo должен возвратить успешный ответ от биткоин-ноды с кодом состояния 200, а также результат команды getinfo в формате JSON: Прекрасно. Расшифруем полученный JSON-текст в body и получим результат: Теперь результаты вызова HelloBitcoin.getinfo, полученные от bitcoind, будут представлены в более удобном виде: Обратите внимание, что необходимые нам данные ("result"), обернуты в словарь, содержащий метаданные о самом запросе. Эти метаданные содержат строку с возможной ошибкой и идентификатор запроса. Перепишем функцию getinfo так, чтобы она включала обработку ошибок и возвращала фактические данные в случае безошибочного выполнения запроса: Теперь при отсутствии ошибок функция getinfo будет возвращать кортеж {:ok, result}, содержащий результат RPC-вызова, а в обратном случае мы получим кортеж {:error, reason} с описанием ошибки. В похожей манере можно реализовать и другие RPC-команды блокчейна, например, getblockhash: Вызвав getblockhash с нулевым индексом, получим первый блок цепочки. Функция getblockhash работает верно, и она практически идентична функции getinfo.  Чтобы избежать дублирования кода, выделим общую функциональную часть в новую вспомогательную функцию bitcoin_rpc: Теперь переопределим функции getinfo и getblockhash в соответствии с функцией bitcoin_rpc: Можно видеть, что bitcoin_rpc представляет собой полноценный RPC-интерфейс для биткоин, позволяющий с лёгкостью выполнять любые RPC-команды. Если вам интересно попробовать осуществить всё вышеперечисленное на своей машине, то исходники проекта можно найти на GitHub. Ну вот и подошла к концу достаточно длинная статья, объясняющая относительно простую идею. Полная нода биткоин предоставляет интерфейс JSON-RPC, доступ к которому можно получить, используя любой язык (например, Эликсир) или стек. Биткоин-разработка – удивительно занимательная вещь, в которую интересно углубиться ещё сильнее. Следующая часть серии статей о работе с биткоином на Эликсире по ссылке. Переводчик