Всем привет, решил перевести свою англоязычную статью, в которой я скомпилировал знания полученные в течение года работы в web3 инфраструктурном провайдере о данных на EVM блокчейнах и инструментах разработчика для доступа к ним.
Сложно сказать, что культура инженерии данных глубоко укоренилась в сообществе разработчиков Web3. И не каждый разработчик может легко определить, что означает индексация в контексте Web3. Я хотел бы уточнить некоторые детали на эту тему и поговорить об инструменте под названием The Graph, который стал де-факто стандартом индустрии для доступа к данным на блокчейне для создателей DApp'ов (децентрализованных приложений).
Начнем с индексации
Индексация в базах данных - это процесс создания структуры данных, которая сортирует и организует данные в базе данных таким образом, чтобы запросы на поиск могли выполняться эффективно. Создав индекс в таблице базы данных, сервер базы данных может быстрее искать и извлекать данные, соответствующие критериям, указанным в запросе. Это помогает улучшить производительность базы данных и сократить время, необходимое для извлечения информации.
Но что насчет индексации в блокчейнах? Самая популярная архитектура блокчейна - это EVM (Ethereum Virtual Machine).
Ethereum Virtual Machine (EVM) - это среда выполнения, которая выполняет смарт-контракты на блокчейне Ethereum. Это компьютерная программа, которая работает на каждом узле сети Ethereum. Она отвечает за выполнение кода смарт-контрактов и также предоставляет функции безопасности, такие как песочница и контроль использования газа. EVM гарантирует, что все участники сети Ethereum могут выполнять смарт-контракты последовательно и безопасно.
Как вы, возможно, знаете, данные на блокчейне хранятся в виде блоков с транзакциями внутри. Также вы, возможно, знаете, что существует два типа учетных записей:
Внешний собственный аккаунт (Externally owned account) - описывается любым обычным адресом кошелька.
Аккаунт контракта (Contract account) - описывается любым адресом развернутого смарт-контракта
Если вы отправляете некоторое количество эфира со своего аккаунта на любой другой аккаунт внешнего владельца - ничего дополнительного за рамками такой транзакции не происходит.
Но вот если вы отправите некоторое количество эфиров на адрес смарт-контракта с любой полезным нагрузкой, вы на самом деле запустите какой-то метод в смарт-контракте, который технически создает так называемые “internal” транзакции.
Но если любая транзакция может быть найдена в блокчейне, почему бы не преобразовать все данные в большую постоянно обновляющуюся базу данных, которую можно будет запрашивать в формате, похожем на SQL?
Проблема в том, что вы можете получить доступ к данным смарт-контракта только если у вас есть "ключ" для расшифровки его. Без этого "ключа" данные смарт-контрактов в блокчейне на самом деле представляют собой байткод. Этот ключ называется ABI (Application Binary Interface).
ABI (Application Binary Interface) - это стандарт, который определяет, как смарт-контракт взаимодействует с внешним миром, включая другие смарт-контракты и пользовательские интерфейсы. Он определяет структуру данных, сигнатуры функций и типы аргументов смарт-контракта для обеспечения правильного и эффективного общения между контрактом и его пользователями.
У любого смарт-контракта в блокчейне есть ABI. Проблема в том, что у вас может не быть ABI для смарт-контракта, который вас интересует. Иногда вы можете найти файл ABI (который на самом деле является JSON-файлом с названиями функций и переменных смарт-контракта, похожим на интерфейс для общения с ним)
на Etherscan (если смарт-контракт был верифицирован, то есть байт код сравнили с тем, что получается из исходников)
на GitHub (если разработчики открыли исходный код проекта)
или если смарт-контракт относится к любому стандартному типу, такому как ERC-20 (взаимозаеменяемые токены как USDT), ERC-721 (невзаимозаменяемые токены или NFT) и т. д.
Конечно, если вы разработчик смарт-контракта, у вас есть ABI, потому что этот файлик генерируется во время компиляции.
Как это выглядит с точки зрения разработчика
Но давайте не будем останавливаться на взгляде на данные через ABI. Что если мы рассмотрим эту тему с точки зрения самого разработчика смарт-контракта? Что такое смарт-контракт? Ответ как бы намного проще, чем вы бы могли подумать. Вот простое объяснение для тех, кто знаком с объектно-ориентированным программированием:
Смарт-контракт в коде разработчика - это класс с некоторыми полями и методами (для смарт-контрактов EVM-совместимых цепочек обычно используется язык программирования Solidity). И задеплоенный смарт-контракт становится как бы уже объектом этого класса. Таким образом, он живет своей жизнью, позволяя пользователям вызывать его методы и изменять его внутренние поля.
Обратите внимание, что любой вызов метода с изменением состояния смарт-контракта означает транзакцию, которая обычно сопровождается событием ("ивентом"), которое разработчик "эмитирует" прямо из кода. Проиллюстрируем вызов функции смарт-контракта ERC-721 (обычный стандарт для коллекций невзаимозаменяемых токенов вроде BoredApeYachtClub), который излучает событие при переходе права собственности на NFT.
/**
* @dev Переводит tokenId от отправителя from к получателю to.
* В отличие от {transferFrom}, это не накладывает ограничений на msg.sender.
*
* Требования:
*
* - to не может быть адресом zero.
* - tokenId token должен принадлежать отправителю from.
*
* Создает событие {Transfer}.
*/
function _transfer(address from, address to, uint256 tokenId) internal virtual {
address owner = ownerOf(tokenId);
if (owner != from) {
revert ERC721IncorrectOwner(from, tokenId, owner);
}
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
_beforeTokenTransfer(from, to, tokenId, 1);
// Проверяем, что tokenId не был передан через хук _beforeTokenTransfer
owner = ownerOf(tokenId);
if (owner != from) {
revert ERC721IncorrectOwner(from, tokenId, owner);
}
// Очищаем одобрения предыдущего владельца
delete _tokenApprovals[tokenId];
// Уменьшаем баланс с проверенной арифметикой, потому что переопределение ownerOf может
// нарушить предположение, что _balances[from] >= 1.
_balances[from] -= 1;
unchecked {
// _balances[to] может переполниться в условиях, описанных в _mint. Для этого потребуется
// сделать минтинг всех 2**256 токенов, что на практике невозможно.
_balances[to] += 1;
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId, 1);
}
Итак, что мы можем здесь заметить. Чтобы передать NFT с вашего адреса на любой другой адрес, вам нужно вызвать функцию _transfer, передав значения этих двух адресов и ID этого NFT. В коде вы можете видеть, что будут выполнены некоторые проверки, а затем изменятся балансы пользователей. Но важно то, что в конце кода функции есть строка:
emit Transfer(from, to, tokenId);
Это означает, что эти три значения будут «транслированы» наружу и могут быть найдены в логах блокчейна. Это гораздо более эффективный способ сохранения необходимых исторических данных, потому что сохранение данных непосредственно в блокчейне слишком дорого.
Теперь мы определили все необходимые понятия для объяснения того, что такое индексация.
Учитывая тот факт, что любой смарт-контракт (будучи объектом некоторого класса) живет своей жизнью, постоянно будучи вызываемым пользователями (и другими смарт-контрактами) и меняя состояние (в то же время транслируя "ивенты"), индексацию можно определить как процесс сбора данных смарт-контракта (любые внутренние переменные внутри контракта и не только те, которые явно передаются) на протяжении его жизненного цикла, сохраняя эти данные вместе с идентификаторами транзакций (хэш) и номерами блоков, чтобы иметь возможность найти любые детали в будущем.
Это очень важно отметить, потому что используя обычный интерфейс блокчейн ноды, просто невозможно получить, например, первую транзакцию кошелька «А» с токеном «B» или самую большую транзакцию в смарт-контракте «C» (или любую другую информацию), если смарт-контракт явно не хранит эти данные (как мы знаем, это очень дорого).
Вот зачем нам нужна индексация. Простые вещи, которые мы можем делать в базе данных SQL, становятся невозможными в блокчейне. Без индексации.
Другими словами, «индексация» здесь - это синоним сбора данных смарт-контракта, потому что отсутствие индексации означает отсутствие доступа к данным в Web3.
Как же разработчики раньше индексировали данные? Они делали это с нуля, для этого:
Они пишут высокопроизводительный код на быстрых языках программирования, таких как Go, Rust и т.д.
Они настраивают базу данных для хранения данных.
Они настраивают API для доступа к данным из приложения.
Они запускают архивную ноду блокчейна.
На первом этапе они сканируют весь блокчейн, находя все транзакции, связанные с определенным смарт-контрактом.
Они обрабатывают эти транзакции, сохраняя новые объекты и обновляя существующие объекты в базе данных.
Когда они достигают текущего блока (chain head), им нужно переключиться на более сложный режим для обработки новых транзакций, потому что каждый новый блок (даже цепочка блоков) может быть отклонен из-за реорганизации цепи (что повлечет некорректность в данных в базе).
Если цепь была реорганизована, им нужно вернуться к блоку, когда сеть реорганизовалась и пересчитать все до нового chain head.
Как вы можете заметить, это не очень просто как разработать, так и поддерживать в реальном времени, потому что каждый сбой на уровне ноды может потребовать еще дополнительных шагов для восстановления актуальности данных. Вот собственно почему появился The Graph. Это простая идея о том, что разработчикам и конечным пользователям нужен доступ к данным смарт-контракта без такиого рода проблем.
Проект The Graph определил парадигму под названием "сабграф" (subgraph), согласно которой для извлечения данных из смарт контракта вам нужно описать 3 вещи:
1. Общие параметры, такие как используемый блокчейн, адрес смарт контракта для индексации, обрабатываемые "ивенты" и начальный блок. Эти переменные определяются в так называемом файле "манифест".
2. Как хранить данные. Какие таблицы следует создать в базе данных для хранения данных смарт контракта? Ответ будет найден в файле "схемы".
3. Как собирать данные. Какие переменные следует сохранять из "ивентов", какие сопутствующие данные (например, хеш транзакции, номер блока, результат вызовов других методов и т. д.) следует также собирать и как они должны быть помещены в определенные схемы. Это описывается в третьем файле.
Эти три вещи можно красиво определить в следующих трех файлах:
subgraph.yaml — файл манифеста
schema.graphql — описание схемы
mapping.ts — файл AssemblyScript
Благодаря этому стандарту крайне легко описать весь процесс индексации, следуя любому из этих обучающих примеров (они пока на английском и я планирую их перевести, если будет заметный интерес к этой статье, так что пожалуйста, поставьте лайк, чтобы я понял, что стоит это продолжать, а если статья уйдет в минусах, я переводить больше не буду????):
Как получить доступ к данным смарт-контракта Tornado Cash с использованием сабграфов The Graph
Как получить доступ к данным смарт контракта в реальном времени из кода на Python
Еще больше мануалов на тему можно найти здесь.
И вот как это выглядит:
Как вы видите здесь, The Graph целиком отвечает за индексирование. Однако вам все еще нужно запускать graph-node (это ПО с открытым исходным кодом от The Graph), а это на деле оказывается задача посложнее, чем просто запускать ноду (которая так и норовит все время выйти из актуального состояния). И здесь происходит очередной сдвиг парадигмы.
Разработчики в прошлом запускали собственные ноды блокчейна, прекратив это делать постепенно и передав эту заботу Web3 инфраструктурным пройдерам. The Graph предложил другое архитектурное упрощение: платформа для хостинга сабграфов The Graph, которая работает для разработчика ("user" здесь) таким образом:
В этом случае пользователь (или разработчик) не должен запускать собственный индексер или граф-ноду, но по-прежнему может контролировать все алгоритмы и даже не попадать в vendor lock, потому что разные провайдеры используют одинаковый формат описания The Graph (Chainstack в частности, полностью совместим с The Graph, но также стоит проверить это утверждение для вашего Web3 провайдера инфраструктуры, если таковой имеется). И это имеет большое значение, потому что это помогает разработчикам ускорить процесс разработки и снизить операционные издержки на обслуживание.
Но то, что также здорово в этой парадигме, что в любое время, когда разработчик захочет сделать свое приложение действительно децентрализованным, он может без проблем перейти на децентрализованную сеть The Graph, используя те же сабграфы.
Что я пропустил в предыдущем повествовании.
Как вы могли заметить, The Graph использует GraphQL вместо REST API. Это позволяет пользователям гибко составлять запросы к любым созданным таблицам, объединяя их и легко фильтруя. Есть хорошее видео о том, как его освоить. Кроме того, ChatGPT может помочь писать запросы GraphQL, как я показал в этом туториале.
У The Graph есть собственный сервис для хостинга сабграфов с большим количеством готовых к использованию сабграфов. Он бесплатен, но, к сожалению, не соответствует требованиям продакшена (надежность, SLA, поддержка), так как фактически является песочницей для децентализованной сети, кроме того, синхронизация происходит медленнее, чем с платными решениями, но все равно может быть использована для разработки. Обучающий материал о том, как использовать готовые к использованию субграфы с Python, можно найти здесь.
Если вы собираетесь использовать субграфы в производстве, я бы порекомендовал обратиться к опытному поставщику инфраструктуры Web3, такому как Chainstack, чтобы достичь эффективности с точки зрения затрат вместе с надежностью и скоростью.
-
Если вы чувствуете себя неуверенно в разработке сабграфов, а все равно хочется их освоить, не стесняйтесь задавать вопросы в этом телеграм-чатике, мне удалось собрать там несколько владеющих экспертизой в этой теме разработчиков и они отвечают на вопросы новичков.
В общем, если вы дочитали до сюда, и вам хотелось бы, чтобы я перевел и другие материалы по доступу к данным на блокчейне или разработке смарт-контрактов, поставьте апвоут и/или напишите в комментариях, про что еще было бы интересно почитать.
Эта статья написана по мотивам советов из чата eth_ru
drch
Спасибо за материал! Хотелось бы увидеть больше материалов на тему сабграфов и работы с ними!
kirill702b Автор
Благодарю! Буду еще писать