GOMTU Crypto
guidePart 23 of 41 in this guide

Ethereum Event Logs Explained: Topics, Data, and eth_getLogs

Learn how Ethereum event logs work, how indexed topics differ from data, how to query eth_getLogs, and what reorgs and decoding can break.

GOMTU
GOMTU
Crypto Research · August 20, 2026 · 8 min read
Share𝕏in

Last updated

A token moves, a swap completes, or a governance vote is cast—and a block explorer shows a neat activity row almost immediately. That readable history is often built from event logs, not by repeatedly scanning every contract variable. Logs connect blockchain basics to the interfaces, alerts, and analytics people use every day. The catch is that a log is evidence emitted by contract code, not an independent guarantee that its label or interpretation is correct.

This guide explains how Solidity events become Ethereum logs, how topics and data are encoded, how eth_getLogs filters them, and what developers and users should verify around decoding and chain reorganizations.

What Ethereum event logs are

Advertisement

Think of a smart contract as a kitchen and an event log as a numbered order slip pinned to the pass. The kitchen changes the actual inventory—that is contract state—while the slip gives outside systems a compact record they can watch and sort. A frontend can refresh a balance, an indexer can build token history, and a monitoring service can raise an alert when a safety-critical action occurs.

In Solidity, a contract declares an event and uses emit while a transaction executes. If the transaction succeeds and is included in a block, its receipt can contain the resulting log entries. Each entry identifies the emitting contract and carries topics plus a data byte string. Logs are cheaper and easier for offchain software to search than storing every reporting field as contract state, but contracts cannot read past logs—even the contract that emitted them cannot retrieve them later.

If execution reverts, the state changes and emitted logs from that reverted execution do not survive. That makes logs part of the transaction result, not a separate message channel that escapes a failed transaction.

How events become topics and data

Consider the familiar ERC-20 shape:

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

A non-anonymous event normally produces this layout:

address: contract that emitted the log
topics[0]: keccak256("Transfer(address,address,uint256)")
topics[1]: indexed from address, encoded as 32 bytes
topics[2]: indexed to address, encoded as 32 bytes
data: ABI-encoded uint256 value

topics[0] is the event selector: the Keccak-256 hash of the canonical event signature. It lets software distinguish Transfer from another event emitted by the same contract. Solidity permits up to three indexed parameters on a regular event because the signature occupies one of the four topic slots. An anonymous event omits that signature topic and can index up to four parameters, but it cannot be filtered by event name in the usual way.

Indexed parameters are designed for search. Non-indexed parameters are Application Binary Interface (ABI)-encoded together in data. For dynamic indexed values such as strings or arrays, the topic contains a hash of a special encoding rather than the original value. You can filter for a known value by hashing it correctly, but you cannot recover an unknown original string from its hash.

Events and calldata answer different questions

Ethereum calldata describes what a transaction asked a contract to do. Event logs describe what the executed contract chose to announce. One transaction may call several contracts and emit several logs. Conversely, a contract may change state without emitting the event an interface expects. To understand a transaction fully, compare input, receipt status, logs, and relevant state changes rather than treating any one field as the whole story.

How to read a transaction receipt

The JSON-RPC method eth_getTransactionReceipt returns null while no receipt is available. For an included transaction, the receipt includes fields such as block hash, block number, status, gas used, and a logs array.

A log object commonly includes:

  • address: the contract that executed the logging opcode
  • topics: the ordered list used for event identity and indexed values
  • data: ABI-encoded non-indexed values
  • blockHash and blockNumber: where the log was included
  • transactionHash and transactionIndex: which transaction produced it
  • logIndex: its position among logs in the block
  • removed: whether a previously delivered log was removed by a chain reorganization

First check the receipt status. A successful status confirms that EVM execution did not revert; it does not prove that the contract was safe or that a human-readable explorer label is authentic. Then verify the emitting address and obtain the correct ABI for that exact contract and network. Proxy systems may require the implementation ABI even though the proxy address appears in the log.

How eth_getLogs filtering works

eth_getLogs asks an Ethereum node for logs matching a filter object. The main filters are a block range, one or more contract addresses, and topic positions.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_getLogs",
  "params": [
    {
      "fromBlock": "0x1200000",
      "toBlock": "latest",
      "address": "0xContractAddress",
      "topics": ["0xEventSignatureHash", null, "0xPaddedIndexedAddress"]
    }
  ]
}

Topic order matters. In the example, position zero selects the event signature, null accepts any first indexed value, and position two constrains the second indexed value. According to the Ethereum JSON-RPC specification, a nested array at one position expresses an OR condition, while different positions are combined as AND conditions.

