Como crear un subgrafo con TheGraph | CourseIt Blog
logo courseit

Como crear un subgrafo con TheGraph

16

Leer data de la blockchain es difícil. La forma en que la misma esta estructurada y como es accedida hace que muchas veces tengamos que hacer código complejo o rebuscado para poder tener la información que necesitamos. Por suerte para nosotros existe TheGraph, un protocolo que nos permite mappear la data que se guarda en la blockchain a una estructura de datos que nos sea conveniente para el consumo futuro. En este articulo vamos a ver como crear un subgrafo para analizar todo lo que es vouching en Proof of humanity.

Primero que nada vamos a ingresar en: https://thegraph.com/studio/ que es la URL del subgraph studio, la UI en donde vamos a estar gestionando nuestro subgrafo. Esto lo podemos hacer porque PoH esta en una de las redes soportadas por este producto, caso contrario tendríamos que utilizar el hosted service (https://thegraph.com/hosted-service/) que si bien es parecido tiene algunas particularidades y seguimos los siguientes pasos:

  • Click en el botón: "Create subgraph" y llenamos la información que nos pide

  • Instalamos graph cli en nuestro entorno de desarrollo con el comando npm install -g @graphprotocol/graph-cli

  • Inicializamos el subgrafo con el comando graph init --studio NOMBRE_SUBGRAFO. Luego de ejecutar el comando, la consola nos va a pedir cierta información para poder crear el subgrafo. En nuestro caso va a ser la siguiente:

✔ Protocol · ethereum

✔ Subgraph slug · nombre_de_tu_subgrafo

✔ Directory to create the subgraph in · poh

✔ Ethereum network · mainnet

✔ Contract address · 0xc5e9ddebb09cd64dfacab4011a0d5cedaf7c9bdb

✔ Contract Name · ProofOfHumanity

Una vez que tengamos inicializado el subrafo en nuestro entorno de desarrollo nos queda autenticarnos y hacer un deploy con el proyecto base qeu nos genera. Para eso vamos a tener que tipear el comando graph auth en nuestra terminal e ingresar la deploy key que podemos encontrar en nuestro dashboard dentro del subgraph studio. En mi caso: https://thegraph.com/studio/subgraph/poh/.

Al terminar eso ingresamos a la carpeta de nuestro subgrafo con el comando cd poh y lo deployamos con npm run deploy. Este comando nos va a pedir que ingresemos una etiqueta para nuestra version, por el momento vamos a ponerle 0.0.1 ya que simplemente estamos probando nuestro deploy.

Habiendo seguido todos estos pasos, si entran nuevamente a la URL de su subgrafo en el subgraph studio, van a ver que el estado del mismo ahora dice: "Deployed", el playground del mismo esta habilitado y luego de algunos minutos va a empezar el proceso de sincronización. Nota de color: Este proceso lleva bastante tiempo, no se asusten.

Genial, ya tenemos nuestro subgrafo, el único problema es que hasta ahora no hace nada. Para poder resolver ese problema vamos a tener que modificar algunas cosas del proyecto que generamos en nuestro entorno de desarrollo. TheGraph nos genera un scaffolding base en donde vamos a prestar especial atención a dos archivos ./schema.graphql y src/mapping.ts. En el primero vamos a tener que definir nuestro modelo de datos mientras que en el segundo vamos a tener la lógica que hace convierte la información de la blockchain al esquema que definimos.

Para no alargar ni complejizar este post en particular, solo vamos a mostrar el resultado final de como definimos nuestro modelo, pero si quieren aprenderlo al detalle pueden verlo en la documentación oficial the GraphQL.

El contenido de nuestro archivo schema.graphql tiene que quedar de la siguiente forma:

type User @entity {
  id: ID!
  vouches: [User!]!
  registerDate: BigInt!
}

Lo que acabamos de hacer fue definir una nueva entidad bajo el nombre User que contiene las propiedades id, vouches, registerDate en donde el ID es el address del usuario, vouches es un array con todas las personas que ese usuario voucheo y registerDate es la fecha en la que el usuario se dio de alta. Ahora, para regenerar los archivos de nuestro subgrafo tenemos que ingresar en nuestra consola el comando graph codegen

