No momento da escrita (Nov 2022), existem mais de 7.000 nós Ethereum rodando no mundo. 79% deles são Geth e cerca de 21% são outros tipos de clientes.
Figura 1: Distribuição de nós Ethereum
Geth e Erigon são os dois clientes Ethereum mais populares no mercado. Ambos implementam um conjunto especial de APIs para depuração de transações – a API de rastreamento.
Este artigo explica o que são as APIs debug_trace e como usá-las com exemplos de código para cada método.
Existem alguns conceitos que você deve conhecer antes de mergulhar no rastreamento:
- O que é transação
- O que é estado
- O que é bloco
- O que acontece quando você chama um contrato
Se você não tem certeza sobre essas terminologias, por favor, confira este artigo sobre eth_call. Ele explica como as transações são executadas pela Ethereum, que é fundamental para o rastreamento. Se você tiver dificuldade em entender os conceitos e termos neste artigo, ler o artigo eth_call pode ajudar.
O que é rastreamento?
Uma transação de blockchain pode falhar devido a várias razões, por exemplo:
- A conta do remetente fica sem ether para pagar o gás.
- Há um bug em um dos contratos inteligentes.
- Um usuário está na lista negra.
- O uso da CPU excede seus limites durante a execução da chamada
O rastreamento pode ajudar a identificar a causa raiz da falha, em qual etapa ela falha e a possível razão para isso.
Quando um cliente Ethereum executa uma transação, o estado global é atualizado, por exemplo:
- O saldo da conta vai mudar
- Algumas informações on-chain podem ser modificadas
- Novo contrato pode ser carregado
O rastreamento coleta os dados de retorno, alterações de estado e registros de execução de chamadas de transações. Pode ser uma chamada de contrato, uma transferência de fundos ou uma execução de bloco.
Figura 2: Dados de rastreamento coletados durante uma transação
O que é um estado?
Para que um nó possa reexecutar uma transação e obter os dados de rastreamento, todos os dados de estado antigos acessados pela transação devem estar disponíveis. Isso significa que as transações que podem ser rastreadas são limitadas pelo tipo de nó:
- Um nó de arquivo (archive node) retém todos os dados históricos a partir do bloco Gênesis. Portanto, pode rastrear transações arbitrárias em qualquer ponto da história da cadeia.
- Um nó completo (full node) mantém apenas os 128 estados de bloco mais recentes na memória. Os estados mais antigos são representados por uma sequência de snapshots a partir do bloco Gênesis. Os estados intermediários podem ser regenerados a partir dos snapshots, mas isso geralmente leva muito tempo para ser executado.
- Um nó sincronizado com snapshot (snapshot synced node) é como um nó completo, mas armazena snapshots a partir de sua sincronização inicial, em vez de começar do bloco Gênesis.
- Um nó leve (light node) não armazena dados históricos, apenas recupera dados conforme a necessidade de uso. Mesmo que, em teoria, possa regenerar estados históricos através de computação pesada; na prática, não podemos assumir a disponibilidade de seus dados.
Figura 3: Histórico da cadeia armazenado de acordo com o tipo de nó
Mais detalhes podem ser encontrados neste artigo.
debug_trace usando Geth & Erigon
Para o Geth, os métodos de rastreamento estão no espaço de nomes debug_
; para o Erigon, os métodos de rastreamento estão nos espaços de nomes debug_
e trace_
. Neste artigo, discutiremos os métodos de rastreamento do Geth e do Erigon.
Métodos de rastreamento comuns disponíveis tanto no Geth quanto no Erigon:
- debug_traceCall
- debug_traceTransaction
- debug_traceBlockByNumber
- debug_traceBlockByHash
4 métodos únicos disponíveis no Geth:
- debug_traceBlock
- debug_traceBlockFromFile
- debug_traceBadBlock
- debug_traceChain
9 métodos únicos disponíveis no Erigon:
- debug_traceCallMany
- trace_call
- trace_callMany
- trace_replayBlockTransactions
- trace_replayTransaction
- trace_block
- trace_filter
- trace_get
- trace_transaction
Experimente com a Chainstack
Todas as amostras de código mencionadas adiante foram desenvolvidas e testadas com um ponto de extremidade da Chainstack – é altamente recomendado usá-lo pelas seguintes razões:
- 3 milhões de solicitações gratuitas
- Suporta tanto Erigon quanto Geth
- Implantação de nó perfeita
Basta seguir estas etapas para implantar um nó:
- Inscreva-se na Chainstack
- Faça a implantação de um nó Ethereum
- Obtenha o ponto de extremidade do nó implantado
Você pode verificar o tipo de seu nó na página do projeto. A opção padrão é Geth.
Figura 4: Local de exibição do tipo de nó da plataforma Chainstack
O Erigon está disponível apenas em um nó de arquivo a partir do plano de negócios. Para implantar um nó Erigon, basta ligar a opção de APIs de depuração e rastreamento quando você implantar um nó.
Figura 5: Local das configurações das APIs de depuração e rastreamento da plataforma Chainstack
Mergulho profundo em métodos de rastreamento
Métodos debug_trace disponíveis tanto no Geth quanto no Erigon
debug_traceCall
Este método executa um eth_call com rastreamento ativado.
{"method": "debug_traceCall", "params": [callObject, blockNumberOrHash, traceOption]}
Os dois primeiros parâmetros são exatamente os mesmos que eth_call
. Este é um exemplo básico de transferência de fundos de traceCall
:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceCall","params":[{"from":"0x1111111111111111111111111111111111111111","to":"0x2222222222222222222222222222222222222222","gas":"0x493E0","gasPrice":"0x37E11D600","value":"0xF"},"latest"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
Isso retorna um registro vazio, pois não há nenhuma operação real envolvida.
Este é um exemplo básico de chamada de rastreamento de contrato de gravação:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceCall","params":[{"from":"0xe7e8569267c4a3278be75a2d86fd1a9e0a6818d8","to":"0xc2edad668740f1aa35e4d8f227fb8e17dca888cd","gas":"0x1E9EF","gasPrice":"0x2C2F7FD5E","data":"0x441a3e70000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000000000000000000000c6c3eca729cb9e"},"latest"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
O método de rastreamento no módulo de depuração suporta várias opções de rastreamento, que oferecem grande flexibilidade sobre quais tipos de dados coletar:
-
disableStorage
: BOOL. Definir isso como verdadeiro desabilitará a captura de armazenamento (padrão = falso). -
disableStack
: BOOL. Definir isso como verdadeiro desabilitará a captura de pilha (padrão = falso). -
enableMemory
: BOOL. Definir isso como verdadeiro habilitará a captura de memória (padrão = falso). -
enableReturnData
: BOOL. Definir isso como verdadeiro habilitará a captura de dados de retorno (padrão = falso). -
tracer
: STRING. Nome para o rastreador embutido ou expressão JavaScript. Veja abaixo para mais detalhes. Se definido, os quatro argumentos anteriores serão ignorados. -
timeout
: STRING. Substitui o tempo limite padrão de 5 segundos para chamadas de rastreamento baseadas em JavaScript.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceCall","params":[{"from":"0xe7e8569267c4a3278be75a2d86fd1a9e0a6818d8","to":"0xc2edad668740f1aa35e4d8f227fb8e17dca888cd","gas":"0x1E9EF","gasPrice":"0x2C2F7FD5E","data":"0x441a3e70000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000000000000000000000c6c3eca729cb9e"},"latest",{"disableStorage": true, "disableStack":true,"enableMemory": false,"enableReturnData":false}],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
Por favor, observe que o Erigon tem uma configuração um pouco diferente.
Geth | Erigon |
enableMemory: false | disableMemory:true |
enableReturnData:false | disableReturnData:true |
Tabela 1. Opção de rastreamento do Geth vs Erigon
Você pode substituir os dados de um bloco ou dados de estado especificando blockoverrides
(número, timestamp) ou stateOverride
(saldo, nonce). Observe a diferença na letra maiúscula "O", isso não é um erro de digitação. Pode ser corrigido em desenvolvimentos futuros.
Abaixo está um exemplo de substituição de estado para uma transação de transferência de fundos:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceCall","params":[{"from":"0x1111111111111111111111111111111111111111","to":"0x2222222222222222222222222222222222222222","gas":"0x493E0","gasPrice":"0x37E11D600","value":"0xFFFFFFFFFFFF"},"latest",{"stateOverrides":{"0x1111111111111111111111111111111111111111":{"balance":"0xFFFFFFFFFFFFFF"}}}],"id":1}' ' https:// nd-123-456-789.p2pify.com/ABCDabcd
debug_traceTransaction
Assim como o debug_traceCall
rastreia uma chamada, este método reexecuta uma transação específica identificada com o hash da transação. Rastrear uma única transação também requer a reexecução de todas as transações precedentes no mesmo bloco. Portanto, o estado histórico deve estar disponível.
Chamada de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0x09d2acb16d30e2017813b532392d0749e871c6ac3b8759424b2923c953928172"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
Assim como debug_traceCall
, este método suporta opções de rastreamento e substituição.
debug_traceBlockByNumber
Quando você rastreia um bloco, está basicamente rastreando todas as transações de um bloco em sequência. Você pode especificá-lo com o número do bloco ou uma tag como latest
.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceBlockByNumber","params":["latest"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
As substituições de estado e de bloco também são suportadas:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceBlockByNumber","params":["latest",{"stateOverrides":{"0x1111111111111111111111111111111111111111":{"balance":"0xFFFFFFFFFFFFFF"}},"blockoverrides":{"number":"0x50"},"disableStorage": true, "disableStack":true,"disableMemory": true,"disableReturnData":true}],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
debug_traceBlockByHash
Este método é como debug_traceBlockByNumber
, mas usa o hash de um bloco em vez do número do bloco.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceBlockByHash","params":["0x77419be3c23ba236fb940d13f15a2ae26d1ec45e6bdb8c11822cde8bc75a6e94"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
Métodos debug_trace únicos do Geth
debug_traceBlock
O método traceBlock
retornará um rastreamento completo de todos os opcodes invocados de todas as transações que foram incluídas em um bloco. As transações são executadas em sequência.
Para usar traceBlock
, duas condições devem ser cumpridas:
- O estado pai do bloco deve ser apresentado
- O RLP do bloco é necessário
Um RLP é um dado serializado de um bloco. Ele pode ser obtido usando o método debug_getBlockRlp.
Para usar debug_traceBlock
com o último bloco, primeiramente você pode usar eth_getBlockByNumber
para obter o número do bloco.
{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest", false],"id":1}
Por favor, observe que o número do bloco obtido aqui está em formato hexadecimal e você precisa convertê-lo para um inteiro para o próximo passo:
{"jsonrpc":"2.0","method":"debug_getBlockRlp","params":[123456],"id":1}
Um exemplo de RLP seria:
Figura 6: Exemplo de saída RLP
Cole os dados RLP em debug_traceBlock
e execute. Assim como outros métodos de rastreamento, ele suporta várias opções de rastreamento.
{"method": "debug_traceBlock", "params": [TheBlockRLP, traceOption]}
debug_traceBlockFromFile
Semelhante ao debug_traceBlock
, o traceBlockFromFile
aceita um arquivo que existe no nó e contém os dados RLP de um bloco.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceBlockFromFile","params":["blockRLP.txt",{}],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
debug_traceBadBlock
Quando o Geth falha ao executar um bloco, ele coloca o "bloco ruim" em um espaço reservado para investigação. Este método retorna os logs de rastreamento para o bloco ruim.
O hash do bloco precisa ser enviado com a solicitação. Para obter uma lista de blocos ruins, use: debug_getBadBlocks.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_ traceBadBlock ","params":[blockHash,{}],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
debug_traceChain
Uma cadeia é composta por vários blocos consecutivos. Este método irá reexecutar cada bloco em uma cadeia e retornar as informações de rastreamento.
Este método retorna os logs estruturados criados durante a execução da EVM (Máquina Virtual Ethereum) entre dois blocos (excluindo o início) como um objeto JSON. Este ponto de extremidade deve ser invocado via
debug_subscribe
da seguinte forma:
const res = provider.send('debug_subscribe', ['traceChain', '0x3f3a2a', '0x3f3a2b'])
Exemplo de debug_traceChain
Um exemplo de uso com wscat:
Figura 9: Exemplo de saída debug_traceChain com wscat
Métodos debug_trace únicos do Erigon
A API de rastreamento do Erigon é equivalente ao módulo de rastreamento do openEthereum. Ela não suporta opções de rastreamento e substituições de estado, ao invés disso, ela suporta 3 modos de rastreamento diferentes.
trace
: Rastreamento da transação. Um rastreamento equivalente ao da seção anterior.
vmTrace
: Rastreamento da execução da Máquina Virtual. Fornece um rastreamento completo do estado da máquina virtual durante a execução da transação, incluindo para qualquer sub-chamada.
stateDiff
: Diferença de estado. Fornece informações detalhando todas as partes alteradas do estado Ethereum devido à execução da transação.
Os dados retornados das APIs do módulo de rastreamento são em geral mais limpos e melhor estruturados. Portanto, mais fáceis de interpretar.
O modo trace
rastreia os resultados da operação de todas as transações internas para uma chamada: o uso de gás, dados de entrada e o resultado da execução.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_call","params":[{"from":"0xe7e8569267c4a3278be75a2d86fd1a9e0a6818d8","to":"0xc2edad668740f1aa35e4d8f227fb8e17dca888cd","gas":"0x1E9EF","gasPrice":"0x2C2F7FD5E","data":"0x441a3e70000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000000000000000000000c6c3eca729cb9e"},["trace"],"0xF52578"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
Saída de exemplo:
Figura 9: Exemplo de saída de operação de rastreamento de transação interna do Erigon
O modo vmTrace
rastreia o estado da máquina virtual durante a transação.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_call","params":[{"from":"0xe7e8569267c4a3278be75a2d86fd1a9e0a6818d8","to":"0xc2edad668740f1aa35e4d8f227fb8e17dca888cd","gas":"0x1E9EF","gasPrice":"0x2C2F7FD5E","data":"0x441a3e70000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000000000000000000000c6c3eca729cb9e"},["vmTrace"],"0xF52578"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
Saída de exemplo:
Figura 10: Exemplo de saída da operação vmTrace
O modo stateDiff
rastreia a diferença de estado entre cada transação interna. Por exemplo, mudanças no saldo das contas, seus dados de armazenamento, etc.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_call","params":[{"from":"0xe7e8569267c4a3278be75a2d86fd1a9e0a6818d8","to":"0xc2edad668740f1aa35e4d8f227fb8e17dca888cd","gas":"0x1E9EF","gasPrice":"0x2C2F7FD5E","data":"0x441a3e70000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000000000000000000000c6c3eca729cb9e"},["stateDiff"],"0xF52578"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
Saída de exemplo:
Figura 11: Exemplo de saída da operação stateDiff
trace_call
Este é um método espelho do debug_traceCall
.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_call","params":[{"from":"0xe7e8569267c4a3278be75a2d86fd1a9e0a6818d8","to":"0xc2edad668740f1aa35e4d8f227fb8e17dca888cd","gas":"0x1E9EF","gasPrice":"0x2C2F7FD5E","data":"0x441a3e70000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000000000000000000000c6c3eca729cb9e"},["trace"],"0xF52578"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
trace_callMany
Este é um método útil que não existe no Geth. Este método permite ao usuário enviar várias transações em um lote para supervisionar as execuções. Essas transações são executadas em sequência, cada transação depende do estado resultante das transações anteriores. Os parâmetros:
A estrutura do parâmetro:
Figura 12: Exemplo de parâmetros do trace_callMany
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_callMany","params":[[[{"from":"0x1111111111111111111111111111111111111111","to":"0x2222222222222222222222222222222222222222","gas":"0x493E0","gasPrice":"0x37E11D600","value":"0xF"},["stateDiff"]],[{"from":"0x1111111111111111111111111111111111111111","to":"0x2222222222222222222222222222222222222222","gas":"0x493E0","gasPrice":"0x37E11D600","value":"0xF"},["stateDiff"]],[{"from":"0x1111111111111111111111111111111111111111","to":"0x2222222222222222222222222222222222222222","gas":"0x493E0","gasPrice":"0x37E11D600","value":"0xF"},["stateDiff"]]],"latest"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
trace_replayBlockTransactions
Este é um método espelho do debug_traceBlockByNumber
.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_replayBlockTransactions","params":["0x2ed119",["stateDiff"]],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
trace_replayTransaction
Este é um método espelho do debug_traceTransaction
.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_replayTransaction","params":["0x09d2acb16d30e2017813b532392d0749e871c6ac3b8759424b2923c953928172",["stateDiff"]],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
trace_block
Em vez de reexecutar um bloco como debug_traceBlockByNumber
e trace_replayBlockTransactions
, este método retorna os dados de rastreamento reais coletados durante a execução do bloco.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_block","params":["0x2ed119"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
trace_transaction
Em vez de reexecutar uma transação como debug_traceTransaction
e trace_replayTransaction
, este método retorna os dados de rastreamento reais para a execução da transação.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_transaction","params":["0x09d2acb16d30e2017813b532392d0749e871c6ac3b8759424b2923c953928172"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
trace_filter
Este método retorna os rastreamentos que correspondem ao filtro dado.
-
Object
- O objeto filtro-
fromBlock
:Quantity
ouTag
- (opcional) A partir deste bloco. -
toBlock
:Quantity
ouTag
- (opcional) Para este bloco. -
fromAddress
:Array
- (opcional) Enviado destes endereços. -
toAddress
:Address
- (opcional) Enviado para estes endereços. -
after
:Quantity
- (opcional) O número de rastreamento deslocado -
count
:Quantity
- (opcional) Número inteiro de rastreamentos para exibir em um lote.
-
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_filter","params":[{"fromBlock": "0x2ed0c4","toBlock": "0x2ed128","toAddress": ["0x8bbB73BCB5d553B5A556358d27625323Fd781D37"]}],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
trace_get
Esta chamada retorna o rastreamento específico de uma transação.
-
Hash
- Hash da transação. -
Array
- Posições de índice dos rastreamentos.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"trace_get","params":["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3",["0x0",]],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
debug_traceCallMany
Este é um método espelho do trace_callMany
exposto em um módulo de depuração.
Código de exemplo:
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"debug_traceCallMany","params":[[[{"from":"0x1111111111111111111111111111111111111111","to":"0x2222222222222222222222222222222222222222","gas":"0x493E0","gasPrice":"0x37E11D600","value":"0xF"},["stateDiff"]],[{"from":"0x1111111111111111111111111111111111111111","to":"0x2222222222222222222222222222222222222222","gas":"0x493E0","gasPrice":"0x37E11D600","value":"0xF"},["stateDiff"]],[{"from":"0x1111111111111111111111111111111111111111","to":"0x2222222222222222222222222222222222222222","gas":"0x493E0","gasPrice":"0x37E11D600","value":"0xF"},["stateDiff"]]],"latest"],"id":1}' https:// nd-123-456-789.p2pify.com/ABCDabcd
Conclusão
Este é o fim deste tutorial. Espero que você o ache útil. Obrigado por ler.
Se você tiver alguma dúvida, sinta-se à vontade para me chamar no Twitter/Telegram/Discord.
Boa programação.
Até mais!
Artigo original publicado por Wuzhong Zhu. Traduzido por Paulinho Giovannini.
Latest comments (0)