Use bounded block ranges and persist a checkpoint rather than repeatedly querying from genesis. RPC providers can impose range, response-size, or rate limits even though those operational limits are not Ethereum consensus rules. EIP-234 also standardized filtering by blockHash as an alternative to fromBlock and toBlock, which is useful when an application needs results tied to one specific block.

A reliable indexing workflow

1. Fix the identity inputs

Record the chain ID, emitting address, ABI version, and deployment block. The same bytecode interface or address-shaped string on another network is different context.

2. Compute and verify the signature

Build the canonical event signature with exact parameter types, then compute its Keccak-256 hash. Names of parameters and the indexed keyword are not part of that signature string. Do not copy a topic from an untrusted post when you can derive it from verified source.

3. Query in deterministic chunks

Fetch a bounded range, decode it, save the last processed block and hash, then continue. Idempotent storage—such as a unique key based on chain, block hash, transaction hash, and log index—helps retries avoid duplicate business actions.

4. Wait for the confidence your use case needs

A recently proposed block can be replaced. A user interface may show a provisional update quickly, while settlement-sensitive accounting should use an explicit confirmation or finality policy. The blockchain finality guide explains why “seen” and “irreversible” are different claims.

5. Roll back on reorganizations

Subscriptions may deliver a log with removed: true after a reorganization. Polling systems should also compare stored block hashes with the canonical chain. Reverse derived records from the displaced block, then process the replacement chain. A database that only appends can silently preserve events that are no longer canonical.

Risks and limitations

A log can be truthful but misleading

The log accurately records bytes emitted by an address. The event name and field labels come from an ABI supplied by an explorer, application, or developer. A malicious contract can emit an event shaped like a familiar token event without implementing the expected asset behavior. Verify the address, code, and state—not just the label.

Missing events are not proof that nothing happened

Events are conventions chosen by contract authors. A state transition may omit a log, use a nonstandard event, or emit through a path your indexer does not cover. Logs are excellent integration surfaces, but they are not a universal audit trail for every EVM effect.

Hashing a string into a topic makes exact-match filtering possible but removes direct decoding. Solidity recommends designs that include both an indexed hash and a non-indexed plain value when applications need searchability and legibility, at the cost of additional log data.

Reorgs and provider behavior affect delivery

The same event can appear provisionally, disappear, and reappear in another block. WebSocket disconnections and provider limits can also create gaps. Production consumers need backfills, checkpoints, deduplication, and reorg handling instead of assuming a subscription is exactly-once delivery.

Warning

Never authorize a transfer or credit funds solely because a decoded event appeared. Confirm the chain, canonical block, receipt status, emitting contract, required confirmations, and resulting state.

Practical checklist

  • Confirm chain ID and emitting contract address
  • Use an ABI tied to verified source and the correct proxy implementation
  • Recompute the canonical event signature and topics[0]
  • Decode indexed and non-indexed fields with their declared types
  • Check receipt status and block identity
  • Query bounded ranges and save block-number-plus-hash checkpoints
  • Deduplicate retries and handle removed logs or hash mismatches
  • Apply a confirmation or finality policy appropriate to the consequence
  • Reconcile important claims against contract state

FAQ

Are Ethereum events stored in contract storage?

No. Logs are included in transaction receipts and committed through the block structure, but they are not contract storage. Contracts cannot query historical logs during execution; offchain clients and indexers do that work.

Why can I filter an indexed address but not decode an indexed string?

An address fits in one 32-byte topic word and is padded. A dynamic value is represented by a Keccak-256 hash of its encoding, so an indexer can test a known candidate but cannot reverse the hash to discover the original value.

Is topics[0] always the event signature?

It is for ordinary Solidity events. Anonymous events omit the signature topic, so every topic may represent an indexed argument. The ABI is required to interpret the layout correctly.

Is a successful receipt enough to trust a token transfer?

No. Success means execution did not revert. It does not authenticate token metadata, prove economic value, or guarantee a familiar-looking event came from the intended contract.

Primary sources

Treat logs as structured evidence

Ethereum event logs are a compact bridge between contract execution and offchain software. Their topics make selected fields searchable, their data carries ABI-encoded detail, and JSON-RPC makes both available to interfaces and indexers. Reliable systems still verify identity, decode with the correct ABI, track canonical blocks, and reconcile high-consequence claims against state.

This article is educational and not financial advice. Onchain applications and assets can fail or lose value. Verify current primary documentation, test with amounts you can afford to lose, and do your own research (DYOR).

Advertisement

Keep learning

Explore related topics

More from GOMTU