В прошлой статье мы рассмотрели причины, по которым нам может понадобится свой blockexplorer. Замечу, что список этот далеко не полный, но будем считать, что мы определились - нам нужен свой источник данных о транзакциях и их связях с адресами.
Попробуем определить, что нам для этого понадобится. Очевидно, нам понадобится для начала копия желаемого блокчейна, причем эта копия должна сохранять актуальность (синхронизироваться с соответствующей сетью). Последнее намекает, что либо нам нужно реализовать полностью соответствующий протокол (что очевидно будет избыточно и крайне дорого) либо - установить соответствующее программное обеспечение, что более рационально. Для Ethereum это будет например Geth (go-ethreum), bitcoind или btcd (реализация на golang) для Bitcoin, или любое соответствующее программное обеспечение. Главное условие - доступ к полному блокчейну (или той части, которую вы хотите отслеживать).
Для ясности давайте вспомним, как должна хранится информация в блокчейн. Bitcoin и его потомки (назовем их “классическими”) используют концепцию UTXO (Unspent Transaction Output). Результат транзакции можно назвать “выходом” (Out), И каждая транзакция за одним исключением должна ссылаться на “Вход” (“In”). Таким образом каждая танзакция содержит адрес-отправитель и адерс получатель в той или иной форме (не будем сейчас вдаваться в детали, на достаточно самого факта наличия такой информации). Побочный эффект - из этой информации мы можем так же построить дерево транзакций, которое позволит отслеживать каждый прошедший по сети сатоши.
Сеть Ethereum обращается с информацией несколько иначе. Как я упомянул в прошлой статье, концепция Ethereum отличается, и хранится информация непосредственно о балансах адресов. Однако информация о транзакциях по прежнему находится в блоках и хранится в сети. Таким образом индексация транзакций и их взаимосвязь с адресами по прежнему возможна. В этой статье я намеренно не буду касаться смартконтрактов и операций с токенами (ERC20/ERC721/ERC1155) и так называемых “Internal Transactions” - рассмотрение этой темы требует отдельной статьи.
А что нам не доступно? Блокчейны, использующие алгоритмы “доказательства с нулевым разглашением” (“Zero-knowledge proof”), такие как Monero и ZCash не могут быть индексированы таким образом, что следует из их концепции.
Далее процесс будет прямолинеен и прост, хотя крайне затратен по времени и по объему дискового пространства, которе вам понадобится.
Шаг первый - запрашиваем начальный блок через RPC (реализация зависит от конкретной сети) и перебирая транзакции по одной, декодируем их и выделяем информацию, которую хотим индексировать. Вероятно нас будут интересовать хеш транзакции, использованные адреса, направление транзакции, время и номер блока. Полный перечень зависит от ваших задач и от доступных вам ресурсов (в основном бутылочным горлышком будет дисковое пространство).
Далее мы сохраняем интересующую нас информацию в каком либо варианте базы данных, берем следующий блок и повторяем описанные действия. Не слишком изящно, однако другого рецепта к сожалению нет.
И возникает логичный вопрос - а почему собственно разработчики блокчейн не дают доступа к такой очевидно полезной информации? Что мешает сразу, при синхронизации с сетью сохранить и индексировать такие данные?
Ответ будет пересекаться с объяснением, почему именно дисковое пространство будет бутылочным горлышком.
Для начала маленький пример. Те, кто разворачивал node для Ethereum знают, что есть несколько вариантов синхронизации Geth. В документации, раздел “Sync modes” упомянуты Full nodes и Light nodes. Последние нас не интересуют, а вот Full nodes в свою очередь условно разделены на Snap, Full и Archive. И вот тут начинается интересное, особенно если рассмотреть внимательно иллюстрацию, кто собственно из них кто. Snap-нода хранит подробную информацию о последних 128 блоках и пару контрольных точек (checkpoint) в относительно недавнем прошлом. Full нода, как следует из иллюстрации хранит контрольные точки (checkpoint) с некоей периодичностью практически до “начала времен”. Archive хранит уже полную информацию, за все время существования Ethereum. Если задаться целью и выяснить, какой объем данных хранит полная (Full) нода, то окажется что это около 1Tb (на момент написания статьи). Не будем вдаваться в механизмы “реорганизации сети”, и прочие ухищрения. Нам интересно другое, объем данных, хранимых Archive нодой - уже около 16Tb(!). Получается, что нам не доступно более 90% информации о блокчейн?
Если поставить один несложный эксперимент - многое становится на свои места.
Воспользуемся сервисом etherscan.io и найдем случайную транзакцию “из начала времен”, например 0x7d7062d6f865931e0bbbccea46551a73d5d58a6ef618d5592c35b5256a65e9ba (примерно за август 2015 года) и попробуем получить информацию о ней с помощью консоли локального Geth, синхронизированного в режиме full. Мы же можем получить такую информацию, да?
Welcome to the Geth JavaScript console! instance: Geth/v1.12.0-stable-e501b3b0/linux-amd64/go1.20.3 at block: 19122581 (Tue Jan 30 2024 23:24:11 GMT+0000 (UTC)) datadir: /home/eth/ethereum modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 To exit, press ctrl-d or type exit > eth.getTransaction("0x7d7062d6f865931e0bbbccea46551a73d5d58a6ef618d5592c35b5256a65e9ba") null
Эм… То есть, информации о транзакции нет? Не совсем… Давайте попробуем просмотреть содержимое блока, в котором находится искомая транзакция, благо мы знаем номер блока:
> eth.getBlockByNumber(122546) { … hash: "0xc58aa38cf7df6050d3be43f1557d61e3a28e3f34d7818b1644e6a9972003e80a", … number: "0x1deb2", … transactions: ["0x7d7062d6f865931e0bbbccea46551a73d5d58a6ef618d5592c35b5256a65e9ba"], … }
Так вот же она, на месте! Если выполнить eth.getBlockByNumber(122546, true) (дополнительный параметр, указывающий запрос на выдачу всей информации о транзакциях в блоке), то мы получим и содержимое транзакции, и например узнаем, что отправителем был адрес 0x5685620dce626248ccb7121e87fbc098fd5310bd а получателем 0x9b0a028eafdecde3afc0fd00b7937098388b7c8a, как и всю сопутствующую информацию. Почему же мы не смогли получить эту информацию, запрашивая напрямую?
Не вдаваясь в технические детали - только архивная нода полностью индексирует весь блокчейн и все связи между блоками, транзакциями и адресами. И “вес” этих индексов - это как раз те самые недостающие 15 террабайт информации.
Это дает нам понимание, к каким объемам данных нам стоит готовится. Однако совсем не обязательно, что ваши конкретные задачи требуют такой подробной индексации, вполне возможно, что ваша база данных будет несколько компактнее.
Что касается bitcoin - там есть подобные механизмы, но объем данных несравнимо меньше. На момент написания статьи, объем блокчейн bitcoin оставляет смехотворные 545Gb, так что проблем с ним будет значительно меньше.
В заключении пару слов, о том, как можно ускорить процесс индексации. Совсем не обязательно обрабатывать все запросы через обращение к клиенту соответствующей сети. Чаще всего программное обеспечение для работы с блокчейн является открытым, а форматы баз данных достаточно стандартизированы. Возможно стоит рассмотреть вариант работы непосредственно сданными на диске уже синхронизированной ноды, и лишь потом - синхронизацию новых блоков.
В следующей статье мы попробуем собрать из подручных средств минимальную реализацию для подготовки базы поиска по адресам для разных блокчейнов.
Читайте также
Криптовалюта своими руками: а теперь серьезно
Создание токена-пустышки малыми силами мы уже рассматривали. А теперь давайте попробуем разобраться, что понадобится для создания полноценной криптовалюты.
Что такое ликвидность криптовалют? Самые ликвидные биткоин биржи
Этот термин обычно используют на финансовых рынках для того, чтобы описать насколько легко можно конвертировать актив в фиат.