Описание подграфа
Подграф определяет, какие данные The Graph будет индексировать из Ethereum и как он будет их хранить.
Материал для перевода взят из статьи.
Три ключевых компонента подграфа для лучшего понимания на высоком уровне:
- Манифест подграфа
- Схема GraphQL
- Написание mappings
Манифест Подграфа
Манифест подграфа subgraph.yaml
определяет смарт-контракты, на которые индексируются ваши подграфы, на какие события из этих контрактов следует обращать внимание и как сопоставлять данные событий с сущностями, которые узел The Graph хранит и позволяет запрашивать. Полную спецификацию для манифестов подграфов можно найти здесь.
Для примера подграф, subgraph.yaml
является:
specVersion: 0.0.1
description: Gravatar for Ethereum
repository: https://github.com/graphprotocol/example-subgraph
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum/contract
name: Gravity
network: mainnet
source:
address: '0x2E645469f354BB4F5c8a05B3b30A929361cf77eC'
abi: Gravity
startBlock: 6175244
mapping:
kind: ethereum/events
apiVersion: 0.0.1
language: wasm/assemblyscript
entities:
- Gravatar
abis:
- name: Gravity
file: ./abis/Gravity.json
eventHandlers:
- event: NewGravatar(uint256,address,string,string)
handler: handleNewGravatar
- event: UpdatedGravatar(uint256,address,string,string)
handler: handleUpdatedGravatar
callHandlers:
- function: createGravatar(string,string)
handler: handleCreateGravatar
blockHandlers:
- function: handleBlock
- function: handleBlockWithCall
filter:
kind: call
file: ./src/mapping.ts
Важными записями манифеста являются:
description
: удобочитаемое описание того, что это за подграф. Описание отображается в Graph Explorer, когда подграф развертывается в размещенной службе.repository
: URL-адрес репозитория, в котором можно найти манифест подграфа. Это также отображается в Graph Explorer.dataSources.source
:address
смарт-контракта, источники подграфа иabi
смарт-контракта для использования.address
не является обязательным; его отсутствие позволяет индексировать совпадающие события из всех контрактов.dataSources.source.startBlock
: необязательный номер блока, с которого источник данных начинает индексацию. В большинстве случаев мы предлагаем использовать блок, в котором был создан контракт.dataSources.mapping.entities
: сущности, которые источник данных записывает в хранилище. Схема для каждой сущности определяется в файлеschema.graphql
.dataSources.mapping.abis
: один или несколько именованных файлов ABI для исходного контракта, а также любых других смарт-контрактов, с которыми вы взаимодействуете из сопоставлений.dataSources.mapping.eventHandlers
: перечисляет события смарт-контрактов, на которые реагирует этот подграф, и обработчики в файле mapping-./src/mapping.ts
в примере, которые преобразуют эти события в entities in the store.dataSources.mapping.callHandlers
: перечисляет функции смарт-контракта, на которые реагирует этот подграф, и обработчики в сопоставлении, которые преобразуют входные и выходные данные в вызовы функций в entities in the store.dataSources.mapping.blockHandlers
: перечисляет блоки, на которые этот подграф реагирует, и обработчики в сопоставлении, которые запускаются при добавлении блока в цепочку. Без фильтра обработчик блока будет запускаться каждый блок. Необязательный фильтр может быть следующих видов:call
. Фильтрcall
запустит обработчик, если блок содержит хотя бы один вызов контракта источника данных.
Один подграф может индексировать данные из нескольких смарт-контрактов. Добавьте запись для каждого контракта, из которого необходимо индексировать данные, в массив dataSources
.
Триггеры для источника данных в блоке упорядочиваются с использованием следующего процесса:
- Триггеры событий и вызовов сначала упорядочиваются по индексу транзакции в блоке.
- Триггеры событий и вызовов, содержащиеся в одной транзакции, упорядочиваются по соглашению: сначала триггеры событий, затем триггеры вызова, причем каждый тип соответствует порядку, который они определены в манифесте.
- Блочные триггеры запускаются после событий и триггеров вызова в том порядке, в котором они определены в манифесте.
Эти правила могут быть изменены.
Получение ABIs
Файл (ы) ABI должен соответствовать вашему контракту (ам). Есть несколько способов получить файлы ABI:
- Если вы создаете свой собственный проект, у вас, вероятно, будет доступ к вашим самым последним ABI.
- Если вы создаете подграф для общедоступного проекта, вы можете загрузить этот проект на свой компьютер и получить ABI с помощью
truffle compile
или использованияsolc
для компиляции. - Вы также можете найти ABI на Etherscan, но это не всегда надежно, поскольку загруженный туда ABI может быть устаревшим. Убедитесь, что у вас правильный ABI, иначе выполнение вашего подграфа не удастся.
Схема GraphQL
Схема для вашего подграфа находится в файле schema.graphql
. Схемы GraphQL определяются с использованием языка определения интерфейса GraphQL. Если вы никогда не писали схему GraphQL, рекомендуется ознакомиться с этим учебником по системе типов GraphQL. Справочную документацию по схемам GraphQL можно найти в разделе GraphQL API.
Определение сущностей
Перед определением сущностей важно сделать шаг назад и подумать о том, как ваши данные структурированы и связаны. Все запросы будут выполняться против модели данных, определенной в схеме подграфа, и сущностей, проиндексированных подграфом. Из-за этого хорошо определить схему подграфа таким образом, чтобы она соответствовала потребностям вашего dApp. Может быть полезно представить сущности как «объекты, содержащие данные», а не как события или функции.
С помощью The Graph вы просто определяете типы сущностей в schema.graphql, а Graph Node будет генерировать поля верхнего уровня для запроса отдельных экземпляров и коллекций этого типа сущности.
Хороший пример
Сущность Gravatar
ниже структурирована вокруг объекта Gravatar и является хорошим примером того, как можно определить сущность.
type Gravatar @entity {
id: ID!
owner: Bytes
displayName: String
imageUrl: String
accepted: Boolean
}
Плохой пример
type GravatarAccepted @entity {
id: ID!
owner: Bytes
displayName: String
imageUrl: String
}
type GravatarDeclined @entity {
id: ID!
owner: Bytes
displayName: String
imageUrl: String
}
Написание Mappings
Mappings преобразуют данные Ethereum, которые ваши mappings получают, в сущности, определенные в вашей схеме. Mappings записываются в подмножестве TypeScript, называемом AssemblyScript, который может быть скомпилирован в WASM (WebAssembly). AssemblyScript строже обычного TypeScript, но обеспечивает знакомый синтаксис.
Для каждого обработчика событий, определенного в subgraph.yaml
в разделе mapping.eventHandlers
, создайте экспортируемую функцию с тем же именем. Каждый обработчик должен принимать один параметр с именем event
с типом, соответствующим имени обрабатываемого события.
В примере подграфа src/mapping.ts
содержит обработчики событий NewGravatar
и UpdatedGravatar
:
import { NewGravatar, UpdatedGravatar } from '../generated/Gravity/Gravity'
import { Gravatar } from '../generated/schema'
export function handleNewGravatar(event: NewGravatar): void {
let gravatar = new Gravatar(event.params.id.toHex())
gravatar.owner = event.params.owner
gravatar.displayName = event.params.displayName
gravatar.imageUrl = event.params.imageUrl
gravatar.save()
}
export function handleUpdatedGravatar(event: UpdatedGravatar): void {
let id = event.params.id.toHex()
let gravatar = Gravatar.load(id)
if (gravatar == null) {
gravatar = new Gravatar(id)
}
gravatar.owner = event.params.owner
gravatar.displayName = event.params.displayName
gravatar.imageUrl = event.params.imageUrl
gravatar.save()
}
Первый обработчик принимает событие NewGravatar
и создает новую сущность Gravatar-new Gravatar(event.params.id.toHex())
, заполняя поля сущности с использованием соответствующих параметров события. Этот экземпляр сущности представлен переменной gravatar
со значением id
event.params.id.toHex()
.
Второй обработчик пытается загрузить существующий Gravatar
из хранилища Graph Node. Если его еще нет, он создается по запросу. Затем объект обновляется в соответствии с новыми параметрами события, прежде чем он будет сохранен обратно в хранилище с помощью gravatar.save()
.
Рекомендуемые идентификаторы для создания новых объектов
У каждой сущности должен быть id
, уникальный среди всех сущностей одного типа. Значение id
объекта устанавливается при создании объекта. Ниже приведены некоторые рекомендуемые значения id
, которые следует учитывать при создании новых сущностей. ПРИМЕЧАНИЕ. Значение id
должно быть string
.
event.params.id.toHex()
event.transaction.from.toHex()
event.transaction.hash.toHex() + "-" + event.logIndex.toString()
Мы предоставляем библиотеку Graph Typescript Library, которая содержит утилиты для взаимодействия с хранилищем Graph Node и удобства для работы с данными и объектами смарт-контрактов. Вы можете использовать эту библиотеку в своих сопоставлениях, импортировав @graphprotocol/graph-ts
в mapping.ts
.
О проекте The Graph
Это протокол индексации для организации и эффективного доступа к данным блокчейнов и сетей хранения. С января 2019 года The Graph использует размещенный сервис с более чем 2300 подграфами, развернутыми для приложений Web3 и DeFi, построенных на Ethereum и IPFS, таких как Synthetix, Uniswap, Aave, Balancer, Gnosis, Aragon и других.
Присоединяйтесь к нашему сообществу, в нашем канале Discord , присоединяйтесь к нашему чату Telegram или подписывайтесь на нас в Twitter! В экосистеме The Graph растет сообщество разработчиков, работающих над построением децентрализованного будущего. Наши разработчики всегда готовы пообщаться с вами.
Testnet website: https://thegraph.com/testnet
Blog: https://thegraph.com/blog/
Linkedin: https://www.linkedin.com/company/thegraph/
Everest: https://everest.link