VIEW THIS AS

Auto mode follows the Route Engine until you choose a viewpoint.

YOU ARE HERE

ROUTE CHECK

CONNECTED TO

WHAT NEXT

Use the canonical route for this room, or HELP if you are unsure.

Ethereum Account and Storage Proofs: Verify the Account, the Slot and the Meaning

Three students in school uniforms work through open books at a classroom table, with textbooks and stationery nearby and study notes on the whiteboard behind them.

中文版 · Blockchain learning guide · Previous article

Blockchain learning · Extension BCX011

Three students in school uniforms work through open books at a classroom table, with textbooks and stationery nearby and study notes on the whiteboard behind them.
Study photograph for illustration; it does not establish that the pictured students are studying blockchain.

A storage value becomes useful evidence only when it is bound to the correct account, the correct state root and the correct storage key. A convincing response field saying “7” is not enough. The verifier must follow the account proof, decode the storage root authenticated inside that account, and then verify the requested slot under that root.

This lesson performs that two-stage investigation using actual, locally generated Ethereum-format bytes. The example is a synthetic state with one account and one nonzero storage slot. It is not a real block, RPC response, deployment or claim about an address on any live network.

The procedure is intentionally narrow. It exercises complete singleton leaves, RLP decoding and secure-key derivation. It is not a general Ethereum client or production proof verifier, and it does not cover every trie shape or malformed input.

Choose your reading route

In this guide

Sections 1–3 define the trusted premise and exact bytes. Sections 4–6 verify the account and slot. Sections 7–10 distinguish altered data, response-field discrepancies, authenticated absence and missing evidence. Sections 11–12 separate proven storage from application meaning and provide a verdict worksheet. The final exercise includes answers.

Back to contents · Next section

1. Supply the state root’s authority separately

The classroom request supplies an authenticated expected state root R. Its provenance is a trusted exercise record, not an inference made from the proof itself. The requested account is the twenty-byte value consisting of 0x11 repeated twenty times. The requested direct storage slot is integer zero encoded as thirty-two zero bytes.

R is 4bb4560f8e14f5b6d3aa1f69c110fd0b458bdcedaf910755f10fffbd474ceab7. Treat this exact value as the accepted root for the independent cases unless a case explicitly changes it. The root is invented state data, not an observed Ethereum header field.

In a real investigation, selecting an authenticated header and its state root would require its own chain, block and finality evidence. A mathematically correct proof under an arbitrary root cannot supply that missing authority. This lesson starts after that choice has been made as a premise.

The question is precise: does the supplied evidence establish the requested keyed state under R? It is not asking whether a provider is reputable, whether two endpoints agree, or whether a webpage displays the same value.

Back to contents · Next section

2. Keep the two commitments and hash inputs distinct

The state trie binds an account key to its account value. The decoded account value contains four fields: nonce, balance, storage root and code hash. The storage trie then binds a storage key to a stored value under that account’s authenticated storage root.

For this secure-trie fixture, the account path is Keccak-256 of exactly the twenty address bytes. The storage path is Keccak-256 of the direct slot encoded as exactly thirty-two bytes. Hashing the displayed hexadecimal text, hashing a single zero byte, or padding the account to thirty-two bytes would answer a different question.

Ethereum Keccak-256 is not the standardized SHA3-256 function exposed by some general hashing libraries. The fixture was generated and independently checked with the required Keccak function. Similar names are not a reason to substitute a different digest algorithm.

The pinned Geth secure-trie implementation provides implementation context for hashed account and storage keys. It was inspected as a versioned reference, not executed as a client or presented as the latest release.

Back to contents · Next section

3. Inspect the small, complete proof packet

The account proof contains one 108-byte node. Its exact hexadecimal bytes are:

f86aa120e2c07404b8c1df4c46226425cac68c28d27a766bbddce62309f36724839b22c0b846f8448080a0f258b1c6d5ee7f6f3549117fb0ac79118d5ad19b9c027f9b8e1471ca519b3b6ca0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a

The storage proof contains one 36-byte node. Its exact hexadecimal bytes are:

e3a120290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56307

Both are complete singleton leaf nodes. Each compact path begins with byte 0x20, the even-length leaf-path encoding for the full sixty-four-nibble key in this fixture. It is not an instruction to prepend that byte to every node in every trie.

The node lengths, compact paths, RLP fields and digests were checked independently. No omitted middle section or ellipsis stands for hidden proof data. The short packet is possible because the synthetic tries each contain only one entry; a general state proof can require a different sequence of node types.

Back to contents · Next section

4. Verify the account before trusting its fields

First compute Keccak-256 of the complete 108-byte account node and compare it with R. For the supplied node, it matches. Next decode the node and verify that its complete leaf path equals the hashed twenty-byte requested address.

