Главная
первый урок
следующий

Как работают блокчейн-индексеры и зачем они нужны

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

В этом курсе мы расскажем обо всем, что нужно знать о блокчейн-индексерах: как они работают, какие есть виды индексеров и как использовать каждый из них с практическими примерами.

Простое объяснение работы индексеров

Индексеры — это программы для трансформации большого объема информации в базу данных с удобным и быстрым поиском. Чтобы было проще понять их роль и принцип работы, лучше начать с примера — библиотеки.

В библиотеке на полках хранятся тысячи книг. Обычно они отсортированы по жанрам и фамилиям авторов. Читатель быстро найдет полку с романами Лавкрафта или справочник по садоводству.

Но допустим, читатель хочет найти что-то конкретное: стих про акацию, роман про архитектора заправки, или все книги написанные в 1962 году. Ему придется проверять все книги в библиотеке, пока не найдет нужные.

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

Теперь можно вернуться к блокчейн-технологиям. Чтобы найти транзакцию по ее хешу или адресу отправителя, придется проверять каждую транзакцию в каждом блоке. Лучший выход из положения — создать отдельную базу данных со всем содержимым блокчейна с указателями для быстрого поиска информации по специфическим запросам и обращаться к ней. Это и делают индексеры.

Детально о базе данных и индексах

База данных — это набор организованных данных. Обычно для хранения используются таблицы: в строке — значения конкретного ключа, в столбцах — значения одного типа.

Разработчики также часто называют базами данных СУБД — системы управления базами данных, то есть программы для работы с базами данных. К ним относятся MySQL, PostgreSQL, Oracle Database, Microsoft Access и другие.

Большинство баз данных — реляционные. Они не просто сортируют и записывают данные в таблицы, но и создают между ними связи. Например, база данных библиотеки может использовать три таблицы:

  • Список книг. Названия всех книг в библиотеке и информация о них;
  • Список читателей. Имя каждого читателя и его контактные данные;
  • Книги на руках. Реестр книг, которые кто-то взял почитать. Ячейка с названием книги ссылается на запись в Списке книг, а ячейка с именем читателя — на запись в Списке читателей.

1

Эти таблицы помогут организовать хранение данных. Но они не сильно ускорят поиск книг, потому что для нахождения конкретного значения в этой таблице придется использовать медленный и неэффективный поиск row-by-row.

Чтобы ускорить поиск, можно хранить данные не в таблице, а в более продвинутой структуре данных, например в сбалансированном бинарном дереве (B-Tree).

Для примера рассмотрим B+ Tree. Корень и узлы помогают маршрутизировать запрос, а ссылки на ячейки в основной таблице или сами значения хранится в листьях.

2

Допустим, нам нужно найти запись о книге Ender's Game. Поиск произойдет так:

  1. Буква E в названии Ender's Game меньше буквы N в Netherlan, выбираем левую ветку.
  2. Буква E меньше буквы G в The God Machine, выбираем левую ветку.
  3. Буква E больше буквы C в The Call of Chtulu, выбираем правую ветку.
  4. Нашли ячейку Ender's Game.

B+ Tree и другие древовидные структуры хранения данных сильно оптимизируют поиск. Например, если в базе данных есть миллион строк, то для поиска одной нужной потребуется не более 20 операций. Без использования дерева количество операций может достигать количества строк в таблице, то есть миллиону.

Данные можно хранить прямо в дереве, но гораздо эффективнее использовать его в качестве дополнительного индекса. В примере с книгами библиотекарь мог бы сделать индексы в B-Tree для каждого типа ключей: названия книг, авторов, имен читателей, их контактных данных и дат, когда они взяли и вернули книги.

Чем больше столбцов и потенциальных ключей в базе данных, тем больше индексов можно создать для эффективного поиска, а они занимают место. В 2019 году Baking Bad рассказали, что индексы базы данных размером 1 ГБ занимают в четыре раза больше места.

3

Зачем нужны индексеры в блокчейне

Блокчейн-протоколы работают благодаря нодам, которые обрабатывают операции, обеспечивают безопасности сети, и самое главное — хранят копии блоков в хронологическом порядке. Ноды валидаторов условно делятся на два типа: легкие с копией последних блоков и архивные с полным блокчейном. Пользователь может получить ончейн-данные с собственной или публичной ноды с помощью интерфейса Remote Procedure Call API (RPC), чтобы запросить данные из блокчейна.

