中文版 · Blockchain learning guide · Previous article
Blockchain learning · Article BC038

A contract’s stored value, a transaction’s emitted log and a website’s indexed result are different kinds of evidence. They can describe related activity without being interchangeable. When a dashboard disagrees with a state query, the first task is to identify the block context and the path used to derive each value.
This lesson follows a fictional counter from a known checkpoint through two updates. An index misses a log, receives a duplicate and later encounters a replacement branch. You will reconcile the numbers while preserving the distinction between current state, historical messages and an off-chain interpretation.
Choose your reading route
In this guide
- 1. Storage answers a state question at a particular context
- 2. Events describe emitted data, not automatic copies of storage
- 3. An index is an off-chain interpretation with its own progress
- 4. Define a counter model that really can be reconstructed
- 5. The first branch produces a stored count of 9
- 6. Missing A101 creates a plausible but wrong total
- 7. Duplicate delivery is not a second state update
- 8. Replacement branches require rollback, not accumulation
- 9. A removal indication needs a defined consumer response
- 10. Decoding requires the right contract and schema
- 11. Equal current totals do not prove equal histories
- 12. A reconciliation checklist for three disagreeing displays
- 13. Exercise: repair the derived record
- 14. Frequently asked questions
- 15. Sources and next reading
Start with the three views and the deliberately strong assumptions of the counter model. Follow the missing-log calculation, then the duplicate and branch-replacement cases. The exercise asks what can be concluded from each observation and what extra evidence remains necessary.
For analysing real business processes from event traces, the existing process-mining guide explains case definitions, missing events and causal limits. This lesson instead focuses on contract records, log identity and blockchain branch context. It does not design a production indexing service.
Back to contents · Next section
1. Storage answers a state question at a particular context
Persistent contract storage forms part of the application’s on-chain state. A state query asks about a value at a selected execution context, such as the state associated with a particular block.
“The counter is 9” is incomplete without that context. The counter might have been 2 earlier and might be 5 on a different selected branch. Those values can all be internally consistent when properly labelled.
The Solidity 0.8.30 introduction distinguishes persistent storage from temporary execution data. Persistence means the record can be read by later executions under the relevant state; it does not mean the value never changes.
A human-readable contract getter can expose a value without requiring the reader to decode raw storage slots. Either way, the evidence must identify the contract and block context. A screenshot with an unlabelled number does not establish which state was queried or how the displayed answer was obtained.
Back to contents · Next section
2. Events describe emitted data, not automatic copies of storage
A Solidity event uses the EVM logging mechanism. The Solidity 0.8.30 contracts reference describes logs associated with the emitting contract and accessible through client interfaces.
The program chooses what to emit. An event named CounterChanged does not, by its name alone, prove that a particular storage field changed by the reported amount. That relationship depends on the code path and the conditions under which the log was produced.
Logs are not simply another storage variable that the emitting contract can later read through an ordinary state-variable access. Their role and access mechanisms differ. A website may use them to construct an activity feed, but the feed remains a derived view.
This distinction is useful even when the application is well designed. A storage value can answer “what is the recorded amount now?” while a complete relevant log history can help answer “which reported updates led here?” Neither question should silently substitute for the other.
Back to contents · Next section
3. An index is an off-chain interpretation with its own progress
An indexer reads selected blockchain data, decodes it and builds a query-friendly representation. A dashboard can then retrieve a list, total or timeline from that representation rather than replaying all relevant records for every request.
The index has its own progress and processing rules. It may be behind, have missed a range, have received the same delivery twice or still retain data from a branch no longer selected. These possibilities concern the derived system and do not automatically imply that validators disagree about execution.
An indexed answer should therefore carry context: which network and contract, which schema, up to which block identity, and what chain-selection or finality policy it follows. “Updated recently” is less useful than a reproducible processing checkpoint.
This lesson uses a tiny hand-maintained index to expose those dependencies. It assumes the required source records are available for the stated checks. Actual endpoint retention and historical query support must be verified before promising that any missing range can always be recovered.
Back to contents · Next section
4. Define a counter model that really can be reconstructed
At checkpoint H100, the fictional contract ArchiveCounter stores count=2. H100 is a particular block identity at height 100, not a label for every possible block with that height.
The supplied fixed program has one relevant successful update operation: add(delta). Each successful update increases count by the given non-negative integer delta and emits exactly one matching Added(delta) log. No other code path changes count, no upgrade occurs, and no additional updates are omitted from the supplied branch histories.
These are strong application assumptions. They are what make summing the listed deltas from the checkpoint a valid reconstruction in this exercise. A real contract may omit events, emit several events, use different meanings or change behavior over time.
All supplied updates succeed, and their logs belong to the selected blocks in their respective scenarios. We exclude reverted execution, fees, account balances and physical archive facts. The values are abstract counters, not assets or personal records.
Our teaching index starts from the same trusted-for-the-exercise checkpoint value 2. It should apply each relevant selected-branch log exactly once, in chain order, and retain enough block identity information to distinguish alternative branches.
Back to contents · Next section
5. The first branch produces a stored count of 9
Branch A extends H100 with A101 and then A102. A101 contains one relevant successful update with delta 3. A102 contains one relevant successful update with delta 4.
The state trace is 2 at H100, then 2+3=5 at A101, then 5+4=9 at A102. A complete matching index also reaches 9 by applying the two logs to its checkpoint.
The log for A101 and the log for A102 are separate records. For this exercise, each has log index 0 within its block. Their distinct block identities keep them distinct even though their log-index numbers match.
A useful observation record includes network, emitting contract, block identity, transaction identity and the log’s position. The exact API fields and indexing conventions must be checked for the client being used. Our symbolic A101 and A102 are not real hashes, but they play the role of distinct block identifiers in the worksheet.
At this point, storage and index agree under the supplied assumptions. That is a consistency check for this model, not a universal proof that every record the application displays is complete or correct.
Back to contents · Next section
6. Missing A101 creates a plausible but wrong total
Suppose the index disconnects after H100 and misses A101. It later receives A102’s delta-4 log and adds it to its checkpoint value 2. Its displayed total becomes 6.
A state query at A102 returns the supplied count 9. The difference is not explained by saying that storage and events are “two opinions.” The model gives a definite reason: the derived calculation omitted delta 3.
The index should mark its range as incomplete rather than claiming to have processed a contiguous history through A102. Receiving a later block’s event does not prove every earlier block was inspected.
To repair this classroom case, verify the missing range and block ancestry, obtain A101’s relevant log, then recompute the selected history from H100 in order: 2+3+4=9. Do not simply overwrite the dashboard with 9 and claim its historical records are now complete.
The recomputation matters beyond this additive example. Addition happens to allow some out-of-order arithmetic to reach the same sum. Other event-driven state updates may depend on sequence. An index should not use that accidental property as a general permission to ignore ordering.
Back to contents · Next section
7. Duplicate delivery is not a second state update
After the repaired index reaches 9, it receives A102’s same log again. A naive consumer that adds every arriving delta would calculate 9+4=13.
The chain did not perform another update in this scenario. The consumer received the same observation twice. A correctly identified duplicate should not create another application effect in the derived view.
For the worksheet, a log key can include network, contract, block identity and log index. Transaction identity is useful additional evidence. The key must distinguish occurrences, not merely event names or payload values.
Two genuine updates can both emit Added(4). Deduplicating only by the delta value would incorrectly discard one of them. Conversely, identifying every delivery as new would incorrectly count retransmission as another update.
The Ethereum JSON-RPC reference documents log fields such as block hash, transaction hash and log index. Those fields support precise identification, but a consumer still needs a processing policy that uses them correctly.
Back to contents · Next section
8. Replacement branches require rollback, not accumulation
Now suppose the selected chain changes after H100. The supplied new branch is H100 followed by B101 and B102. B101 adds 1 and B102 adds 2. A101 and A102 are no longer on the selected branch.
The correct new state is 2+1+2=5. Starting from the old index value 9 and simply appending the new deltas would produce 12, which mixes two alternative histories.
A clean classroom repair returns to the shared checkpoint H100 with value 2, removes the A-branch effects from the selected view and applies B101 then B102. The new selected-view count becomes 5.
The old A-branch observations need not be erased from an audit archive. They can be retained with their branch status clearly marked. What must change is the claim that their effects belong to the current selected history.
Both branches contain blocks at heights 101 and 102, but their identities and contents differ. A checkpoint that stores only “processed height 102” cannot tell the two histories apart. This is why block identity and ancestry belong in the reconciliation record.
Back to contents · Next section
9. A removal indication needs a defined consumer response
Client interfaces can expose information about logs removed because of a reorganisation. The JSON-RPC documentation includes a removed indicator for relevant log results. Such information is useful only if the consumer knows how to undo or rebuild the corresponding derived effects.
A consumer that displays a warning but keeps adding replacement-branch deltas to the old total has not completed reconciliation. Likewise, a lost connection can mean the consumer missed notifications; a robust interpretation should not assume every important change was delivered exactly once.
Our worksheet uses a supplied branch replacement and a known common checkpoint so that the correction is unambiguous. It does not prescribe one universal production rollback depth, database design or finality wait.
Finality policy changes what a service is willing to present as settled, but it should be stated rather than hidden. A current-head index and an index restricted to a finalised checkpoint can legitimately show different progress. Compare them at aligned contexts before describing a contradiction.
Back to contents · Next section
10. Decoding requires the right contract and schema
Raw log bytes are not self-explanatory business sentences. The Solidity 0.8.30 ABI specification defines how event data and topics encode values. Correct interpretation depends on the expected event definition and which parameters are indexed.
For this exercise we supply already-decoded Added(delta) records from the intended contract. A real consumer must also check the emitting address and relevant schema. A familiar event name or matching-looking topic does not independently establish the application’s identity or meaning.
Indexed dynamic values can be represented by hashes rather than their original contents. Do not promise that every displayed text field can be recovered directly from a topic. The exact encoding rules determine what information is available.
If an application’s code or schema changes, an index may need version-aware decoding. Applying today’s interpretation to every historical log can turn valid bytes into misleading records. The toy’s fixed-code assumption deliberately avoids that additional complication while making it visible.
Back to contents · Next section
11. Equal current totals do not prove equal histories
Imagine a separate index that somehow displays 9 at A102 but has no A101 record. Perhaps it copied the current state value directly after the gap. Its headline number now agrees with storage, yet its activity history is still incomplete.
This is not necessarily a bad design if the service clearly offers only a current snapshot. It becomes misleading when the same evidence is advertised as a complete update history.
Likewise, two different sequences can produce the same final additive count. A final-state equality check cannot establish the full order or identity of every update. The required evidence depends on whether the user’s question concerns the present value, a particular transaction or the complete history.
Our reconstruction succeeds because the model explicitly guarantees a known initial value and exactly one matching log for every change. Without those assumptions, summing events is an interpretation to validate, not a universal way to recover any contract’s storage.
Back to contents · Next section
12. A reconciliation checklist for three disagreeing displays
When a state query, event feed and dashboard disagree, collect a small evidence packet before proposing a cause.
- Identify the network and exact contract for all three views.
- Record the state query’s block identity and the index’s processed checkpoint.
- Verify that the relevant block range is contiguous and belongs to one selected ancestry.
- Check the event schema, emitting address and decoded fields.
- Distinguish duplicate deliveries from distinct log occurrences.
- Determine whether removed-branch effects remain in the derived view.
- State which code assumptions connect emitted data to stored values.
- Separate current-state correctness, history completeness and finality claims.
For the missing-log case, the explanation is: “The index started at H100=2 but applied only A102’s delta 4, so it showed 6. Replaying the complete supplied A branch gives 9.” This identifies the missing evidence and the repair calculation.
For the branch case, the explanation is: “The current view follows B101 and B102 from H100 and therefore equals 5. The former A-branch total 9 is retained only as a historical observation, not as the selected state.”
Neither explanation requires alleging that the contract lied or the network lost arithmetic consistency. Those stronger claims would need different evidence.
Back to contents · Next section
13. Exercise: repair the derived record
Use the supplied fixed program and checkpoint H100=2. Treat the scenarios separately unless a sequence is explicitly stated.
- What are the state values after A101 adds 3 and A102 adds 4?
- An index misses A101 and applies only A102. What does it display, and what value should an aligned complete reconstruction produce?
- After repair to 9, the same A102 log arrives again. What would naive repeated addition produce, and what should a deduplicating index retain?
- Two distinct blocks each contain a genuine Added(4) event. Should equal payloads alone cause one to be discarded?
- The selected branch becomes B101 adding 1 and B102 adding 2 after H100. What is the correct count, and what wrong count results from appending these deltas to the old 9?
- A service stores only processed height 102. Is that enough to distinguish A102 from B102?
- A dashboard equals the storage value 9 but lacks an earlier event. Does equality prove complete history?
Answers and reasoning
- The values are 5 and then 9.
- It displays 6, while the complete aligned A-branch reconstruction gives 9. The omitted delta is 3.
- Naive addition gives 13. Correct occurrence-aware processing retains 9 because no new chain update was supplied.
- No. Equal values can belong to distinct occurrences. Deduplicate using appropriate identity and context, not payload equality alone.
- The correct count is 5. Appending to the old branch total gives the incorrect mixed-history value 12.
- No. The same height can refer to different block identities and ancestries.
- No. Current-value agreement and historical completeness are different claims.
Extension: a new occurrence with the same delta
Continue the A branch with A103, which contains a genuinely new successful Added(4) update. The state and complete index now become 13. This result is numerically equal to the earlier duplicate-processing error, but the supporting history is different.
A correct number for the wrong reason is still an unreliable explanation. Preserve occurrence identity so that another reader can distinguish A103’s real update from a second delivery of A102’s old log.
Back to contents · Next section
14. Frequently asked questions
Are events the contract’s database?
They are emitted log data, with a different role from persistent storage. An off-chain service may build a database from them, but that database has its own completeness and interpretation assumptions.
Does an event name prove what happened?
No. Check the emitting contract, schema, code path and block context. A label is not a proof that the payload matches a particular state variable or external event.
Can a current state query replace an activity history?
It can answer the current-value question at its context. It does not automatically enumerate all updates that produced that value.
Is an index necessarily wrong if it lags?
Not if its progress and purpose are accurately described. The error is presenting an older or incomplete view as an aligned, complete current result.
Back to contents · Next section
15. Sources and next reading
Sources checked on 12 October 2026, Singapore time. Solidity references are pinned to 0.8.30. API descriptions support the named concepts, not a guarantee that every endpoint retains all historical data.
- Solidity 0.8.30 introduction: persistent and temporary data distinctions.
- Solidity 0.8.30 contracts and events: emitted logs and event interpretation.
- Solidity 0.8.30 ABI specification: event topics and data encoding.
- Ethereum JSON-RPC: state contexts, receipts and log identity fields.
- How Process Mining Works: a separate guide to analysing recorded business processes.
Review contract state machines to see why code conditions matter when interpreting an event. Continue to failed-transaction diagnosis for execution outcomes, and later to indexing infrastructure for service-level design. For now, keep state, emitted records and derived views separately labelled and reconcile them at the same block context.
