Pular para o conteúdo principal

The Graph: Corrigindo a consulta de dados na Web3

Solidity
contratos inteligentes
consulta
the graph
React
Intermediário
Markus Waas
6 de setembro de 2020
8 minutos de leitura

Desta vez, daremos uma olhada mais de perto no The Graph, que essencialmente se tornou parte da pilha padrão para o desenvolvimento de aplicativos descentralizados (dapps) no último ano. Vamos primeiro ver como faríamos as coisas da maneira tradicional...

Sem o The Graph...

Então, vamos usar um exemplo simples para fins de ilustração. Todos nós gostamos de jogos, então imagine um jogo simples com usuários fazendo apostas:

Agora digamos que em nosso dapp, queremos exibir o total de apostas, o total de jogos perdidos/ganhos e também atualizá-lo sempre que alguém jogar novamente. A abordagem seria:

  1. Buscar totalGamesPlayerWon.
  2. Buscar totalGamesPlayerLost.
  3. Inscrever-se nos eventos BetPlaced.

Podemos ouvir o evento na Web3 (opens in a new tab) conforme mostrado à direita, mas isso requer lidar com vários casos.

Agora, isso ainda é aceitável para o nosso exemplo simples. Mas digamos que agora queremos exibir os valores das apostas perdidas/ganhas apenas para o jogador atual. Bem, estamos sem sorte, é melhor você implantar um novo contrato que armazene esses valores e buscá-los. E agora imagine um contrato inteligente e um dapp muito mais complicados, as coisas podem ficar confusas rapidamente.

One Does Not Simply Query

Você pode ver como isso não é o ideal:

  • Não funciona para contratos já implantados.
  • Custos extras de gás para armazenar esses valores.
  • Requer outra chamada para buscar os dados de um nó Ethereum.

Thats not good enough

Agora vamos ver uma solução melhor.

Deixe-me apresentar o GraphQL

Primeiro, vamos falar sobre o GraphQL, originalmente projetado e implementado pelo Facebook. Você pode estar familiarizado com o modelo tradicional de API REST. Agora imagine se, em vez disso, você pudesse escrever uma consulta exatamente para os dados que deseja:

GraphQL API vs. REST API

Animated demonstration of a GraphQL query in The Graph playground

As duas imagens capturam muito bem a essência do GraphQL. Com a consulta à direita, podemos definir exatamente quais dados queremos, então obtemos tudo em uma única solicitação e nada mais do que exatamente o que precisamos. Um servidor GraphQL lida com a busca de todos os dados necessários, por isso é incrivelmente fácil para o lado do consumidor frontend usar. Esta é uma boa explicação (opens in a new tab) de como exatamente o servidor lida com uma consulta, se você estiver interessado.

Agora, com esse conhecimento, vamos finalmente pular para o espaço da blockchain e do The Graph.

O que é o The Graph?

Uma blockchain é um banco de dados descentralizado, mas, ao contrário do que geralmente acontece, não temos uma linguagem de consulta para esse banco de dados. As soluções para recuperar dados são dolorosas ou completamente impossíveis. O The Graph é um protocolo descentralizado para indexar e consultar dados da blockchain. E você já deve ter adivinhado, ele usa o GraphQL como linguagem de consulta.

The Graph

Exemplos são sempre a melhor forma de entender algo, então vamos usar o The Graph para o nosso exemplo do GameContract.

Como criar um Subgrafo

A definição de como indexar dados é chamada de subgrafo. Ele requer três componentes:

  1. Manifesto (subgraph.yaml)
  2. Esquema (schema.graphql)
  3. Mapeamento (mapping.ts)

Manifesto (subgraph.yaml)

O manifesto é o nosso arquivo de configuração e define:

  • quais contratos inteligentes indexar (endereço, rede, ABI...)
  • quais eventos ouvir
  • outras coisas para ouvir, como chamadas de função ou blocos
  • as funções de mapeamento sendo chamadas (veja mapping.ts abaixo)

Você pode definir vários contratos e manipuladores (handlers) aqui. Uma configuração típica teria uma pasta de subgrafo dentro do projeto Hardhat com seu próprio repositório. Então você pode referenciar facilmente a ABI.