Однако RPC не предназначен для работы со сложными запросами и быстрого поиска по блокчейну. Например, чтобы получить детали об операции, нужно точно знать где их искать.

Попробуем получить данные о транзакции с помощью Tezos client и RPC API — opRjkzJxJ1xZaUnBDykGUjrRV8qgHFvchcYnbkkcotS1Y7idCSL.

4

Выделенная синим строка на скриншоте — команда, которую мы использовали для получения данных:

tezos-client rpc get /chains/main/blocks/2283698/operations/3/2.

Цифры в команде означают следующее:

  • 2283698 — уровень блока, в котором была операция;
  • 3 — индекс типа источника (инициатора) операции. 3 означает, что ее инициировал пользователь;
  • 2 — индекс операции в конкретном блоке.

То есть, чтобы получить детали конкретной операции, нам нужно знать ее точное положение в блокчейне: уровень блока, тип инициатора, индекс в блоке. Чтобы узнать это, нам нужно по очереди проверить все блоки на наличие нужного хеша, что медленно и неэффективно.

Индексеры упрощают задачу получения нужных данных из блокчейна. Они запрашивают у нод полные блоки и записывают их в собственные базы данных. Затем индексеры создают собственно индексы — дополнительные структуры данных, оптимизированные под быстрый поиск данных (помните B-Tree?), которые хранят либо сами данные, либо ссылку на соответствующее место в основной базе данных. При поиске каких-либо данных индексер ищет их в соответствующем индексе, а не в основной базе.

5

На скриншоте — контракт USDT, проиндексированный Que Pasa. Индексер создал таблицы для каждой точки входа и структуры данных в хранилище, а также создал индекс для каждой таблицы. С их помощью мы можем найти баланс случайного держателя USDT по его адресу за 0,064 миллисекунды вместо того, чтобы часами проверять блоки в поисках последней операции и изменения баланса указанного адреса.

6

Список таблиц, схем индексов и синтаксис запросов зависит от индексера и базы данных, которую он использует. Например, аналогичный запрос баланса USDT от публичного TzKT будет выглядеть так:

https://api.tzkt.io/v1/tokens/balances?token.contract=KT1XnTn74bUtxHfDtBmm2bGZAQfhPbvKWR8o&account=tz1a1RTsGUbads3VucUQDxJF4EDXkDWcDHPK
  • желтый — просто ссылка на TzKT API;
  • зеленый — путь к таблице базы данных TzKT с балансами токенов;
  • синий, начинается с ? — первый поисковый фильтр, в котором мы указываем адрес нужного контракта;
  • красный, начинается с & — второй поисковый фильтр, в котором мы указываем адрес держателя.

Кроме быстрого поиска по базе данных, у индексирования есть еще одно преимущество перед поиском по блокчейну: возможность кастомизировать правила индексирования. Например, TzKT предоставляет для токенов дополнительный индекс, в котором каждому FA1.2 и FA2 токену присваивается внутренний id. В результате вместо поиска по сравнительно длинному адресу контракта индексер будет сравнивать короткие числа, что сделает поиск данных еще быстрее.

7

Блокчейн-индексеры делятся на два типа: полные и селективные.

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

Лучшие примеры полных индексеров с публичными API — TzKT и TzStats. Они позволяют найти практически любую информацию, которая когда-то попала в блокчейн Tezos.

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

Из популярных селективных индексеров мы рассмотрим Que Pasa и фреймворки для создания индексеров DipDup и Dappetizer. Их используют многие проекты Tezos, например Teia.art и другие NFT-маркетплейсы сделали собственные индексеры на базе DipDup для работы с NFT.

Какие данные можно получить через блокчейн-индексер

Точный список запросов и фильтров зависит от выбранного индексера. Но в общем от полного индексера можно получить информацию про:

  • аккаунт — баланс tez, историю операций, тип адрес, статусы вроде «бейкер» и «делегатор» и другое;
  • блок — хедер, содержание блока, метаданные вроде адреса и соцсетей бейкера, которы его создал;
  • контракт — описание, точки входа, баланс, код в Michelson, содержание хранилища или конкретной big map;
  • бейкеров и делегаторов — кто сколько заработал, кто эндорсил конкретный блок, сколько делегируют пользователи;
  • протокол — какой сейчас цикл, что на голосовании, какая эмиссия tez.

