The block array
A Data Feed delivers one row per block. Most onchain activity is exposed as typed arrays on that row
(tokenSwaps, tokenTransfers, …), but the raw block header, transactions, logs, withdrawals, and access
lists all arrive together in a single flattened array called block.
If you’re coming from the REST API, where GET /{address}/logs hands you ready-made log objects, this is the
biggest shape change to understand.
One array, many row types
Every element ofblock has the same wide shape: all the block*, transaction*, log*, and
withdrawal* columns exist on every element. A discriminator column, itemType, tells you what each
element actually is; only the columns matching that itemType are populated, the rest are null.
itemType is one of: block, transaction, log, withdrawal, accessList.
So for a block with 110 transactions, each emitting 4 logs, the block array contains roughly:
≈ 551 elements in that one block row (plus any
withdrawal / accessList rows).
⚠️ Log rows don’t carry the transaction hash
This is the detail that trips people up. Alog element has its transactionIndex and logIndex, the
emitting logAddress, the four topics, and the raw logData, but no transactionHash.
To attach the hash, join each log to its sibling transaction element on transactionIndex:
itemType = 'transaction' AND transactionIndex = N→ the tx hash + metadataitemType = 'log' AND transactionIndex = N→ that transaction’s logs
blockNumber, timestamp, blockHash) comes from the top-level row (position,
timestamp, hash), not from the log element.
Worked example, two transactions, four logs each
Top-level row for the block:position = 21000000, hash = "0xblk…", timestamp = 1718800000.
Below is an excerpt of its block array showing transactions #5 and #6 with their logs. Only populated
columns are shown; everything else on each element is null.
Reading it
- Get a transaction with its logs: filter
itemType='transaction'for the hash/metadata anditemType='log'for the events, both on the sametransactionIndex, then join ontransactionIndex. - On-chain order of a log is
(blockNumber, transactionIndex, logIndex), don’t rely on physical array position; use the index columns (orsequenceIndexfor the raw interleaving). - Topics are flat columns.
topic0(the event signature hash) is always present;topic1..topic3arenullwhen the event has fewer topics. Re-assemble atopics[]array if your downstream expects one. - No decoding.
logData+ topics are raw hex, the event name and parameters are yours to decode from the contract ABI. (The REST API’s decoded/“verbose” responses do this for you; on a raw feed it’s a derive-yourself step.)
ThelogsByContractandlogsByTopic0recipes do exactly this filtering+join for you and write a flat one-row-per-log table, a drop-in forGET /{address}/logs.

