Debugging de Subgraphs Rápido e Fácil Com Forks
Reading time: 4 min
Assim como vários sistemas que processam uma abundância de dados, os Indexadores do Graph (Graph Nodes) podem demorar um pouco para sincronizar o seu subgraph com a blockchain de destino. A discrepância entre mudanças rápidas para fins de debugging e os longos tempos de espera necessários para o indexing é extremamente contraprodutiva, e nós sabemos muito bem disso. É por isso que introduzimos o subgraph forking, desenvolvido pela ; neste artigo, veja como é possível acelerar bastante o debugging de subgraphs!
Subgraph forking é o processo de retirar entidades tranquilamente do armazenamento de outro subgraph (sendo muitas vezes remoto).
No contexto do debugging, o subgraph forking permite debugar o seu subgraph falho no bloco X sem precisar esperar que ele sincronize até o bloco X.
Quando lanças um subgraph a um Graph Node remoto para o indexing e ele falha no bloco X, a boa notícia é que o Graph Node ainda servirá queries GraphQL com seu armazenamento, que é sincronizado até o bloco X. Ótimo! Podemos aproveitar este armazenamento "atualizado" para consertar os bugs que surgem ao indexar o bloco X.
Resumindo, faremos um fork do subgraph falho de um Graph Node remoto para garantir que o subgraph seja indexado até o bloco X, para fornecer ao subgraph lançado localmente uma visão atualizada do estado da indexação, sendo este debugado no bloco X.
Para manter o foco no debugging dos subgraphs, vamos simplificar as coisas e seguir o com a indexação do contrato inteligente do Ethereum Gravity.
Aqui estão os handlers definidos para o indexamento dos Gravatar
s, sem qualquer bug:
export function handleNewGravatar(event: NewGravatar): void {let gravatar = new Gravatar(event.params.id.toHex().toString())gravatar.owner = event.params.ownergravatar.displayName = event.params.displayNamegravatar.imageUrl = event.params.imageUrlgravatar.save()}export function handleUpdatedGravatar(event: UpdatedGravatar): void {let gravatar = Gravatar.load(event.params.id.toI32().toString())if (gravatar == null) {log.critical('Gravatar not found!', [])return}gravatar.owner = event.params.ownergravatar.displayName = event.params.displayNamegravatar.imageUrl = event.params.imageUrlgravatar.save()}
Que pena! Quando eu lanço o meu lindo subgraph ao , ele falha com o erro "Gravatar not found" (Gravatar não encontrado).
A maneira mais comum de tentar consertar este erro é:
- Fazer uma mudança na fonte dos mapeamentos, que talvez possa resolver o problema (mas é claro que não vai).
- Reeditar o subgraph ao (ou outro Graph Node remoto).
- Esperar que ele se sincronize.
- Se quebrar novamente, volte ao passo 1. Se não: Eba!
É um típico processo ordinário de debug, mas há um passo que retarda muito o processo: 3. Esperar que ele se sincronize.
Com o subgraph forking, podemos essencialmente eliminar este passo. Ele é algo assim:
- Crie um Graph Node local com o conjunto de fork-base apropriado.
- Faça uma mudança na fonte dos mapeamentos, que talvez possa resolver o problema.
- Lance ao Graph Node local, faça um fork do subgraph falho e comece do bloco problemático.
- Se quebrar novamente, volte ao passo 1. Se não: Eba!
Agora, você deve ter duas perguntas:
- Que fork-base???
- Forkar quem?!
E eu respondo:
fork-base
é o URL "base", tal que quando o subgraph id é atrelado, o URL resultante (<fork-base>/<subgraph-id>
) se torna um endpoint GraphQL válido para o armazenamento do subgraph.- Forking é fácil, não precisa se preocupar:
$ graph deploy <subgraph-name> --debug-fork <subgraph-id> --ipfs http://localhost:5001 --node http://localhost:8020
Aliás, não esqueça de preencher o campo dataSources.source.startBlock
no manifest do subgraph com o número do bloco problemático, para pular a indexação de blocos desnecessários e tomar vantagem do fork!
Aqui está o que eu faço:
- Eu crio um Graph Node local () com a opção
fork-base
dehttps://api.thegraph.com/subgraphs/id/
, já que eu vou forkar um subgraph, o bugado que eu lancei anteriormente, do .
$ cargo run -p graph-node --release -- \--postgres-url postgresql://USERNAME[:PASSWORD]@localhost:5432/graph-node \--ethereum-rpc NETWORK_NAME:[CAPABILITIES]:URL \--ipfs 127.0.0.1:5001--fork-base https://api.thegraph.com/subgraphs/id/
- Após vistoriar com cuidado, percebo uma discrepância nas representações de
id
usadas ao indexarGravatars
nos meus dois handlers. EnquantohandleNewGravatar
o converte a um hex (event.params.id.toHex()
), ohandleUpdatedGravatar
usa um int32 (event.params.id.toI32()
). Assim, ohandleUpdatedGravatar
entra em pânico com o "Gravatar não encontrado!". Eu faço os dois converterem oid
em um hex. - Após ter feito as mudanças, lanço o meu subgraph ao Graph Node local, forkando o subgraph falho e programando o
dataSources.source.startBlock
em6190343
nosubgraph.yaml
:
$ graph deploy gravity --debug-fork QmNp169tKvomnH3cPXTfGg4ZEhAHA6kEq5oy1XDqAxqHmW --ipfs http://localhost:5001 --node http://localhost:8020
- Eu verifico os logs produzidos pelo Graph Node local e... eba! Parece que deu tudo certo.
- Lanço o meu subgraph, agora livre de bugs, a um Graph Node remoto e vivo feliz para sempre! (mas sem batatas)