Ahora nos toca modificar el archivo mapping.ts que es donde vamos a crear esta logica para convertir de formato blockchain a nuestro modelo de datos. Si bien ahora vamos a explicar un poco que hace cada cosa, el codigo completo es el siguiente:

import {
  AddSubmission,
  VouchAdded,
  VouchRemoved
} from "../generated/ProofOfHumanity/ProofOfHumanity";

import { User } from "../generated/schema";

export function handleVouchAdded(event: VouchAdded): void {
  let user = User.load(event.transaction.from.toHex());

  if (user == null) return;

  let vouches = user.vouches;
  vouches.push(event.params._submissionID.toHex());
  user.vouches = vouches;
  user.save();
}

export function handleAddSubmission(event: AddSubmission): void {
  let user = new User(event.params._submissionID.toHex());
  user.vouches = new Array<string>();
  user.registerDate = event.block.timestamp;
  user.save();
}

La idea del código que acabamos de ver es manejar dos eventos de la blockchain. El primero es VouchAdded y el segundo es AddSubmission los cuales se encargan de notificar cada vez que alguien vouchea a otra persona y cuando alguien se da de alta en PoH. Esta información la busque y saque del contrato oficial que pueden encontrar acá.

Si bien la lógica de cada función es diferente, la idea base es leer la información de la blockchain y transformarla en algo que a nos sea mas fácil de consumir por lo que en ambas funciones lo que hacemos es generar una nueva instancia del modelo que creamos en mapping.ts y cargarle la información que sea necesaria en ese momento, veamos el código documentado:

export function handleVouchAdded(event: VouchAdded): void {
  // Creamos una instancia del modelo User, el ID de esa nueva instancia va a ser el campo "from" de la transaccion
  // El .toHex() es para transformarlo en un tipo de dato valido para ser almacenado como ID
  let user = User.load(event.transaction.from.toHex());

  // Si el usuario no existe, no seguimos haciendo nada, esto es porque un usuario que no existe no deberia poder vouchear a otros
  if (user == null) return;

  // Leemos los vouches del usuario
  let vouches = user.vouches;
  
  // Le sumamos un nuevo vouch al array en base al evento que estamos recibiendo en este momento
  vouches.push(event.params._submissionID.toHex());
  
  // Actualizamos los vouches del usuario
  user.vouches = vouches;

  // Actualizamos la informacion del usuario
  user.save();
}
export function handleAddSubmission(event: AddSubmission): void {
  // Nuevamente creamos una instancia de nuestro usuario en este caso como ID usamos el valor de uno de los parametros de nuestro evento
  let user = new User(event.params._submissionID.toHex());

  // Creamos un array vacio para nuestros vouches
  user.vouches = new Array<string>();

  // Guardamos la fecha de registro del usuario
  user.registerDate = event.block.timestamp;

  // Guardamos el usuario
  user.save();
}

Una vez que tengamos esto armado, nos toca volver a deployar nuestro subgrafo para poder probar si esta funcionando como esperamos. Para eso primero vamos a revisar que nuestro código se haya generado correctamente y no tenga errores a la hora de buildear por lo que tenemos que correr el comando graph codegen && graph build en nuestra terminal. Una vez que eso haya funcionado correctamente vamos a deployarlo con el comando graph deploy --studio poh

Una vez que el deploy haya terminado y la nueva version de nuestro subgrafo este completamente sincronizada, podemos empezar a jugar con el playground.

Por ejemplo con la siguiente query vamos a ver los primeros 500 usuarios que fueron sincronizados:

{
  users(first: 500) {
    id
    vouches {
      id
    }
    registerDate
  }
}

O con esta query podemos ver a las personas que le hice vouch desde mi perfil:

{
  users(where:{id: "0x3111992d5ddc310654a6978fad3ff56da6fb25ca"}) {
    id
    vouches {
      id
    }
    registerDate
  }
}

Listo! Ya tenemos nuestro subgrafo deployado y funcionando tal y como esperabamos. ¿Ahora como seguimos? Bueno, hay un millón de cosas mas para aprender. Mi recomendación es que vayan a la documentación oficial de TheGraph y lean sobre los distintos parametros que se pueden configurar en el archivo subgraph.yaml como para empezar a entender que optimizaciones se pueden hacer (por ejemplo agregar un startBlock para reducir tiempos de sincronización) y como crear cosas un poco mas complejas con multiples dataSources