The leaf’s value is itself an RLP-encoded account. Decode that inner value rather than treating the outer trie node as the account tuple. The resulting nonce is 0, balance is 0, storage root is S, and code hash is K.

S is f258b1c6d5ee7f6f3549117fb0ac79118d5ad19b9c027f9b8e1471ca519b3b6c. K is bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a, the hash of the supplied single code byte 00, an inert STOP instruction.

That code byte exists only to make the synthetic account tuple complete. It is not claimed to implement a counter, a registry or the later hypothetical layout card. Nor do the encoded account fields prove that this synthetic state arose from a real reachable deployment history.

This first stage authenticates S through the account under R. A separate response field labelled storageHash has no authority to replace S merely because it appears beside the proof.

Back to contents · Next section

5. Verify slot zero under the decoded storage root

Now hash the complete 36-byte storage node and compare it with S decoded from the account. The supplied node matches. Decode its compact leaf path and compare it with Keccak-256 of the thirty-two zero bytes representing direct slot zero.

That path matches as well. The leaf’s stored value decodes to integer 7. In this small RLP case, the single byte 0x07 represents the integer’s minimal byte form, and wrapping that one-byte value in the relevant RLP layers does not add a long string prefix.

The successful chain of evidence is therefore R to the correct account, that account to S, and S to slot zero’s value 7. It is not a proof made by hashing the decimal text “7” and comparing it directly with the state root.

A model result can now state: “Under the supplied authenticated synthetic state root, the requested account is present and its direct slot zero has value seven.” Whether seven means reviewed records, a flag or something else requires additional interpretation evidence.

Back to contents · Next section

6. Decode lengths rather than trusting appearance

The account node starts with f8 6a: an RLP list with a 106-byte payload, plus its two-byte prefix, totaling 108. Its path item occupies 34 bytes: one string prefix plus thirty-three bytes containing the compact-path flag and hashed key.

The remaining outer value item is a 70-byte account encoding wrapped by a two-byte string prefix, totaling 72. Thus 34+72=106. Inside that account encoding, a 68-byte list payload contains the two canonical zero integer fields and two thirty-two-byte fields with their string prefixes.

The storage node begins e3, a one-byte list prefix for a 35-byte payload. Its path item again occupies 34 bytes and the encoded value occupies one, giving 36 bytes overall. These checks make the supplied packet inspectable without pretending that all proofs share these exact lengths.

Ethereum’s RLP documentation explains the byte-string, list and integer conventions. The local fixture checks these specific encodings; it is not a hardened decoder for all malformed lengths, nesting or resource-exhaustion cases.

Back to contents · Next section

7. Separate tampering from a false convenience field

In the first independent variation, change the storage node’s final value byte from 07 to 08 while retaining the original expected S. Hashing the changed node no longer gives S. The storage commitment check fails. The original account proof may still be valid, but the modified storage evidence is not bound to its storage root.

In a different variation, keep both proof nodes unchanged and set a convenience response field value to 8. The cryptographic proof still decodes 7. The correct verdict is “authenticated value seven; claimed response value eight disagrees,” not “all proof arithmetic failed.”

Likewise, a fabricated standalone storageHash field cannot override S recovered from the authenticated account tuple. If the field disagrees, identify that disagreement. Do not switch to a different root to make a separately supplied proof appear acceptable.

These distinctions preserve useful evidence. A misleading summary field need not destroy an otherwise valid proof, while a changed proof byte is not merely a display typo if its commitment check fails.

Back to contents · Next section

8. Use the requested key, not whichever value the leaf contains

For an independent slot query, request direct slot one: thirty-one zero bytes followed by 01. Its Keccak path differs from the complete slot-zero leaf path. Under the authenticated singleton storage root, the supplied complete leaf therefore establishes that slot one is absent.

The leaf contains a value of seven for slot zero, but that does not make seven the value of slot one. Under the stated Ethereum storage semantics, the absent slot’s default value is zero. The path comparison is essential to deciding which statement the evidence supports.

Similarly, query a different synthetic twenty-byte address consisting of 0x22 repeated twenty times. The authenticated account leaf has a different complete path. In this singleton state trie, that proves the requested other account is absent; it does not authenticate the original account tuple as belonging to that other address.

The proof bytes can thus be cryptographically valid while refuting a claim of membership for the requested key. Distinguish authenticated non-membership from malformed cryptography and from a provider merely answering an unintended identity.

Back to contents · Next section

9. Do not turn missing nodes into zero

Return to the original nonempty storage root S and requested slot zero. This time omit the required storage node. The verifier cannot complete the storage check. It has missing evidence, not an authenticated zero value.

The previous absence result used a complete leaf whose root binding and divergent path were verified. An empty response or a timeout supplies neither. The difference is evidentiary: one demonstrates where the requested key cannot occur in the authenticated shape; the other does not provide the needed shape at all.