Мы взяли несколько интересных и простых примеров для вызова индексеров BetterCallDev и TzKT. Переходите по ссылкам и вставляйте в адресную строку свой адрес вместо tz1…9v4, чтобы получить данные о своем кошельке:

Где применяются индексеры

Многие приложение, которое работает с ончейн-данными, использует индексер.

Самый простой пример работы с индексером — блокчейн-кошелек. Например, чтобы отобразить балансы токенов пользователя, Temple Wallet запрашивает эти данные у индексера TzKT, сортирует их по убыванию и отображает логотипы токенов из метаданных контракта.

8

Попробуйте сами: перейдите по этой ссылке и замените tz1…9v4 на адрес своего кошелька. TzKT вернет вам балансы всех токенов, которые есть на вашем адресе. Это тот же запрос к TzKT API, который использует Temple: '/tokens/balances' в константах getTokenBalances и getNFTBalances.

По такому же принципу Temple Wallet получает детали операций, отображает NFT, награды за делегирование, стоимость ваших токенов и другие данные. Однако, для разных запросов он использует разные источники, например, курс XTZ он запрашивает у Coingecko.

Другие блокчейн-приложения работают по похожему принципу:

  • сайты децентрализованные биржи с помощью индексеров получают исторические данные о балансах каждого пула, операциях с ними и стоимости tez. На основе этих данных они считают объемы операций в tez и долларах, а также исторические цены токенов в долларах;
  • сайты NFT-маркетплейсов индексируют операции со своими контрактами, чтобы отображать новые NFT, историю операций с ними и статистику самых популярных токенов;
  • блокчейн-обозреватели с помощью индексеров показывают данные со всех блоков и позволяют быстро найти ончейн-данные, например операцию по ее хешу. Благодаря этому пользователи могут найти нужную информацию в удобном графическом интерфейсе. Также обозреватели запускают публичные API, которыми пользуются другие проекты.

Tezos Ukraine спросили MadFish Solutions, Kukai Wallet, Plenty DeFi, youves и разработчиков других популярных проектов Tezos, какими индексерами они пользуются. Результаты интересные: для работы одного приложения требуется от двух до пяти индексеров: публичные индексеры для общих данных, self-hosted-полные для особо важных и селективные индексеры для интерфейса. Мы подробно расскажем про виды индексеров, их преимущества и недостатки в следующем уроке.

Неочевидные задачи, которые решают разработчики индексеров

Во-первых, Tezos эволюционирует. Новая версия протокола может например изменить схему ответа от RPC-ноды, из-за чего индексер будет неправильно индексировать блоки.

Во-вторых, в блокчейнах время от времени случаются реорганизации: два бейкера одновременно добывают два валидных блока, а другие начинают добавлять блоки к обеим цепочкам. Затем сеть отбрасывает одну из цепочек и операции в этих блоках.

При реорганизации блокчейн-обозреватели и индексеры также должны удалить из базы данных и индексов отброшенные блоки. В 2015 году в тестовой сети Bitcoin произошла реорганизация длинной в 100 блоков, которая сломала часть блокчейн-обозревателей.

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

Домашнее задание

Допустим, вы планируете запустить DeFi-дэшборд, который будет отображать полный баланс пользователя. Теперь, когда вы знаете для чего нужны индексеры и что с ними можно делать, подумайте над тем, как бы вы решили задачу. Просто подумайте, а затем посмотрите решение.

Ответы

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

В TzKT это уже реализовано в отдельном API Endpoint:

[https://api.tzkt.io/v1/tokens/balances?account=tz1UEQzJbuaGJgwvkekk6HwGwaKvjZ7rr9v4](https://api.tzkt.io/v1/tokens/balances?account=tz1UEQzJbuaGJgwvkekk6HwGwaKvjZ7rr9v4)

Использовать индексер намного проще, чем получать данные напрямую от RPC-ноды. Для этого сначала нужно получить хеш адреса пользователя с помощью команды:

tezos-client hash data '"{address}"' of type address

9

Затем найти id big_map balances нужного контракта. Например, в контракте стейблкоина Kolibri USD id нужной big_map — 380. Теперь можно сделать запрос:

tezos-client get element exprvEJ9kYbvt2rmka1jac8voDT4xJSAiy48YJdtrXEVxrdZJRpLYr of big map 380

10

В результате получим количество токенов на адресе, но как всегда — без запятых.

Поделиться в соцсетях: