WEB3DEV

Cover image for RPCs Ethereum, Métodos e Chamadas
Panegali
Panegali

Posted on • Atualizado em

RPCs Ethereum, Métodos e Chamadas

JSON RPC, métodos, chamadas, solicitações - o que tudo isso significa?! Quando você começa a construir um dapp na ​​blockchain Ethereum, você é apresentado a uma série de novos conceitos, métodos de solicitação e convenções de nomenclatura para empregar - pode ser esmagador. A equipe da Infura é especialista em infraestrutura web3. Construímos ferramentas e materiais de código aberto para ajudar mais desenvolvedores a interagir com a Ethereum e IPFS. Neste tutorial, aproveitamos a experiência coletiva de nossa equipe para trazer a você um guia detalhado de leitura e gravação de solicitações para a blockchain Ethereum, usando a Infura.

Principais Termos e Conceitos

Antes de entrar no assunto deste tutorial, vamos esclarecer algumas terminologias importantes. Abaixo está uma lista de termos importantes e suas definições correspondentes com as quais você precisa se familiarizar.

Solicitar

Um desenvolvedor interage com a Infura enviando uma solicitação por meio de JSON RPC por HTTP ou WebSocket; como uma única solicitação ou como uma matriz em lote. As solicitações seguem este formato:

{"id":1234, "method": "eth_foo", "params":[...] }

Como você deve postar isso em um endpoint que tenha sua chave v3, sempre podemos associar essas solicitações a uma chave ou a um projeto.

Método

O método é essencialmente a função na qual estamos pedindo a um nó Ethereum para executar. Isso solicitará dados do nó, executará uma função EVM e retornará uma resposta ou transmitirá dados para a rede Ethereum (enviará uma transação). Atualmente existem 65 métodos que são suportados pelos clientes populares da Ethereum (Geth, Parity, Besu, Nethermind):

1

Os métodos mais utilizados estão destacados em negrito e compreendem a grande maioria do tráfego da Infura:

2

Esses métodos podem ser agrupados nas seguintes categorias:

  • Bloquear Dados Relacionados
  1. eth_getBlockByHash: recupera os detalhes de um bloco pelo seu hash (uma string representando o hash de 32 bytes de um bloco);
  2. eth_getBlockByNumber: recupera os detalhes de um bloco pelo seu número (um número inteiro do bloco, ou a string "latest", "earliest" ou "pending");
  3. eth_blockNumber: recupera o número do bloco atual.

Estes métodos recuperam dados estáticos sobre um bloco específico na blockchain. Esses dados estão contidos nos cabeçalhos da blockchain e podem incluir informações como número do bloco ou transações extraídas, por exemplo.

  • Dados por usuário (endereço)
  1. eth_getTransactionCount: recupera o nonce de um endereço (ou seja: quantas transações já foram mineradas, por usuário, para esse endereço). Isso é necessário porque quando você vai enviar uma nova transação, há um campo chamado 'the nonce' que se destina a impedir que você retransmita acidentalmente as transações e as envie em uma ordem que você não pretendia.

Este método recupera os dados de estado simples para endereços. Não importa se esse endereço é um usuário ou um contrato inteligente. Qualquer endereço pode ter um saldo ETH.

- Lendo dados de contratos inteligentes existentes

O conceito de contratos inteligentes e a interação com eles é o que torna a Ethereum diferente de outras blockchains. Um contrato inteligente é duas coisas:

  1. É um pouco de código, geralmente escrito em Solidity, que compila em byte code - que é entendido pela Ethereum Virtual Machine (EVM);
  2. É um meio de armazenamento. Pense nisso como o meio caminho entre 'armazenamento em disco' e 'ram'.

Abaixo estão os métodos mais comuns para interagir com contratos inteligentes:

  • eth_call: recupera um método EVM constante em um contrato inteligente e é a principal maneira de recuperar dados já extraídos da blockchain sobre um contrato inteligente específico;
  • eth_getLogs: recupera eventos publicados por transações de contrato inteligente. Contratos inteligentes podem emitir logs que são realmente definidos pelo usuário, portanto, ao criar esse contrato inteligente, você pode decidir o formato desses eventos de log. Esses dapps podem ver quando seu contrato inteligente emitiu esses eventos e responder de acordo;
  • eth_getStorageAt: recupera o armazenamento de estado bruto para um contrato inteligente;
  • eth_getCode: recupera o código EVM compilado para um contrato inteligente. Não há cópia do código-fonte de um contrato inteligente na própria blockchain. Assim, por exemplo, quando você pesquisa um endereço no Etherscan e o código verificador deste contrato inteligente é retornado, tudo acontece off chain.

Usando eth_call

O ERC20 é um padrão de como os desenvolvedores podem criar um token. Quase todos os softwares de carteira entendem esse padrão, portanto, se você deseja criar um token e facilitar a interação das pessoas com ele, o ERC20 é um bom lugar para começar.