Por motivos de conveniência, você também pode querer usar uma ferramenta de modelo como o mustache. Então você cria um subgraph.template.yaml e insere os endereços com base nas implantações mais recentes. Para uma configuração de exemplo mais avançada, veja, por exemplo, o repositório do subgrafo da Aave (opens in a new tab).

E a documentação completa pode ser vista aqui (opens in a new tab).

Esquema (schema.graphql)

O esquema é a definição de dados do GraphQL. Ele permitirá que você defina quais entidades existem e seus tipos. Os tipos suportados pelo The Graph são

  • Bytes
  • ID
  • String
  • Boolean
  • Int
  • BigInt
  • BigDecimal

Você também pode usar entidades como tipo para definir relacionamentos. Em nosso exemplo, definimos um relacionamento de 1 para muitos de jogador para apostas. O ! significa que o valor não pode estar vazio. A documentação completa pode ser vista aqui (opens in a new tab).

Mapeamento (mapping.ts)

O arquivo de mapeamento no The Graph define nossas funções que transformam eventos recebidos em entidades. Ele é escrito em AssemblyScript, um subconjunto do TypeScript. Isso significa que ele pode ser compilado em WASM (WebAssembly) para uma execução mais eficiente e portátil do mapeamento.

Você precisará definir cada função nomeada no arquivo subgraph.yaml, então, em nosso caso, precisamos de apenas uma: handleNewBet. Primeiro tentamos carregar a entidade Player a partir do endereço do remetente como id. Se ela não existir, criamos uma nova entidade e a preenchemos com os valores iniciais.

Em seguida, criamos uma nova entidade Bet. O id para isso será event.transaction.hash.toHex() + "-" + event.logIndex.toString() garantindo sempre um valor único. Usar apenas o hash não é suficiente, pois alguém pode estar chamando a função placeBet várias vezes em uma transação por meio de um contrato inteligente.

Por fim, podemos atualizar a entidade Player com todos os dados. Arrays não podem receber push diretamente, mas precisam ser atualizados conforme mostrado aqui. Usamos o id para referenciar a aposta. E .save() é necessário no final para armazenar uma entidade.

A documentação completa pode ser vista aqui: https://thegraph.com/docs/en/developing/creating-a-subgraph/#writing-mappings (opens in a new tab). Você também pode adicionar saída de log ao arquivo de mapeamento, veja aqui (opens in a new tab).

Usando no Frontend

Usando algo como o Apollo Boost, você pode integrar facilmente o The Graph em seu dapp React (ou Apollo-Vue). Especialmente ao usar React hooks e Apollo, buscar dados é tão simples quanto escrever uma única consulta GraphQL em seu componente. Uma configuração típica pode ser assim:

E agora podemos escrever, por exemplo, uma consulta como esta. Isso nos buscará

  • quantas vezes o usuário atual ganhou
  • quantas vezes o usuário atual perdeu
  • uma lista de carimbos de data/hora (timestamps) com todas as suas apostas anteriores

Tudo em uma única solicitação ao servidor GraphQL.

Magic

Mas está faltando uma última peça do quebra-cabeça e esse é o servidor. Você pode executá-lo por conta própria ou usar o serviço hospedado.

O servidor do The Graph

Graph Explorer: O serviço hospedado

A maneira mais fácil é usar o serviço hospedado. Siga as instruções aqui (opens in a new tab) para implantar um subgrafo. Para muitos projetos, você pode realmente encontrar subgrafos existentes no explorer (opens in a new tab).

The Graph-Explorer

Executando seu próprio nó

Alternativamente, você pode executar seu próprio nó. Documentação aqui (opens in a new tab). Um motivo para fazer isso pode ser o uso de uma rede que não é suportada pelo serviço hospedado. As redes atualmente suportadas podem ser encontradas aqui (opens in a new tab).

O futuro descentralizado

O GraphQL também suporta fluxos (streams) para novos eventos recebidos. Eles são suportados no The Graph por meio de Substreams (opens in a new tab), que estão atualmente em beta aberto.

Em 2021 (opens in a new tab), o The Graph iniciou sua transição para uma rede de indexação descentralizada. Você pode ler mais sobre a arquitetura dessa rede de indexação descentralizada aqui (opens in a new tab).

Dois aspectos principais são:

  1. Os usuários pagam aos indexadores pelas consultas.
  2. Os indexadores fazem stake de Graph Tokens (GRT).