FORENSIAWeb3 forensicsOpen workspace

Checking what the screen says against the responses that were kept

Forensia rebuilds its supported readings from the provider responses retained in your browser and blocks saving and export on a contradiction. It checks consistency with those bytes. It does not re-execute the chain.

· Forensia · 7 min read · Evidence, Saved work

An investigation tool shows you a reading of data: this call moved that amount, this approval came before that transfer. The reading was produced from responses a data provider sent at one moment. If the reading and the stored responses ever drift apart, through a bug, an edited file or damaged storage, you want to know before the result goes in a report.

Forensia now does that check on request. It takes the provider responses kept in your browser, confirms they are the same bytes that were captured, rebuilds each supported interpretation from them, and compares the rebuilt version with what is on screen. If they disagree, Report, saving the result and the combined raw export are blocked.

This is a consistency check between an interpretation and its own source material. It is not an independent execution of the blockchain, and it does not test whether the provider told the truth.

#Plain languageChecking the summary against the photocopy

Suppose you wrote a summary of a bank statement, and you kept a photocopy of the statement in a sealed envelope. Later you confirm the seal is intact and read the photocopy line by line against your summary. If your summary says 400 and the photocopy says 300, something is wrong with the summary, and you should not send it to anyone.

Note what this cannot tell you. If the bank printed a wrong statement, the photocopy is wrong in the same way, and your summary will match it perfectly. A match means the summary is faithful to the copy you kept. Nothing more.

#How it worksRunning the check from Sources

  1. Open a result and go to Sources.
  2. Open the section named Capture integrity & local evidence.
  3. Under What can you verify now, choose Check local evidence. The check reads only this browser’s vault and contacts no provider.
  4. Read the first line (how many response bodies were verified locally), then the result blocks below it. Each block covers one kind of interpretation and appears only when the result contains that kind.
BlockMatched headingConflict heading
Token stepsToken steps checked against saved receiptsToken interpretation needs review
Account changesAccount changes match saved responsesAccount changes need review
Historical codeHistorical code matches saved responsesHistorical code needs review
Contract callsContract calls match saved responsesContract calls need review
Permission eventsPermission events match saved receiptPermission events need review
Wrapping actionWrapping action matches saved responsesWrapping action needs review
Execution contextExecution context matches saved responsesExecution context needs review
Bitcoin allocationBitcoin inputs and outputs match saved responseBitcoin allocation needs review

Anything else is shown as incomplete, with the reason: a body was never saved, the local copy expired, or a size limit was reached. Incomplete means unchecked. It does not mean disproven, and it does not count as a match.

On a conflict, a banner titled Interpretation conflicts with saved evidence appears, any report link already prepared is withdrawn, and the Report button, Save result and the combined raw export stay disabled for that result.

#Technical detailTwo stages: verify the bytes, then rebuild the reading

Stage one: the bytes

Response bodies are stored in IndexedDB as gzip-compressed, AES-GCM encrypted blobs keyed by the SHA-256 of the original response, with a 30-day retention period. For each source record the verifier requires exactly one link and exactly one blob, a matching manifest digest, a matching response digest, a matching media type and a matching original byte length. It decrypts with the digests as additional authenticated data, checks the compressed size and compressed SHA-256, decompresses with a running cap so an oversized stream is cancelled, then checks the original size and original SHA-256.

LimitValue
Original bytes per response8 MiB
Compressed bytes per response1,000,000
Total original bytes per check64 MiB
Records per check512

Only bodies that pass are handed to stage two. Each record ends in one state: verified, reference only, no response captured, body not saved, missing, expired, failed, key unavailable, or check limit reached.

Stage two: the interpretations

Each interpreter receives a bounded number of verified bodies and re-runs the same decoder that produced the display. Every one first checks the JSON-RPC envelope: version 2.0, a response id equal to the request id, no error member, and strict UTF-8.

CheckVerified bodies usedWhat is compared
Token stepsEach eth_getTransactionReceipt body; up to 256 steps and 16,384 logsKind, sender, recipient, token contract, raw value, token ID, batch index, execution status, and the linked activity row, keyed by log index
Account changesUp to 6 state and code responsesAccount-change view and transaction-start code, in canonical JSON so key order is ignored
Historical codeUp to 4 code responses, 128 KiB eachRequested address, containing-block request and returned bytes, compared without regard to hex letter case
Contract callsExactly 3: eth_getTransactionByHash, eth_getTransactionReceipt, debug_traceTransaction with the callTracerRoot sender, target, value, selector and status; then every nested call’s path, order, depth, call type, sender, target, value, selector, status and failure origin
Permission events1 receipt; up to 48 events and 24 sequences, 4,096 decoded transfersEvent identity, participants, emitting contract, raw quantity or token ID, log position, grant or revocation state, and each approval-then-outflow sequence
Wrapping action3: transaction, receipt, blockAccount, input, exact amount, event position, successful receipt, and the transaction appearing exactly once in the block list
Execution context3: transaction, receipt, blockTransaction and receipt type, reported chain ID, signature v, block hash, height, index, and recorded fee inputs
Bitcoin allocation1 transaction response, 1 MiBOrdered inputs and outputs, participants, integer satoshi amounts, fee, counts and block

The call check rebuilds the call tree at the limits recorded in the capture, with hard ceilings of 256 calls and depth 12. Call types such as CALL, DELEGATECALL and STATICCALL are compared as the tracer returned them, and a retained transferFrom call has its argument and return bytes compared too. Activity rows for internal calls must each map to one retained call ordinal. Activity may show fewer calls than were retained, never extra ones.

Rules that apply to every check

  • A contradiction outranks a gap. If one body is missing and another available body disagrees with the display, the result is a conflict, not incomplete.
  • A full match needs every required body. Two of three is reported as incomplete.
  • Nothing is fetched, repaired or refreshed. The capture time, digests and stored bytes are never rewritten.
  • Captures made after decoder versioning was added record which decoder produced them, for example forensia.geth-call-tree.v1 and forensia.receipt-transfers.v1. An unknown or contradictory version is a conflict before any comparison runs.
  • Older captures without call paths or version records are left as unchecked. They are not reinterpreted under newer rules.
  • The combined raw export runs the full verification again on its own and refuses on any conflict.

In local review, the Ethereum transaction 0x22fc4a1bba0e2a711a5852f5c835eea4cb764f989895b1b48ec73d84dab8ed95 checked with 31 of 31 body hashes, 30 token items, five state responses, four code observations and 64 nested calls matched. A second, 0x698dc47038978fad61d69a87d14b98679e37a772fa06d726523778d1e34530a7, matched four permission events and three sequences. These are selected examples, not a benchmark.

#LimitsWhat a match does not mean

  • A matching hash shows the stored bytes are the captured bytes. It does not authenticate the provider or its content.
  • No receipt-trie proof, consensus check or finality check is performed.
  • The call check does not establish which code actually ran, that an allowance was consumed, or that a given call caused a given event.
  • The code check compares a provider’s answer for the containing block. It does not identify the code at the moment of the call or resolve an EIP-7702 delegation target.
  • The permission check covers events inside one receipt. It does not cover current allowance, permit signatures, token compliance or wallet-history windows.
  • The wrapping check covers direct calls to the Ethereum mainnet WETH contract only. Routers, swaps and other deployments are not relabeled as supported.
  • Only retained items are checked. Matching a bounded sample never means the trace or the receipt was complete.
  • Findings outside these eight checks are not verified by them.
  • Files you downloaded before a conflict was found cannot be recalled.
  • Clearing browser data or reaching the retention expiry removes the bodies. A hash cannot bring them back.