What a seizure-warrant trace reveals about blockchain evidence
· 13 min read
A transaction hash is where most investigations start and where too many stop. The hash identifies the envelope: the signed message broadcast to the network, containing the sender, the recipient, the value, and the input data. It does not say whether execution succeeded, which contracts actually ran, or what assets moved. Those facts live in other artifacts: the receipt, the event logs, the call tree, and the execution trace. Each answers a different question and each carries different evidentiary weight. Explorer pages fuse these layers into one screen, which is exactly why lawyers overstate what a hash proves. For the fundamentals of reading a single transaction, start with the basic guide.
The hash is a cryptographic fingerprint of the signed transaction, computed from the transaction data at signing time. Retrieving the transaction object through eth_getTransactionByHash, a method in the execution-apis JSON-RPC collection, returns the envelope: from, to, value, input data, nonce, gas parameters, fee fields, block number, and index. The from address is derived from the cryptographic signature, so the envelope establishes which account signed the message, not which person held that account.
If to is a contract address, the input field is an encoded function call, and the envelope alone does not reveal what that function did, whether it succeeded, or whether any token changed hands. The value field carries only native ETH and only the top-level amount: a 5,000 USDC transfer typically appears with a value of zero. Confirm finality before treating a mined hash as settled: a transaction in a block reorganized out of the canonical chain can disappear from the record.
Unlike a trace, a receipt is consensus data. Blocks commit a receipts root, and a node that still holds the relevant history can serve the receipt via eth_getTransactionReceipt. The execution-apis receipt schema requires status (after Byzantium), gasUsed, cumulativeGasUsed, logs, and effectiveGasPrice, the amount actually deducted per gas. Some clients prune old receipts and return a "pruned history unavailable" error, so confirm the node still holds the block before treating a missing receipt as proof that the transaction never existed.
Status semantics come from EIP-658, which replaced the receipt's intermediate state root with a status code: 1 for success, 0 for failure. The change activated with the Byzantium hard fork at block 4,370,000 on October 16, 2017. Transactions before that fork have no status field, and failure was inferred by comparing gasUsed against the gas limit. EIP-658's own motivation explains why that heuristic became unsound: with the REVERT opcode, "it is no longer possible for users to assume that a transaction failed iff it consumed all gas." For pre-Byzantium transactions, the outcome can only be reconstructed by replaying execution.
A status of 0 means the top-level call failed and every state change rolled back. The transaction is still recorded, its nonce is consumed, and the sender pays for gas actually used. After Byzantium that is often well below the gas limit: EIP-140 added REVERT so a contract can "stop execution and revert state changes, without consuming all provided gas." Solidity require and revert use that opcode. Exceptional failures such as out-of-gas still consume remaining gas. gasUsed multiplied by effectiveGasPrice (or gasPrice where that is the legacy price) is the fee figure, usable for damages even when the transfer failed. Success means only that the call did not revert, so no asset conclusion should rest on the status field alone.
Logs are stored inside the receipt and emitted by contract code during execution. Each log carries the emitting contract address, up to four indexed topics, and a data payload, and history can be queried with eth_getLogs, filtered by address and topic signature. The "token transfers" panels on explorers are decodes of these logs, not independent data.
The ERC-20 standard (EIP-20) requires a Transfer event on every transfer and transferFrom call, including zero-value transfers, and an Approval event on every successful approve. A token that creates new tokens SHOULD emit a Transfer with _from set to the zero address. Those conventions are why Transfer logs are the backbone of token-flow reconstruction.
The protocol does not enforce any of it. Events are emitted by whatever code the contract runs, and the EVM does not check whether an emitted Transfer corresponds to a real balance change. A noncompliant contract can emit a Transfer without moving a token, or move tokens while emitting nothing. EIP-140 notes that reverting an EVM execution means "all changes, including LOGs, are lost," so a failed transaction's receipt carries no logs, and an event from a failed subcall disappears even when the surrounding transaction succeeds. Fee-on-transfer and rebasing tokens can log an amount that differs from the balance delta. Treat logs as admissions by the contract, not ground truth. Corroborate with balanceOf at the relevant block via eth_call, check that an allowance was consumed, and confirm the flow against the call tree.
One envelope can fan out into many internal executions, and the shape of that tree is often the entire case. A contract that calls another executes the callee's code in the callee's context, with the caller as msg.sender. Delegatecall, the opcode added in the Homestead fork (EIP-7), inverts that: the callee's code runs in the caller's storage context, preserving msg.sender and msg.value. This is the mechanism behind upgradeable proxies, where a user calls a proxy address and the proxy delegatecalls an implementation contract. The forensic consequence is direct: the address that received the call is not necessarily the address whose code ran, and a plain transaction page will not tell you which is which.
Routers and aggregators add a third layer. A swap transaction shows to equal to a router address; the call tree shows the router calling pair contracts, which move tokens on their own ledgers. ETH that a contract forwards onward appears only in the trace, and ERC-20 movement appears only in the token contract's logs and ledger. Where holdings pass through several protocol contracts inside one transaction, tracing through DeFi mechanics is where that analysis gets its teeth, while smart contract disputes covers the contract interpretation and remedies side of the same record.
Retrieval is where standardization ends. Tracing RPCs are client-specific: geth exposes trace methods in its debug namespace and documents tracing as re-running transactions locally. EIP-3155 proposed a JSON format for EVM traces during state tests; it remains at Last Call and is not a finalized debug_traceTransaction standard. EIP-1474, which cataloged JSON-RPC methods, is stagnant; the maintained specification is the execution-apis repository. Because output depends on the client, its version, and the tracer, an expert's methodology documentation matters as much as the trace itself.
Traces are re-execution, not stored data. Reproducing what a transaction did requires the state that existed at that block.
A full node caches only recent state, on the order of the last 128 blocks, per ethereum.org's archive-node documentation and geth's tracing notes. Older states can be regenerated from checkpoints, which becomes expensive the further back you go. Geth's default reexec window is 128 blocks; beyond it, a trace fails unless the window is increased or the node is an archive node. An archive node stores historical states so those queries return immediately, at the cost of multiple terabytes of disk. Confirm archive-state access or provider tracing support before promising a trace of an old transaction, and record the node type, client version, sync mode, tracer, and block height.
Opcode-level traces can run to hundreds of megabytes for a busy transaction, which makes them impractical to attach wholesale; high-level call tracers are compact but capture a different layer. Execution is deterministic given the same client, state, and tracer, but different client versions can produce different output. Our methodology treats reproducibility and documented retrieval as core requirements of blockchain forensic work; for packaging this evidence for court, ConsensusIntel offers blockchain tracing and evidence review built around artifact-level preservation rather than explorer screenshots.
Hypothetical example: the addresses and amounts below are invented for illustration; no real matter is described.
A victim account (V) has an outstanding approve to an attacker-controlled contract (D) for 5,000 USDC. D was deployed with code that delegatecalls a reusable template (T). V signs a single transaction to D. The explorer shows "Method: transfer", "Status: Success", and a tokens-transferred panel reading "USDC 5,000 from V to A".
Layer 1, the envelope: from V, to D, value 0, a small input payload. V submitted a message to D; no ETH moved to D; there is no USDC in this artifact.
Layer 2, the receipt: status 1, gasUsed 94,220, and three logs: Transfer from V to D of 5,000 USDC, Transfer from D to A of 5,000 USDC, and RewardsClaimed for V. Execution succeeded, the sender paid for the gas, and the USDC contract recorded two transfers.
Layer 3, logs plus ledger state: balanceOf at the final block shows V's USDC fell by 5,000, D's rose and then fell, and A's rose by 5,000. The ledger corroborates the two Transfer logs. RewardsClaimed corresponds to no balance change: a fabricated reward event with no asset behind it.
Layer 4, the call tree: D delegatecalled T, so template code ran in D's storage with msg.sender still V. D then called USDC.transferFrom to pull the allowance, USDC.transfer to send on to A, and forwarded 0.02 ETH to A internally. The executing code was T's, running in D's context, and 0.02 ETH reached A inside a transaction whose value field says zero.
A careless report says "V transferred USDC to A." A defensible report stacks the layers: the envelope proves V signed to D; the ledger plus logs prove the USDC flow; the trace proves which code ran and where the ETH landed.
From the envelope alone: submission, sender account, recipient, payload, fee parameters, and block inclusion.
From the receipt: inclusion, success or failure, execution cost, and the set of logs emitted. Nothing about assets.
From logs plus ledger reads: token flows as recorded by the token contract, always subject to that contract's truthfulness about its own state.
From the call tree: which code executed, in whose storage context, in what order, and where ETH flowed internally.
From state at a block: balances, allowances, and storage as the network recorded them, the ground-truth layer for assets.
Below the line sit claims no artifact supports: who physically held the private key, what the sender intended, and anything that happened off-chain. Label every conclusion with its source layer. A report that lets a receipt's status carry the weight of a token movement, or a log carry the weight of a balance, has overstated the evidence.
eth_getTransactionByHash, eth_getTransactionReceipt, and eth_getLogs at query time; record the timestamp, the node or provider, the client and version, and the exact parameters.eth_call, and check that allowances were consumed.Traces and logs reconstruct execution, not people. They cannot prove who held a private key, what a party intended, or any off-chain fact. Explorer "internal transactions" tabs are client-generated renderings, not consensus data. Reorganizations can orphan a transaction, log queries can be range-limited, and some nodes prune old receipts. On layer-2 rollups, receipts describe sequencer-era execution and the layer-1 commitments are a separate artifact. Everything before October 2017 on Ethereum lacks a receipt status, and the absence of an event proves nothing. How a court weighs these artifacts depends on the forum's evidence rules.
A: No. Status proves only that the transaction did not revert. Token movement is evidenced by the token contract's Transfer logs and by balanceOf at the relevant block. The explorer's "transfer" label is a decode of the input data and says nothing about whether tokens moved.
A: A receipt is consensus data: status, gas used, and logs, stored with the block. A trace is a reconstruction: a node re-executes the transaction locally. Receipts exist for every included transaction the node still holds. Traces depend on the client, the tracer, and historical state, which generally means an archive node for old transactions. There is no finalized trace-format standard.
A: gasUsed multiplied by effectiveGasPrice is the fee the sender paid, which can support damages even when the transfer failed. The receipt also proves the failure: status 0, state changes rolled back, nonce consumed. That pairing can establish that the account was operated, that an attempt occurred, and what it cost.
A: Envelope, receipt, and logs are available only if the node still holds that history; some clients prune old receipts. Traces require state as of the target block. Recent transactions can be traced on a full node; old ones generally need an archive node or a tracing provider. Pre-Byzantium transactions (before October 2017) have no receipt status and can only be reconstructed by replay.
Every matter turns on its own facts, and the weight a court gives these artifacts depends on the jurisdiction, the claims, and how the evidence was collected and preserved. If you are litigating or investigating a matter where EVM execution details matter, contact ConsensusIntel to discuss what a forensic analysis can defensibly establish from your specific transactions.
· 13 min read
· 12 min read
· 16 min read
If your matter involves blockchain evidence, ConsensusIntel can help you evaluate your options.
Get in Touch