15 dakika
Advanced Subgraph Features
Genel Bakış
Add and implement advanced Subgraph features to enhanced your Subgraph’s built.
Starting from specVersion
0.0.4
, Subgraph features must be explicitly declared in the features
section at the top level of the manifest file, using their camelCase
name, as listed in the table below:
Feature | Name |
---|---|
Non-fatal errors | nonFatalErrors |
Full-text Search | fullTextSearch |
Aşılama | grafting |
For instance, if a Subgraph uses the Full-Text Search and the Non-fatal Errors features, the features
field in the manifest should be:
1specVersion: 1.3.02description: Gravatar for Ethereum3features:4 - fullTextSearch5 - nonFatalErrors6dataSources: ...
Note that using a feature without declaring it will incur a validation error during Subgraph deployment, but no errors will occur if a feature is declared but not used.
Zaman Serileri ve Toplulaştırmalar
Prerequisites:
- Subgraph specVersion must be ≥1.1.0.
Timeseries and aggregations enable your Subgraph to track statistics like daily average price, hourly total transfers, and more.
This feature introduces two new types of Subgraph entity. Timeseries entities record data points with timestamps. Aggregation entities perform pre-declared calculations on the timeseries data points on an hourly or daily basis, then store the results for easy access via GraphQL.
Örnek Şema
1type Data @entity(timeseries: true) {2 id: Int8!3 timestamp: Timestamp!4 price: BigDecimal!5}67type Stats @aggregation(intervals: ["hour", "day"], source: "Data") {8 id: Int8!9 timestamp: Timestamp!10 sum: BigDecimal! @aggregate(fn: "sum", arg: "price")11}
How to Define Timeseries and Aggregations
Timeseries entities are defined with @entity(timeseries: true)
in the GraphQL schema. Every timeseries entity must:
- have a unique ID of the int8 type
- have a timestamp of the Timestamp type
- include data that will be used for calculation by aggregation entities.
These Timeseries entities can be saved in regular trigger handlers, and act as the “raw data” for the aggregation entities.
Aggregation entities are defined with @aggregation
in the GraphQL schema. Every aggregation entity defines the source from which it will gather data (which must be a timeseries entity), sets the intervals (e.g., hour, day), and specifies the aggregation function it will use (e.g., sum, count, min, max, first, last).
Aggregation entities are automatically calculated on the basis of the specified source at the end of the required interval.
Mevcut Toplulaştırma Aralıkları
hour
: sets the timeseries period every hour, on the hour.day
: sets the timeseries period every day, starting and ending at 00:00.
Mevcut Toplulaştırma Fonksiyonları
sum
: Total of all values.count
: Number of values.min
: Minimum value.max
: Maximum value.first
: First value in the period.last
: Last value in the period.
Örnek Toplulaştırmalar Sorgusu
1{2 stats(interval: "hour", where: { timestamp_gt: 1704085200 }) {3 id4 timestamp5 sum6 }7}
Read more about Timeseries and Aggregations.
Ölümcül Olmayan Hatalar
Indexing errors on already synced Subgraphs will, by default, cause the Subgraph to fail and stop syncing. Subgraphs can alternatively be configured to continue syncing in the presence of errors, by ignoring the changes made by the handler which provoked the error. This gives Subgraph authors time to correct their Subgraphs while queries continue to be served against the latest block, though the results might be inconsistent due to the bug that caused the error. Note that some errors are still always fatal. To be non-fatal, the error must be known to be deterministic.
Note: The Graph Network does not yet support non-fatal errors, and developers should not deploy Subgraphs using that functionality to the network via the Studio.
Enabling non-fatal errors requires setting the following feature flag on the Subgraph manifest:
1specVersion: 1.3.02description: Gravatar for Ethereum3features:4 - nonFatalErrors5 ...
The query must also opt-in to querying data with potential inconsistencies through the subgraphError
argument. It is also recommended to query _meta
to check if the Subgraph has skipped over errors, as in the example:
1foos(first: 100, subgraphError: allow) {2 id3}45_meta {6 hasIndexingErrors7}
If the Subgraph encounters an error, that query will return both the data and a graphql error with the message "indexing_error"
, as in this example response:
1"data": {2 "foos": [3 {4 "id": "0xdead"5 }6 ],7 "_meta": {8 "hasIndexingErrors": true9 }10},11"errors": [12 {13 "message": "indexing_error"14 }15]
IPFS/Arweave Dosya Veri Kaynakları
File data sources are a new Subgraph functionality for accessing off-chain data during indexing in a robust, extendable way. File data sources support fetching files from IPFS and from Arweave.
Bu aynı zamanda zincir dışı verilerinin belirlenebilir indekslenmesi için zemin hazırlar ve keyfi HTTP kaynaklı verilerin tanıtılma potansiyelini de beraberinde getirir.
Genel Bakış
İşleyici yürütülürken dosyaları “sıra sıra” almak yerine, Dosya Veri Kaynakları, belirli bir dosya kimliği için yeni veri kaynakları olarak kullanılabilecek şablonlar sunar. Bu yeni veri kaynakları dosyaları getirir. Başarısız olurlarsa yeniden denerler ve dosya bulunduğunda bu işe mahsus bir işleyici çalıştırırlar.
This is similar to the existing data source templates, which are used to dynamically create new chain-based data sources.
This replaces the existing ipfs.cat
API
Yükseltme rehberi
Update graph-ts
and graph-cli
File data sources requires graph-ts >=0.29.0 and graph-cli >=0.33.1
Dosyalar bulunduğunda güncellenecek yeni bir varlık türü ekleyin
Dosya veri kaynakları zincir tabanlı varlıklara erişemez veya bunları güncelleyemez, ancak dosya belirli varlıkları güncellemelidir.
Bu, mevcut varlıklardaki alanları ayrı varlıklara bölmeyi gerektirebilir ve bunlar birbirine bağlanabilir.
Özgün birleştirilmiş varlık:
1type Token @entity {2 id: ID!3 tokenID: BigInt!4 tokenURI: String!5 externalURL: String!6 ipfsURI: String!7 image: String!8 name: String!9 description: String!10 type: String!11 updatedAtTimestamp: BigInt12 owner: User!13}
Yeni, ayrılmış varlık:
1type Token @entity {2 id: ID!3 tokenID: BigInt!4 tokenURI: String!5 ipfsURI: TokenMetadata6 updatedAtTimestamp: BigInt7 owner: String!8}910type TokenMetadata @entity {11 id: ID!12 image: String!13 externalURL: String!14 name: String!15 description: String!16}
Ana varlık ve sonuç dosya veri kaynak varlığı arasındaki ilişki bire bir ise, en basit kalıp, IPFS CID’yi arama anahtarı olarak kullanarak ana varlığını sonuç dosya varlığına bağlamaktır. Yeni dosya tabanlı varlıklarınızın modellemesiyle ilgili sorun yaşarsanız Discord üzerinden iletişime geçin!
You can use nested filters to filter parent entities on the basis of these nested entities.
Add a new templated data source with kind: file/ipfs
or kind: file/arweave
Bu, ilgi alanı dosyası tespit edildiğinde oluşturulacak veri kaynağıdır.
1templates:2 - name: TokenMetadata3 kind: file/ipfs4 mapping:5 apiVersion: 0.0.96 language: wasm/assemblyscript7 file: ./src/mapping.ts8 handler: handleMetadata9 entities:10 - TokenMetadata11 abis:12 - name: Token13 file: ./abis/Token.json
Currently abis
are required, though it is not possible to call contracts from within file data sources
The file data source must specifically mention all the entity types which it will interact with under entities
. See limitations for more details.
Dosyaları işlemek için yeni bir işleyici oluşturun
This handler should accept one Bytes
parameter, which will be the contents of the file, when it is found, which can then be processed. This will often be a JSON file, which can be processed with graph-ts
helpers (documentation).
The CID of the file as a readable string can be accessed via the dataSource
as follows:
1const cid = dataSource.stringParam()
Örnek işleyici:
1import { json, Bytes, dataSource } from '@graphprotocol/graph-ts'2import { TokenMetadata } from '../generated/schema'34export function handleMetadata(content: Bytes): void {5 let tokenMetadata = new TokenMetadata(dataSource.stringParam())6 const value = json.fromBytes(content).toObject()7 if (value) {8 const image = value.get('image')9 const name = value.get('name')10 const description = value.get('description')11 const externalURL = value.get('external_url')1213 if (name && image && description && externalURL) {14 tokenMetadata.name = name.toString()15 tokenMetadata.image = image.toString()16 tokenMetadata.externalURL = externalURL.toString()17 tokenMetadata.description = description.toString()18 }1920 tokenMetadata.save()21 }22}
Gerektiğinde dosya veri kaynakları oluşturun
Artık zincir tabanlı işleyicilerin yürütülmesi sırasında dosya veri kaynakları oluşturabilirsiniz:
- Import the template from the auto-generated
templates
- call
TemplateName.create(cid: string)
from within a mapping, where the cid is a valid content identifier for IPFS or Arweave
For IPFS, Graph Node supports v0 and v1 content identifiers, and content identifiers with directories (e.g. bafyreighykzv2we26wfrbzkcdw37sbrby4upq7ae3aqobbq7i4er3tnxci/metadata.json
).
For Arweave, as of version 0.33.0 Graph Node can fetch files stored on Arweave based on their transaction ID from an Arweave gateway (example file). Arweave supports transactions uploaded via Irys (previously Bundlr), and Graph Node can also fetch files based on Irys manifests.
Örnek:
1import { TokenMetadata as TokenMetadataTemplate } from '../generated/templates'23const ipfshash = 'QmaXzZhcYnsisuue5WRdQDH6FDvqkLQX1NckLqBYeYYEfm'4//This example code is for a Crypto coven Subgraph. The above ipfs hash is a directory with token metadata for all crypto coven NFTs.56export function handleTransfer(event: TransferEvent): void {7 let token = Token.load(event.params.tokenId.toString())8 if (!token) {9 token = new Token(event.params.tokenId.toString())10 token.tokenID = event.params.tokenId1112 token.tokenURI = '/' + event.params.tokenId.toString() + '.json'13 const tokenIpfsHash = ipfshash + token.tokenURI14 //This creates a path to the metadata for a single Crypto coven NFT. It concats the directory with "/" + filename + ".json"1516 token.ipfsURI = tokenIpfsHash1718 TokenMetadataTemplate.create(tokenIpfsHash)19 }2021 token.updatedAtTimestamp = event.block.timestamp22 token.owner = event.params.to.toHexString()23 token.save()24}
Bu, Graph Düğümü’nün yapılandırılmış IPFS veya Arweave uç noktasını sorgulayacak yeni bir veri kaynağı dosyası oluşturacak ve bulunamazsa yeniden deneyecek. Dosya bulunduğunda, dosya veri kaynağı işleyicisi çalıştırılacaktır.
This example is using the CID as the lookup between the parent Token
entity and the resulting TokenMetadata
entity.
Previously, this is the point at which a Subgraph developer would have called ipfs.cat(CID)
to fetch the file
Tebrikler, dosya veri kaynaklarını kullanıyorsunuz!
Deploying your Subgraphs
You can now build
and deploy
your Subgraph to any Graph Node >=v0.30.0-rc.0.
Sınırlamalar
File data source handlers and entities are isolated from other Subgraph entities, ensuring that they are deterministic when executed, and ensuring no contamination of chain-based data sources. To be specific:
- Dosya Veri Kaynakları tarafından oluşturulan varlıklar değiştirilemez ve güncellenemez
- Dosya Veri Kaynağı işleyicileri, diğer dosya veri kaynaklarından varlıklara erişemez
- Dosya Veri Kaynaklarıyla ilişkili varlıklara zincir tabanlı işleyicilerden erişilemez
While this constraint should not be problematic for most use-cases, it may introduce complexity for some. Please get in touch via Discord if you are having issues modelling your file-based data in a Subgraph!
Ek olarak, zincir üstü bir veri kaynağı veya başka bir dosya veri kaynağı olsun, bir dosya veri kaynağından veri kaynakları oluşturmak mümkün değildir. Bu kısıtlama gelecekte kaldırılabilir.
En iyi uygulamalar
NFT meta verilerini ilgili tokenleri bağlarken, Üst veri varlığına Token varlığından başvurmak için üst verinin IPFS hash değerini kullanın. Üst veri varlığını IPFS hash değerini bir kimlik olarak kullanarak kaydedin.
You can use DataSource context when creating File Data Sources to pass extra information which will be available to the File Data Source handler.
If you have entities which are refreshed multiple times, create unique file-based entities using the IPFS hash & the entity ID, and reference them using a derived field in the chain-based entity.
Yukarıdaki öneriyi geliştirmeye çalışıyoruz, bu nedenle sorgular yalnızca “en son” sürümü döndürür
Bilinen Sorunlar
File data sources currently require ABIs, even though ABIs are not used (issue). Workaround is to add any ABI.
Handlers for File Data Sources cannot be in files which import eth_call
contract bindings, failing with “unknown import: ethereum::ethereum.call
has not been defined” (issue). Workaround is to create file data source handlers in a dedicated file.
Örnekler
Crypto Coven Subgraph migration
Referanslar
Endekslenmiş Argüman Filtreleri / Konu Filtreleri
Requires: SpecVersion >= 1.2.0
Topic filters, also known as indexed argument filters, are a powerful feature in Subgraphs that allow users to precisely filter blockchain events based on the values of their indexed arguments.
-
These filters help isolate specific events of interest from the vast stream of events on the blockchain, allowing Subgraphs to operate more efficiently by focusing only on relevant data.
-
This is useful for creating personal Subgraphs that track specific addresses and their interactions with various smart contracts on the blockchain.
Konu Filtreleri Nasıl Çalışır
When a smart contract emits an event, any arguments that are marked as indexed can be used as filters in a Subgraph’s manifest. This allows the Subgraph to listen selectively for events that match these indexed arguments.
- The event’s first indexed argument corresponds to
topic1
, the second totopic2
, and so on, up totopic3
, since the Ethereum Virtual Machine (EVM) allows up to three indexed arguments per event.
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.0;34contract Token {5 // Adresler için endekslenmiş parametreleriyle birlikte olay bildirimi6 event Transfer(address indexed from, address indexed to, uint256 value);78 // Token transferini simüle eden fonksiyon9 function transfer(address to, uint256 value) public {10 // Transfer olayını from, to ve value ile yayma11 emit Transfer(msg.sender, to, value);12 }13}
Bu örnekte:
- The
Transfer
event is used to log transactions of tokens between addresses. - The
from
andto
parameters are indexed, allowing event listeners to filter and monitor transfers involving specific addresses. - The
transfer
function is a simple representation of a token transfer action, emitting the Transfer event whenever it is called.
Subgraph’lerde Yapılandırma
Topic filters are defined directly within the event handler configuration in the Subgraph manifest. Here is how they are configured:
1eventHandlers:2 - event: SomeEvent(indexed uint256, indexed address, indexed uint256)3 handler: handleSomeEvent4 topic1: ['0xValue1', '0xValue2']5 topic2: ['0xAddress1', '0xAddress2']6 topic3: ['0xValue3']
Bu bağlamda:
topic1
corresponds to the first indexed argument of the event,topic2
to the second, andtopic3
to the third.- Her konu (topic) bir veya daha fazla değere sahip olabilir ve bir olay yalnızca karşılık geldiği konudaki değerlerden biriyle eşleşiyorsa işlenir.
Filtre Mantığı
- Tek Bir Konu İçinde: VEYA koşulu olarak çalışır. Olay, verilen konunun listesindeki herhangi bir değerle eşleşirse işlenecektir.
- Farklı Konular Arasında: VE koşulu olarak çalışır. Bir olayın ilgili işleyiciyi tetiklemesi için farklı konular arasındaki belirlenmiş tüm koşulları karşılaması gerekir.
Örnek 1: Adres A’dan Adres B’ye Doğrudan Transferleri Takip Etme
1eventHandlers:2 - event: Transfer(indexed address,indexed address,uint256)3 handler: handleDirectedTransfer4 topic1: ['0xAddressA'] # Sender Address5 topic2: ['0xAddressB'] # Receiver Address
Bu konfigürasyonda:
topic1
is configured to filterTransfer
events where0xAddressA
is the sender.topic2
is configured to filterTransfer
events where0xAddressB
is the receiver.- The Subgraph will only index transactions that occur directly from
0xAddressA
to0xAddressB
.
Örnek 2: İki veya Daha Fazla Adres Arasında Her İki Yönde Gerçekleşen İşlemleri Takip Etme
1eventHandlers:2 - event: Transfer(indexed address,indexed address,uint256)3 handler: handleTransferToOrFrom4 topic1: ['0xAddressA', '0xAddressB', '0xAddressC'] # Sender Address5 topic2: ['0xAddressB', '0xAddressC'] # Receiver Address
Bu konfigürasyonda:
topic1
is configured to filterTransfer
events where0xAddressA
,0xAddressB
,0xAddressC
is the sender.topic2
is configured to filterTransfer
events where0xAddressB
and0xAddressC
is the receiver.- The Subgraph will index transactions that occur in either direction between multiple addresses allowing for comprehensive monitoring of interactions involving all addresses.
Deklare edilmiş eth_call
Not: Bu, henüz stabil bir Graph Düğümü sürümünde mevcut olmayan deneysel bir özelliktir. Yalnızca Subgraph Studio’da veya sağlayıcılığını kendiniz yaptığınız düğümünüzde kullanabilirsiniz.
Declarative eth_calls
are a valuable Subgraph feature that allows eth_calls
to be executed ahead of time, enabling graph-node
to execute them in parallel.
Bu özellik:
- Significantly improves the performance of fetching data from the Ethereum blockchain by reducing the total time for multiple calls and optimizing the Subgraph’s overall efficiency.
- Daha hızlı veri çekmeye olanak tanıyarak, daha hızlı sorgu yanıtları alınmasını ve daha iyi bir kullanıcı deneyimi sağlar.
- Birden fazla Ethereum çağrısından veri toplaması gereken uygulamalar için bekleme sürelerini azaltarak veri çekme sürecini daha verimli hale getirir.
Ana Kavramlar
- Declarative
eth_calls
: Ethereum calls that are defined to be executed in parallel rather than sequentially. - Paralel Yürütme: Bir çağrıyı başlatmak için diğerinin bitmesini beklemek yerine, birden fazla çağrı aynı anda başlatılabilir.
- Zaman Verimliliği: Tüm çağrılar için geçen toplam süre, bireysel çağrı sürelerinin toplamından (işlemler ardışık yapıldığında), en uzun çağrının süresine dönüşür (işlemler paralel yapıldığında).
Scenario without Declarative eth_calls
Imagine you have a Subgraph that needs to make three Ethereum calls to fetch data about a user’s transactions, balance, and token holdings.
Geleneksel olarak, bu çağrılar ardışık olarak yapılabilir:
- Çağrı 1 (İşlem geçmişi): 3 saniye sürer
- Çağrı 2 (Bakiye): 2 saniye sürer
- Çağrı 3 (Token varlıkları): 4 saniye sürer
Toplam geçen süre = 3 + 2 + 4 = 9 saniye
Scenario with Declarative eth_calls
Bu özellik sayesinde bu çağrıların paralel olarak gerçekleştirileceğini belirtebilirsiniz:
- Çağrı 1 (İşlem geçmişi): 3 saniye sürer
- Çağrı 2 (Bakiye): 2 saniye sürer
- Çağrı 3 (Token varlıkları): 4 saniye sürer
Bu çağrılar paralel olarak yürütüldüğünden, toplam süre en uzun süren çağrının süresine eşittir.
Toplam süre = max (3, 2, 4) = 4 saniye
Nasıl Çalışır
- Declarative Definition: In the Subgraph manifest, you declare the Ethereum calls in a way that indicates they can be executed in parallel.
- Paralel Çalıştırma Motoru: Graph Düğümü’nün yürütme motoru bu bildirimleri tanır ve çağrıları aynı anda çalıştırır.
- Result Aggregation: Once all calls are complete, the results are aggregated and used by the Subgraph for further processing.
Subgraph Manifestosunda Örnek Yapılandırma
Declared eth_calls
can access the event.address
of the underlying event as well as all the event.params
.
subgraph.yaml
using event.address
:
1eventHandlers:2event: Swap(indexed address,indexed address,int256,int256,uint160,uint128,int24)3handler: handleSwap4calls:5 global0X128: Pool[event.address].feeGrowthGlobal0X128()6 global1X128: Pool[event.address].feeGrowthGlobal1X128()
Yukarıdaki örnek için detaylar:
global0X128
is the declaredeth_call
.- The text (
global0X128
) is the label for thiseth_call
which is used when logging errors. - The text (
Pool[event.address].feeGrowthGlobal0X128()
) is the actualeth_call
that will be executed, which is in the form ofContract[address].function(arguments)
- The
address
andarguments
can be replaced with variables that will be available when the handler is executed.
subgraph.yaml
using event.params
1calls:2 - ERC20DecimalsToken0: ERC20[event.params.token0].decimals()
Mevcut Subgraph’ta Graftlama
Note: it is not recommended to use grafting when initially upgrading to The Graph Network. Learn more here.
When a Subgraph is first deployed, it starts indexing events at the genesis block of the corresponding chain (or at the startBlock
defined with each data source) In some circumstances; it is beneficial to reuse the data from an existing Subgraph and start indexing at a much later block. This mode of indexing is called Grafting. Grafting is, for example, useful during development to get past simple errors in the mappings quickly or to temporarily get an existing Subgraph working again after it has failed.
A Subgraph is grafted onto a base Subgraph when the Subgraph manifest in subgraph.yaml
contains a graft
block at the top-level:
1description: ...2graft:3 base: Qm... # Subgraph ID of base Subgraph4 block: 7345624 # Block number
When a Subgraph whose manifest contains a graft
block is deployed, Graph Node will copy the data of the base
Subgraph up to and including the given block
and then continue indexing the new Subgraph from that block on. The base Subgraph must exist on the target Graph Node instance and must have indexed up to at least the given block. Because of this restriction, grafting should only be used during development or during an emergency to speed up producing an equivalent non-grafted Subgraph.
Because grafting copies rather than indexes base data, it is much quicker to get the Subgraph to the desired block than indexing from scratch, though the initial data copy can still take several hours for very large Subgraphs. While the grafted Subgraph is being initialized, the Graph Node will log information about the entity types that have already been copied.
Graftlanan subgraph, temel subgraphla tamamen aynı olmayan, ancak onunla uyumlu olan bir GraphQL şemasını kullanabilir. Kendi başına geçerli bir subgraph şeması olmalıdır, ancak şu şekillerde temel subgraph şemasından sapabilir:
- Varlık türlerini ekler veya kaldırır
- Varlık türlerinden öznitelikleri kaldırır
- Varlık türlerine null yapılabilir öznitelikler ekler
- Null yapılamayan öznitelikleri null yapılabilir özniteliklere dönüştürür
- Numaralandırmalara değerler ekler
- Arayüzleri ekler veya kaldırır
- Arayüzün hangi varlık türleri için uygulandığını değiştirir
Feature Management: grafting
must be declared under features
in the Subgraph manifest.