Eth_call é o método mais comumente usado para interagir com contratos inteligentes, particularmente contratos ERC20. Uma solicitação típica eth_call se parece com isso:

3

À primeira vista, não está claro o que estas informações representam. Vamos vê-las por partes :

4

O campo "id":1 é uma string identificadora definida pelo solicitante e ajuda a garantir que o cliente e o servidor estejam se comunicando no mesmo contexto.

O campo "jsonrpc":"2.0" especifica a versão do protocolo e deve ser exatamente “2.0”, o que o protocolo espera.

O campo from é o solicitante de dados, que pode ser qualquer endereço de carteira ou contrato inteligente. Este campo é opcional.

O campo to é sempre um contrato inteligente. Existem duas maneiras de descobrir o que é esse contrato inteligente:

  1. Você pode fazer uma solicitação na blockchain usando eth _getCode, mas isso forneceria o código compilado. A menos que você tenha ferramentas para fazer engenharia reversa do byteCode EVM, você não saberá imediatamente o que isso significa.

  2. Você pode digitar o endereço do contrato inteligente no Etherscan. Pesquisar no Etherscan é a maneira mais comum de descobrir com que tipo de contrato inteligente você está lidando. Vamos pegar o endereço do contrato inteligente 0x6B175474E89094C44Da98b954EedeAC495271d0F e digitá-lo para ver o que acontece:

5

O Etherscan nos diz que este contrato inteligente é para a 'Stablecoin Dai (DAI)'. Neste ponto, também temos a oportunidade de inspecionar o código Solidity original para este contrato e confirmar que ele foi verificado:

6

Excelente! Agora sabemos que este endereço representa um contrato ERC20.

Entrando no ERC20

Criado em 2015, o ERC20 é um padrão de token relativamente simples e o tipo de contrato mais comum na Ethereum. Dentro deste padrão, um token ERC20 deve implementar as seguintes funções:

  • function totalSupply() public constant returns (uint);
  • function balanceOf(address tokenOwner) public constant returns (uint balance);
  • function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
  • function transfer(address to, uint tokens) public returns (bool success);
  • function approve(address spender, uint tokens) public returns (bool success);
  • function transferFrom(address from, address to, token uint) public returns (bool success).

Em determinados momentos, um token ERC20 também deve emitir os seguintes eventos:

  • event Transfer(address indexed from, address indexed to, uint tokens);
  • event Approval(address indexed tokenOwner, addressed indexed spender, uint tokens).

Você pode visualizar o padrão no GitHub para obter mais detalhes sobre como essas funções funcionam e quando emitir esses eventos. Por enquanto, vamos tentar solicitar o saldo de alguns dos tokens DAI.

Sabemos que nosso endereço é 0xDfBaf3E4c7496DAd574a1B842bC85B402BDC298D.

Também sabemos que o endereço do contrato DAI é 0x6B175474E89094C44Da98b954EedeAC495271d0F.

Para consultar nosso saldo usando eth_call, nós utilizamos a função balanceOf do contrato de token. O formato JSON-RPC espera eth_call ter um formato de campo de dados específico que requer a normalização da função de contrato balanceOf para um seletor de função curta . Para fazer isso, retiramos os nomes e o tipo de entradas que ele recebe e tomamos isso como uma string. Em seguida, executamos o hash sha3 keccak da Ethereum:

web3_sha3(“balanceOf(address)”)[0..4]-> 0x70a08231

Os primeiros quatro bytes desse hash compreendem sua assinatura de 4 bytes. Em seguida, pegamos essa assinatura de 4 bytes, preenchemos com zeros, adicionamos nosso endereço como entrada e enviamos o eth_call:

7

Este é um número hexadecimal, preenchido com um comprimento de 32 bytes com zeros. Se quisermos, podemos converter essa saída em um número decimal usando um conversor hexadecimal. Isso retornaria o resultado 3,890227426645114e+24, que é a notação científica para 3,890227426645114 * 10^24. Este é o saldo do contrato do Dai em wei, uma unidade padrão de 10^18.

Então, finalmente, dívida 3,890227426645114 * 10^24 por 10^18. Agora sabemos que o saldo do endereço da carteira 0xDfBaf3E4c7496DAd574a1B842bC85B402BDC298D neste contrato é 3.890.227,426645114 Dai.

Enviando transações

Eth_calls são comumente usados ​​para ler dados de um contrato inteligente. Mas e se você quiser gravar dados em um contrato inteligente?

Digamos que queremos chamar a função de transferência. Novamente, precisaríamos normalizar a função primeiro. Pegamos a string transfer(address to, uint tokens) e fazemos o hash para obter a assinatura de 4 bytes. Novamente, pegamos essa assinatura de 4 bytes, preenchemos com zeros, inserimos o endereço e a quantidade de tokens e empacotamos essas informações em uma string de dados. Em seguida, assinamos a transação e a enviamos usando eth_sendRawTransaction.