Pinned Geth proof code distinguishes proof-node availability from verified absence. Our missing-node conclusion is explicitly about this nonempty-root fixture. It must not be generalized into “every empty proof array is invalid.”

An authenticated empty-trie root has different semantics and may need no ordinary leaf evidence under the relevant verifier rules. That case is outside our worked shape. A reviewer should recognize its separate conditions rather than applying the singleton missing-node rule indiscriminately.

Back to contents · Next section

10. A correct proof under the wrong root answers the wrong question

Keep the original proof nodes, but change the requested expected state root to another supplied value unequal to R. The account-node hash no longer matches that expected root. Stop before treating the inner storage root as authoritative for the new request.

Alternatively, suppose someone verifies the original packet under R and then labels the result as current state at an unspecified later block. The proof has not supplied that temporal step. It remains evidence under R, not a general statement about every future state.

Proof verification and root selection therefore stay separate. A provider cannot repair a mismatch by suggesting that the verifier adopt whichever root its packet happens to produce. The application must retain its authenticated target context.

Nothing in this fixed exercise establishes canonical chain membership, finalized status or an RPC endpoint’s honesty. Those are intentionally supplied or excluded premises rather than conclusions hidden inside a successful digest comparison.

Back to contents · Next section

11. Slot evidence does not supply its own application layout

Consider a separate hypothetical interpretation card saying: “For the intended application, reviewCount is an unsigned 256-bit value in direct slot zero.” If that card is independently justified for the relevant application and context, the verified slot value supports the conditional interpretation reviewCount=7.

The card is additional evidence. The synthetic STOP code does not implement this named variable, and our proof does not certify a Solidity compilation or deployment. We are demonstrating how an interpretation depends on a separately supported layout statement.

Remove the card and the proof still establishes slot zero’s value, but not the name reviewCount. Replace it with a card assigning reviewCount to direct slot one, and the slot-zero membership result no longer establishes that variable. In the supplied singleton storage state, the separate slot-one absence check gives default zero instead.

Real storage can involve packing, mappings, dynamic arrays, inheritance and proxies. The Solidity 0.8.30 layout reference describes layout rules; this lesson deliberately uses a declared direct slot rather than pretending that every variable is found by hashing its name or using a mapping formula.

For how implementation changes affect stored meaning, use Proxy State and Migration. The proof here binds bytes to a root; it does not settle upgrade semantics.

Back to contents · Next section

12. Record four conclusions, not a single green badge

A useful worksheet has four fields. First record the root and context premise. Second record account membership or absence and the authenticated tuple when present. Third record storage membership, absence or unavailable evidence. Fourth record the application interpretation and its supporting layout, if any.

For the main packet: the root is supplied and trusted for the synthetic exercise; the requested account is present; its decoded storage root binds direct slot zero to seven; and no real application variable is established without a separate justified interpretation card.

For the altered response-field case, preserve the valid seven and record the field disagreement. For the missing-node case, mark storage evidence unavailable. For the divergent slot-one case, record authenticated absence and default zero under the stated semantics. These outcomes should not collapse into one ambiguous “failed” label.

EIP-1186 describes an account/storage proof RPC proposal, but its page is Stagnant, created 24 June 2018. This lesson does not call it Final, execute its historical examples or certify complete eth_getProof conformance. The actual fixed byte vectors were generated separately and checked locally.

Back to contents · Next section

Exercise with answers

  1. Which root verifies the storage node? The storage root decoded from the authenticated account, S; not an unrelated response field and not R directly.
  2. What bytes form the account key input? Exactly twenty address bytes, not their textual hexadecimal characters.
  3. What bytes form direct slot zero’s key input? Exactly thirty-two zero bytes before Keccak-256.
  4. Unchanged proofs accompany a field claiming eight. What follows? The proof establishes seven, and the convenience field disagrees.
  5. The storage node itself changes its final byte to eight. What follows? Its digest fails to match the original S.
  6. The complete authenticated singleton leaf has another full path than requested slot one. What follows? Authenticated absence, corresponding to default zero under the given semantics.
  7. The required leaf is omitted under nonempty S. What follows? Missing evidence, not proven absence or zero.
  8. Does proving slot zero’s seven prove a named Solidity counter exists? No. A relevant independently supported layout and implementation interpretation are still needed.

For a length check, add the outer account leaf’s 34-byte path item and 72-byte value item. The payload is 106 bytes; its two-byte list prefix yields 108. For the storage leaf, 34 plus 1 gives 35, and the one-byte prefix yields 36. Neither calculation establishes a general maximum proof size.

Back to contents · Next section

Sources and further reading

A sound result follows the entire link from the chosen root to the account, from that account to the requested slot, and from the proven value to only the meaning that the available layout evidence supports.

Back to contents