Обзор
Блокчейн Solana хранит данные в последовательном реестре, допускающем только добавление записей. Это обеспечивает целостность данных и высокую пропускную способность транзакций, но имеет существенный недостаток: запросы к историческим данным становятся крайне неэффективными и недопустимо медленными. Сложные операции часто требуют фильтрации, агрегирования или объединения данных из нескольких источников. В таких случаях прямые запросы к Solana непрактичны для большинства реальных приложений. Чтобы решить эту проблему, большинство компаний создают частные индексы исторических данных Solana. Это руководство охватывает весь жизненный цикл: ретроспективную загрузку исторических данных с помощьюgetTransactionsForAddress и других архивных методов RPC, выбор базы данных и поддержание актуальности индекса с помощью потоковой передачи в реальном времени.
Когда это использовать
Создайте индекс, если:- Вашему продукту нужны быстрые запросы с фильтрацией, для которых прямые вызовы RPC слишком медленны (например, получение счетов токенов и балансов кошелька или полной истории торговой пары)
- Вам нужно фильтровать, агрегировать или объединять данные из блокчейна либо сочетать их с данными вне блокчейна (цены CEX, KYC, метки)
- Вы вычисляете такие показатели, как PnL, аналитика держателей или история продаж NFT, для которых нужны предварительно обработанные данные с возможностью выполнения запросов
- Вы обслуживаете множество пользователей и не можете допустить задержку при обращении к блокчейну для каждого запроса
Что означает индексирование данных Solana?
Индексирование — это процесс запроса данных из блокчейна Solana и их сохранения в серверной базе данных (например, PostgreSQL или ClickHouse), которую затем можно использовать для быстрого обслуживания запросов клиентов без прямого обращения к блокчейну через вызовы Solana RPC. Обычно индексатор выполняет четыре задачи:- Ретроспективно загружает исторические данные: использует архивные методы RPC, чтобы запросить все исторические данные
- Передает новые данные в потоке: обрабатывает новые блоки после их подтверждения сетью
- Анализирует и преобразует данные: извлекает нужные данные из подтвержденных блоков (например, транзакции, изменения состояния и т. д.)
- Организует данные в базе данных: обновляет индекс новыми данными
Почему большинство компаний создают индексы Solana?
Компании создают индексы Solana, поскольку их бизнес зависит от быстрого доступа в реальном времени к специализированным данным блокчейна, которые недоступны через встроенные RPC (например, к истории продаж NFT). Компании также используют собственные индексы, чтобы объединять данные вне блокчейна (например, цены централизованных бирж, сведения KYC и т. д.) со своими данными в блокчейне.Пример с кошельком
Например, если кошельку Solana нужно быстро получить счета токенов и балансы пользователя, прямой запрос к Solana с помощьюgetTokenAccountsByOwner и getTokenAccountBalance будет слишком медленным и может сделать продукт непригодным для использования. Поэтому кошельки обычно поддерживают собственные индексы адресов клиентов, токенов и балансов счетов.
Пример с торговлей
Аналогично, компания, занимающаяся торговлей криптовалютами, может захотеть регистрировать всю торговую активность по определенной торговой паре (например, SOL-USDC) или на определенном рынке, чтобы проводить ретроспективное тестирование своих торговых алгоритмов. Прямой запрос этих данных из блокчейна был бы слишком медленным для практического анализа торговли. Вместо этого количественные трейдеры могут создать индексы для рынка SOL-USDC и обновлять их последними сделками с помощью таких продуктов потоковой передачи в реальном времени, как LaserStream.Пример с фильтрацией
Представьте, что пользователь хочет отфильтровать транзакции по определенным критериям в клиентском приложении (например, по типу токена, сумме перевода, дате или адресу кошелька). Без индексатора вашему приложению пришлось бы просматривать миллионы транзакций в сотнях тысяч блоков, проверяя каждую из них на соответствие критериям фильтрации. Этот процесс слишком медленный для современных пользовательских интерфейсов.Пример с PnL
Чтобы рассчитать прибыль и убыток трейдера (PnL), потребуется:- Найти каждую транзакцию, связанную с его кошельком за заданный период
- Отфильтровать транзакции обмена и пометить их как покупки или продажи
- Определить размер комиссий, уплаченных пользователем при каждом обмене
- Получить исторические данные о цене каждого токена на момент каждой сделки
- Агрегировать PnL каждой транзакции, чтобы рассчитать общий PnL трейдера
Шаг 1. Получите исторические данные
Первый шаг при создании индекса Solana — получить все необходимые вам исторические данные. Существует три основных способа сделать это:- getTransactionsForAddress (рекомендуется)
- getSignaturesForAddress и getTransaction
- getBlock
Метод 1. getTransactionsForAddress (рекомендуется)
Метод RPCgetTransactionsForAddress позволяет получить полные сведения о транзакциях для произвольного сегмента данных блокчейна. Благодаря мощным возможностям фильтрации вы не будете тратить время на получение данных, которые не нужны вашему индексу, а функция обратного поиска позволяет получать транзакции в хронологическом порядке.
Как использовать этот метод
- Определите период, за который вам нужны данные, и соответствующим образом настройте фильтр
- Установите для
transactionDetailsзначениеfull, чтобы получать все сведения о транзакциях - При необходимости настройте фильтр
tokenAccounts, чтобы включить транзакции связанных счетов токенов - Последовательно получайте страницы результатов с помощью
paginationToken - На каждой итерации извлекайте необходимые данные и сохраняйте их в своей базе данных
Преимущества getTransactionsForAddress
Основные преимущества конечной точки gTFA — скорость и простота. Благодаря фильтрам по слотам и времени, поддержке счетов токенов, обратному поиску и пагинации вы можете получить любые нужные данные за любой период в истории Solana одним вызовом, без сложных циклов или логики повторных попыток. В отличие отgetSignaturesForAddress, этот метод также может включать транзакции со связанными счетами токенов, принадлежащими указанному адресу.
Если ваш индекс предназначен именно для отслеживания перемещений токенов и нативного SOL (платежи, реестры, сверка балансов), метод getTransfersByAddress возвращает проанализированные строки переводов, готовые к сверке, вместо полных транзакций. Это позволяет исключить этап анализа.
Метод 2. getSignaturesForAddress и getTransaction
До выпуска gTFA стандартный подход к запросу исторических данных заключался в рекурсивном переборе подписей с помощьюgetSignaturesForAddress (от новых к старым) и последующем вызове getTransaction для извлечения полных сведений о транзакциях.
Как использовать этот метод
Основные шаги для использования этого метода:- Вызовите
getSignaturesForAddress - Сохраните подпись последней транзакции, полученной при этом вызове
- Для следующего вызова
getSignaturesForAddressустановите параметрbeforeравным этой подписи - Повторяйте эти действия в цикле столько, сколько потребуется
- Для каждой полученной таким образом подписи транзакции вызовите
getTransaction, чтобы получить полные сведения о транзакции - Добавьте нужные данные в свою базу данных
Недостатки этого метода
К сожалению, при использовании этого метода необходимо:- Начать с самой новой транзакции и двигаться назад
- Выполнить один дополнительный вызов RPC для каждой транзакции
- Создать потокобезопасную очередь для параллельной обработки
- Реализовать логику повторных попыток и увеличения интервалов между ними, чтобы избежать пропуска данных и ограничения частоты запросов
- Метод не включает транзакции со связанными счетами токенов, принадлежащими указанному адресу
getTransactionsForAddress.
Метод 3. Используйте getBlock
МетодgetBlock наиболее эффективен, когда для анализа важна большая доля транзакций в целевых блоках. Например, при индексировании транзакций часто используемых программ Solana, таких как Aggregator от DFlow, программа Pump.fun или программа Token от Solana.
Как использовать этот метод
Основной процесс запроса исторических данных с помощьюgetBlock включает следующие действия:
- Выберите временной диапазон для запроса
- Преобразуйте этот временной диапазон в номера слотов
- Последовательно получите соответствующие блоки (в прямом или обратном порядке)
- В каждом блоке отфильтруйте транзакции, относящиеся к вашему индексу
- Сохраните нужную информацию из них в своем индексе
Шаг 2. Синхронизируйте данные Solana с базой данных
После получения исторических данных необходимо преобразовать их и эффективно сохранить в базе данных. Выбор хранилища должен соответствовать вашему конкретному сценарию использования — универсального решения не существует. Подходящая база данных зависит от размера набора данных, требований к задержке, шаблонов запросов и опыта команды.Вариант 1. Базы данных SQL
Для большинства сценариев рекомендуется хранить данные Solana в реляционных базах данных, таких как PostgreSQL. SQL отличается гибкостью, широко распространен и прост в освоении. Современные реляционные базы данных могут масштабироваться до более чем 100 млн строк, сохраняя при этом преимущества соответствия ACID, сложных объединений и мощных вторичных индексов. Используйте SQLite для создания прототипов, локальной разработки или в случаях, когда вам нужна база данных в одном файле без настройки. Она идеально подходит, если объем вашего набора данных не превышает нескольких гигабайт. Используйте PostgreSQL для производственных приложений, которым требуются репликация данных, одновременный доступ нескольких клиентов или расширенные возможности, такие как полнотекстовый поиск и операторы JSON. Для большинства производственных индексаторов Solana мы рекомендуем PostgreSQL.Пример реализации:
В качестве примера покажем, как хранить переводы токенов в базе данных PostgreSQL. Сначала создайте таблицу:Вариант 2. Колоночные базы данных
Колоночные базы данных оптимизированы для аналитических запросов, агрегирования и больших объемов данных временных рядов. Если вам нужно проиндексировать несколько миллиардов транзакций, лучше всего подойдут колоночные базы данных, такие как ClickHouse или Cassandra. Используйте ClickHouse, если вам нужны аналитические запросы к большим наборам данных в реальном времени: эта база оптимизирована для быстрого чтения, агрегирования и анализа временных рядов. Используйте Cassandra, если вам нужны чрезвычайно высокая пропускная способность записи, простое горизонтальное масштабирование и высокая отказоустойчивость. Благодаря этому она идеально подходит для непрерывного приема огромных объемов данных Solana.Пример реализации:
Покажем, как хранить переводы токенов в базе данных ClickHouse. Для этого создайте таблицу, использующую табличный движок MergeTree. Он рассчитан на высокую скорость приема данных, поэтому идеально подходит для индексирования. Используйте эту команду:(token_mint, date) используется одновременно как первичный ключ и ключ сортировки. ClickHouse упорядочивает данные на диске в соответствии с ключом сортировки. Это оптимально для запросов по одному выпуску токена и сужения ответа по диапазонам дат.
Пример запроса:
FixedString(N), который содержит ровно N байт. ClickHouse автоматически сжимает данные, что сокращает затраты на хранение в 10–20 раз и повышает производительность запросов.
Чтобы оптимизировать производительность запросов, используйте материализованные представления для предварительного вычисления распространенных агрегатов.
Например, можно заранее вычислять суточный объем переводов токенов для диаграмм объема на панели мониторинга.
Вариант 3. Озера данных
Озера данных идеально подходят для хранения огромных объемов необработанных и обработанных данных блокчейна с целью долгосрочного архивирования и выполнения аналитических запросов. В простой реализации используется формат данных Parquet вместе с Amazon Athena. Parquet — это колоночный формат файлов данных, предназначенный для эффективного хранения и извлечения данных. Amazon Athena — это интерактивный сервис запросов, который позволяет анализировать данные, хранящиеся в Amazon S3, с помощью стандартного SQL без необходимости настраивать инфраструктуру или загружать данные в отдельную базу данных.Пример реализации:
Мы хотим создать архив переводов токенов и выполнять к нему запросы. Сначала необходимо сохранить их в S3: создайте корзину с именемsolana_index и разделите данные переводов токенов по времени с помощью следующей структуры ключей:
Используйте фреймворки индексирования
Используйте Carbon и аналогичные фреймворки, чтобы не писать шаблонный код и настроить индексатор за несколько часов, а не дней.Основные возможности:
- Готовые декодеры для популярных программ (программа Token, протоколы DeFi, Metaplex)
- Настраиваемые источники данных (RPC, LaserStream, расширенные WebSocket)
- Встроенная поддержка ретроспективной загрузки и потоковой передачи в реальном времени
- Вывод в разные серверные хранилища (поддержка Postgres доступна изначально)
- Полная настройка: можно задавать собственные источники данных, декодеры и приемники данных
Шаг 3. Поддерживайте актуальность индекса
После ретроспективной загрузки исторических данных вам понадобится решение для потоковой передачи в реальном времени, чтобы обновлять индекс с учетом новой активности в блокчейне. Без этого индекс устареет.Метод 1. LaserStream (рекомендуется)
Мы рекомендуем использовать LaserStream gRPC как основной вариант для всех производственных сценариев индексирования. Он специально разработан для надежной и отказоустойчивой потоковой передачи данных со сверхнизкой задержкой. Некоторые преимущества LaserStream:- Воспроизведение истории за 24 часа: если индексатор отключится, LaserStream автоматически воспроизведет все пропущенные транзакции с того места, на котором вы остановились
- Автоматическое переподключение: наши SDK LaserStream (Rust, Go, JS/TS) автоматически обрабатывают прерывания сети
- Переключение между узлами при сбое: подключение LaserStream одновременно агрегирует данные из нескольких узлов, обеспечивая максимальную доступность
Как использовать LaserStream для индексирования
Используйте методsubscribe, чтобы подписаться на события блокчейна.
Рекомендуется придерживаться следующих практик:
- Максимально сузьте фильтр: подписывайтесь только на данные, которые действительно нужно индексировать, чтобы минимизировать потребление пропускной способности и объем необходимой обработки.
- Используйте уровень подтверждения
confirmed: он обеспечивает баланс между задержкой и окончательностью. Уровеньprocessedможет быть недостаточно надежным, аfinalizedдобавляет задержку около ~13 секунд - Установите
failed: false, если вам не требуется специально отслеживать неуспешные транзакции - Исключите транзакции голосования (
vote: false), поскольку они не нужны для индексирования
Метод 2. Используйте LaserStream WebSocket
LaserStream WebSocket — вариант LaserStream на основе WebSocket, включающий специальное для Helius расширениеtransactionSubscribe. Он работает на той же серверной инфраструктуре, что и LaserStream gRPC, и представляет собой экономичную альтернативу для потоковой передачи в реальном времени, когда gRPC не требуется.
Используйте LaserStream WebSocket, если:
- Ваше приложение допускает периодические пропуски данных
- Обновления в реальном времени важны, но не являются критически необходимыми
- У вас есть инфраструктура для обнаружения и ретроспективной загрузки отсутствующих данных
- Бюджет значительно ограничен и вам необходимо свести к минимуму расходы на потоковую передачу
- Вы создаете прототип или проводите тестирование перед переходом на LaserStream
- Скорость: LaserStream WebSocket работает на той же серверной инфраструктуре, что и LaserStream gRPC, но протокол WebSocket добавляет обрамление JSON и накладные расходы для каждого сообщения. Чтобы получить минимально возможную задержку для тех же данных, используйте LaserStream gRPC
- Надежность: воспроизведение истории не гарантируется. Если соединение WebSocket прервется, вам потребуется вручную обнаружить и заполнить пропуски с помощью методов RPC
- Сложность: требуется дополнительная инфраструктура мониторинга для обеспечения полноты данных
Как использовать WebSocket для индексирования
Чтобы обновлять индекс, в котором хранятся все переводы токенов, подпишитесь наtransactionSubscribe следующим образом:
Начало работы
Для создания надежного индекса Solana и ретроспективной загрузки данных необходимо решить три основные задачи:- Эффективно получать исторические данные
- Преобразовывать и хранить данные для быстрого извлечения
- Обновлять индексированные данные Solana в реальном времени
getTransactionsForAddress, и ведущим отраслевым решениям для потоковой передачи данных, таким как LaserStream, создавать индексы Solana стало проще и практичнее, чем когда-либо.
Дополнительные варианты
Собственный индекс дает полный контроль, но нужен не всегда. Для распространенных задач управляемый API Helius может заменить или дополнить собственный индекс:- DAS API — выполняйте запросы к NFT, взаимозаменяемым токенам и сжатым активам (метаданные, владение, балансы, фильтрация по владельцу, коллекции или создателю), не индексируя данные активов самостоятельно.
- Wallet API — высокоуровневые конечные точки REST для получения балансов, истории, переводов и идентификационных данных кошелька со значениями в долларах США и более простой структурой ответа.
Дальнейшие действия
- Зарегистрируйте бесплатную учетную запись Helius, чтобы получить доступ к API
- Ознакомьтесь с руководством по getTransactionsForAddress для ретроспективной загрузки данных
- Изучите обзор LaserStream для потоковой передачи в реальном времени
- Ознакомьтесь с обзором исторических данных, чтобы узнать обо всех архивных методах