Uma declaração de evento em Solidity define um formato nomeado para registrar argumentos. Já um log é um registro específico produzido pelo mecanismo de logs da Máquina Virtual Ethereum, a EVM. Entender a diferença entre logs e eventos no Ethereum exige separar a definição de uma ocorrência registrada e, depois, distinguir os bytes do registro da interpretação atribuída a eles.
Essa distinção ajuda quando um explorador mostra um nome de evento ao lado de tópicos e dados em hexadecimal. O nome, os campos decodificados e o registro bruto respondem a perguntas diferentes. A apresentação legível é útil, mas sua interpretação depende do esquema do evento e do contexto correspondente.
1. A declaração do evento define o formato
Os eventos de Solidity oferecem uma abstração sobre o mecanismo de logs da EVM. A emissão de um evento registra seus argumentos na estrutura de logs da transação. Uma declaração descreve o que pode ser emitido; sozinha, não demonstra que determinada emissão aconteceu. A documentação de contratos do Solidity explica essa relação e as informações necessárias para interpretar os dados de eventos.
Por exemplo, uma declaração pode dar a um evento o nome Reading e especificar dois argumentos inteiros sem sinal. Isso estabelece um formato no programa hipotético. Para analisar uma ocorrência, seria necessário identificar um registro emitido específico.
Ao ler um trecho de código, portanto, pergunte se ele apenas declara o evento ou se há também evidência de uma emissão. Encontrar a definição não substitui encontrar o registro.
2. Leia emissor, tópicos e dados separadamente
Três partes organizam o registro:
- Emissor: o campo
addressdo log identifica o endereço de onde ele se originou. - Tópicos: o campo
topicscontém de zero a quatro entradas, cada uma com 32 bytes. - Dados: na codificação de eventos do Solidity, o campo
datacontém os argumentos não indexados, codificados segundo a ABI.
O endereço do emissor responde a uma pergunta sobre origem. Sua presença, por si só, não identifica o remetente da transação nem um destinatário econômico. Atribuir esses papéis exige contexto adicional.
A documentação JSON-RPC do Ethereum define esses campos e apresenta um exemplo de log gerado pela EVM e incluído no recibo de uma transação. O exemplo mostra onde um log pode aparecer; não estabelece que toda transação produza um. O recibo reúne informações sobre a transação, enquanto o log é o item específico interpretado aqui.
Para entender o software que fornece informações por RPC, consulte o guia sobre nós e clientes Ethereum. Identificar a origem de uma resposta também ajuda a manter explícito o contexto dos dados analisados.
3. Os tópicos seguem as regras de codificação do evento
Em um evento não anônimo que segue a convenção da ABI do Solidity, topics[0] contém o hash Keccak do nome do evento e da lista de tipos canônicos de seus parâmetros. Para um evento chamado Reading com dois parâmetros uint256, o texto dessa assinatura é Reading(uint256,uint256). Os nomes dos parâmetros e o marcador indexed ficam fora dessa fórmula.
Eventos anônimos omitem o tópico de assinatura. Por isso, antes de tratar o primeiro tópico como identificador do evento, é preciso estabelecer qual convenção se aplica.
Um argumento uint256 indexado é representado diretamente em seu tópico como um valor ABI de 32 bytes. Essa regra não deve ser estendida a todos os tipos. Arrays indexados, inclusive os de tamanho fixo, além de strings, bytes dinâmicos e structs, usam um hash Keccak de uma codificação especial, em vez do valor codificado diretamente. Nesse contexto, bytes dinâmicos e tipos de bytes de tamanho fixo não são intercambiáveis.
Como explica a especificação da ABI do Solidity, essa representação por hash permite procurar valores candidatos conhecidos, mas não permite decodificar um valor original desconhecido apenas a partir daquele tópico. Informações obtidas separadamente podem ajudar; nesse caso, constituem evidência adicional.
4. A ABI fornece o contexto para decodificar
A decodificação correta exige conhecer os tipos do evento, quais parâmetros são indexados e se ele é anônimo. Uma ABI, ou um esquema equivalente do evento, fornece esse contexto. O log bruto não armazena uma descrição completa do tipo do evento junto com seus valores.
Isso importa mesmo quando uma ferramenta exibe nomes de campos plausíveis. O esquema fornecido orienta a interpretação dos bytes. Da distinção entre dados registrados e informações de tipo fornecidas externamente decorre uma dedução: conseguir decodificar os bytes sob determinado esquema não verifica, de forma independente, que esse esquema corresponde ao registro analisado.
Há outro limite para a comparação de assinaturas: a documentação do Solidity informa que um evento anônimo pode imitar o tópico de assinatura de outro evento. Portanto, um tópico correspondente, isoladamente, não autentica a declaração presumida. Isso não significa que o endereço emissor tenha sido falsificado dessa forma; origem e interpretação dos tópicos continuam sendo questões separadas.
5. Um registro Reading hipotético, interpretado com cuidado
Exemplo hipotético: suponha que um contrato inventado emita um evento não anônimo declarado como event Reading(uint256 indexed sensor, uint256 value);, com os argumentos (7, 42). Suponha também que o registro siga a codificação ABI dessa declaração. Trata-se de uma situação didática, não de uma transação observada.
Com essas premissas e as regras documentadas de codificação, a interpretação seria:
addressidentifica o endereço do contrato emissor estipulado, que o exemplo deixa sem especificar.topics[0]contém o hash Keccak deReading(uint256,uint256).topics[1]codifica o argumento indexadosensorcomo o inteiro sem sinal 7.datacodifica o único argumento não indexado,value, como o inteiro sem sinal 42.
As duas últimas posições são deduções da declaração estipulada: a assinatura ocupa o primeiro tópico, o argumento indexado ocupa o seguinte e o argumento não indexado fica em data.
Na ABI padrão, inteiros sem sinal usam a ordem de bytes big-endian e recebem bytes zero à esquerda até completar 32 bytes. Assim, a palavra do sensor hipotético termina em 07, e a palavra de dados termina em 2a, representação hexadecimal de 42. Os bytes anteriores de cada palavra são zeros.
O que o número 42 demonstra?
Sob o esquema assumido, ele demonstra o valor do argumento decodificado. Nenhuma unidade física, unidade monetária ou operação de pagamento foi estipulada. Logo, deduz-se que esse registro hipotético, sozinho, não comprova que ocorreu um pagamento de 42.
Esse limite não significa que logs nunca possam contribuir como evidência de atividade econômica. Uma interpretação mais forte exigiria informações sobre o comportamento relevante do contrato e o contexto de execução. Neste exercício, decodificar o argumento e comprovar um resultado econômico são etapas distintas de análise.
6. Checklist prático para ler um log
- Separe definição e ocorrência. Você está olhando uma declaração de evento ou um registro emitido específico?
- Identifique o emissor. Leia o endereço do log como sua origem, sem atribuir automaticamente outros papéis aos participantes.
- Estabeleça o esquema. Identifique os tipos dos argumentos, as posições indexadas e se o evento é anônimo.
- Confira a interpretação dos tópicos. Determine se deve existir um tópico de assinatura e se os demais tópicos contêm valores diretos ou hashes.
- Decodifique com premissas explícitas. Mantenha os bytes brutos distinguíveis dos nomes e valores derivados do esquema.
- Limite a conclusão. Registre o que as evidências demonstram e deixe sem conclusão as unidades e os resultados não estabelecidos.
Essas verificações podem ser feitas como exercício de leitura com documentação e registros de exemplo. A atribuição de fontes sustenta a explicação técnica; não certifica a segurança de um contrato específico nem comprova um resultado econômico.
Material educativo preparado com auxílio de IA. Explica a interpretação de registros e não recomenda transações ou assinaturas com carteira.