A este ponto, os nós começam a transmitir a nossa transação para o resto da rede. Eventualmente, um minerador obterá uma cópia dele, passará por todas as suas coisas de prova de trabalho, terá sorte e encontrará um hash que corresponda à prova de trabalho e transmitirá um bloco que contenha a nossa transação. Cada nó que recebe este bloco lê as transações dentro dele, as executa novamente e mantém nossa transação de token ERC20 no EVM para atualização.

O gas é enviado junto com quaisquer outros valores e é gasto executando o código EVM. O minerador recebe a recompensa do bloco, além de todo o gas gasto nas transações. Se você quiser saber mais sobre como a mineração da Ethereum funciona, esses documentos do EthHub são um ótimo começo.

Transações Minadas

Quando uma transação é minerada, duas coisas importantes acontecem: o estado on-chain da Ethereum é alterado por meio de interações de contrato e os logs de eventos são publicados para visualização pública. Uma vez que os logs de eventos são publicados, podemos executar solicitações JSON-RPC para eth_getLogs investigar o que mudou, em relação aos eventos que nos interessam, e reagir a eles.

Por exemplo: um serviço de emissão de ingressos de eventos que deseja emitir ingressos fora da cadeia com base em pagamentos criptográficos, pode usar eth_getLogs para encontrar pagamentos em seu endereço e reagir a esses eventos processando alguma lógica em seus servidores de back-end para emitir ingressos para usuários.

Usando eth_getLogs

8

Na solicitação de amostra acima, usamos os parâmetros "from block" e "to block" para especificar o número do bloco hexadecimal do qual estamos interessados ​​em recuperar os logs. Observe que se esta informação for omitida, o método retornará informações do "bloco 0" ao "bloco mais recente" por padrão (todo o histórico da cadeia) e isso não é o ideal. A Infura tem um limite de solicitações de 10.000 eventos por consulta. A melhor prática é solicitar um único bloco, como fizemos neste exemplo, e fazer isso para cada bloco minerado.

O que esta solicitação está dizendo a blockchain é “ei, quero logs de eventos relacionados ao endereço 0x6B175474E89094C44Da98b954EedeAC495271d0F emitido no bloco 0x91F37C (hexadecimal para o bloco 9565052) que corresponda aos tópicos 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef e .0x000000000000000000000000ee25e1ba53c225d250861c8e5a9a3e0fe19c790e 0x000000000000000000000000dfbaf3e4c7496dad574a1b842bc85b402bdc298d.

9

A resposta retornada para esta solicitação é uma matriz de eventos. No exemplo que estamos usando, apenas um evento para um endereço correspondeu aos tópicos especificados.

Tópicos

Os tópicos são eventos emitidos por contratos inteligentes. Se olharmos novamente o contrato original ERC20 Solidity de DAI 0x6B175474E89094C44Da98b954EedeAC495271d0F, podemos ver duas assinaturas de eventos que podem estar associadas a ele:

  • 94 event Transfer(address indexed from, address indexed to, uint tokens);
  • 95 event Approval(address indexed tokenOwner, address indexed spender, uint tokens).

Como descobrimos qual tópico (evento) realmente era? Você adivinhou: temos que criar o Seletor de Função do Evento e pegar o hash dele. Vamos tentar o evento na linha 94:

web3.sha3('Aprovação(endereço,endereço,uint256)')

O hash resultante é 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. Isso não corresponde ao hash fornecido na resposta da solicitação inicial. Agora vamos tentar o evento na linha 95 do contrato:

web3.sha3('Transferir(endereço,endereço,uint256)')

Bingo! O hash resultante é 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, que corresponde ao hash fornecido na resposta da solicitação inicial. Agora sabemos que 0xddf25 é o evento * Transfer*.

Mais registros de eventos

Você pode estar se perguntando o que significa o data fornecido na resposta da solicitação:

10

Nesse contexto, data refere-se a todas as 'coisas não indexadas' capturadas nos eventos. Em nosso exemplo, para o tópico Transferir, data representa o número de tokens que foram transferidos. Ou seja, aquele 0x41f900d25d6693623a6 ou 19471.6949921 tokens Dai foram transferidos de ee25e1ba53c225d250861c8e5a9a3e0fe19c790e para dfbaf3e4c7496dad574a1b842bc85b402bdc298d.

Isso completa nossa investigação!

Veja nossa documentação do desenvolvedor para explorar diferentes maneiras de interagir com a Infura para ler e gravar dados da Ethereum. Novo na Infura ? Inscreva-se e comece gratuitamente!


Este artigo foi escrito por Talia Knowles-Rivas e traduzido por Marcelo Panegali. O original pode ser encontrado aqui.

Latest comments (0)