Cookbook > Subgraph Best Practice 4: Avoid eth_calls

Melhores Práticas de Subgraph Parte 4 - Como Melhorar a Velocidade da Indexação ao Evitar eth_calls

Reading time: 4 min

TLDR

Link para esta seção

eth_calls são chamadas feitas de um subgraph a um node no Ethereum. Estas chamadas levam um bom tempo para retornar dados, o que retarda a indexação. Se possível, construa contratos inteligentes para emitir todos os dados necessários, para que não seja necessário usar eth_calls.

Por que Evitar eth_calls É uma Boa Prática

Link para esta seção

Subgraphs são otimizados para indexar dados de eventos emitidos de contratos inteligentes. Um subgraph também pode indexar os dados que vêm de uma eth_call, mas isto pode atrasar muito a indexação de um subgraph, já que eth_calls exigem a realização de chamadas externas para contratos inteligentes. A capacidade de respostas destas chamadas depende não apenas do subgraph, mas também da conectividade e das respostas do node do Ethereum a ser consultado. Ao minimizar ou eliminar eth_calls nos nossos subgraphs, podemos melhorar muito a nossa velocidade de indexação.

Como É Um eth_call?

Link para esta seção

eth_calls tendem a ser necessárias quando os dados requeridos por um subgraph não estão disponíveis via eventos emitidos. Por exemplo, vamos supor que um subgraph precisa identificar se tokens ERC20 são parte de um pool específico, mas o contrato só emite um evento Transfer básico e não emite um evento que contém os dados que precisamos:

event Transfer(address indexed from, address indexed to, uint256 value);

Suponhamos que a filiação de pool dos tokens seja determinada por um variável de estado chamado getPoolInfo. Neste caso, precisaríamos usar uma eth_call para consultar estes dados:

import { Address } from '@graphprotocol/graph-ts'
import { ERC20, Transfer } from '../generated/ERC20/ERC20'
import { TokenTransaction } from '../generated/schema'
export function handleTransfer(event: Transfer): void {
let transaction = new TokenTransaction(event.transaction.hash.toHex())
// Atrele a instância de contrato ERC20 ao endereço dado:
let instance = ERC20.bind(event.address)
// Retire a informação do pool via eth_call
let poolInfo = instance.getPoolInfo(event.params.to)
transaction.pool = poolInfo.toHexString()
transaction.from = event.params.from.toHexString()
transaction.to = event.params.to.toHexString()
transaction.value = event.params.value
transaction.save()
}

Isto é funcional, mas não ideal, já que ele atrasa a indexação do nosso subgraph.

Como Eliminar eth_calls

Link para esta seção

Idealmente, o contrato inteligente deve ser atualizado para emitir todos os dados necessários dentro de eventos. Por exemplo, modificar o contrato inteligente para incluir informações de pools no evento pode eliminar a necessidade de eth_calls:

event TransferWithPool(address indexed from, address indexed to, uint256 value, bytes32 indexed poolInfo);

Com esta atualização, o subgraph pode indexar directamente os dados exigidos sem chamadas externas:

import { Address } from '@graphprotocol/graph-ts'
import { ERC20, TransferWithPool } from '../generated/ERC20/ERC20'
import { TokenTransaction } from '../generated/schema'
export function handleTransferWithPool(event: TransferWithPool): void {
let transaction = new TokenTransaction(event.transaction.hash.toHex())
transaction.pool = event.params.poolInfo.toHexString()
transaction.from = event.params.from.toHexString()
transaction.to = event.params.to.toHexString()
transaction.value = event.params.value
transaction.save()
}

Assim, o desempenho melhora muito por eliminar a necessidade de eth_calls.

Como Otimizar eth_calls

Link para esta seção

Se não for possível modificar o contrato inteligente e se eth_calls forem necessários, leia “Improve Subgraph Indexing Performance Easily: Reduce eth_calls” para aprender várias estratégias sobre como otimizar eth_calls.

Como Reduzir o Overhead de Runtime de eth_calls

Link para esta seção

Para eth_calls que não podem ser eliminadas, o overhead de runtime que elas introduzem pode ser minimizado ao declará-las no manifest. Quando ograph-node processa um bloco, ele realiza todas as eth_calls em paralelo antes da execução dos handlers. Chamadas não declaradas são executadas em sequência quando os handlers são executados. A melhoria do runtime vem da execução das chamadas em paralelo, e não em sequência - isto ajuda a reduzir o tempo total gasto em chamadas, mas não o elimina por completo.

Atualmente, eth_calls só podem ser declaradas para handlers de evento. No manifest, escreva

event: TransferWithPool(address indexed, address indexed, uint256, bytes32 indexed)
handler: handleTransferWithPool
calls:
ERC20.poolInfo: ERC20[event.address].getPoolInfo(event.params.to)

A porção destacada em amarelo é a declaração de chamada. A parte antes dos dois pontos é apenas um rótulo de texto usado só para mensagens de erro. A parte após os dois pontos tem a forma Contract[address].function(params). Valores permissíveis para address e params são event.address e event.params.<name>.

O próprio handler acessa o resultado desta eth_call exatamente como na secção anterior ao atrelar ao contrato e fazer a chamada. o graph-node coloca em cache os resultados de eth_calls na memória e a chamada do handler terirará o resultado disto no cache de memória em vez de fazer uma chamada de RPC real.

Nota: eth_calls declaradas só podem ser feitas em subgraphs com specVersion maior que 1.2.0.

Podemos melhorar muito o desempenho da indexação ao minimizar ou eliminar eth_calls nos nossos subgraphs.

Editar página

Anterior
Subgraph Best Practice 3: Using Immutable Entities and Bytes as IDs
Próximo
Tranfer to The Graph
Editar página