Continue to the next learning task
Next: reproducible study package · Write an evidence-based technical handover · Learning-series hub
Debugging a blockchain study programme begins with a precise mismatch, not a guess about which technology is unreliable. This guide uses the previous offline state simulator to connect a failed observation to a violated rule, a responsible function and a reproducible retest. The complete diagnostic companion is included.
You will inspect four deliberately faulty variants against four independent probes, explain their different failure patterns and write a regression notebook that preserves the reference contract. The reference programme remains unchanged. The exercise is local and synthetic, with no accounts, signatures, network services or transactions.
The result is a method for learning from code failures, not an audit of a production blockchain or a claim that four probes find every possible defect. A successful diagnostic run shows that these controlled mistakes produce the stated observations in this supplied experiment.
The featured photograph illustrates study, not a verified blockchain class.
Find your next learning step
How to Learn Blockchain Technology · Guide 20
Choose the question · Define the objects · Work the case · Check and vary · Test transfer
Contents
Chapters 1–5
1. Start with the mismatch you can reproduce
2. Freeze the reference contract
3. Define four complete probes before seeing results
Chapters 6–10
6. Diagnose revision changes on rejection
7. Diagnose double increments on success
8. Diagnose resetting every replay step
Chapters 11–15
11. Write a complete regression entry for P1
12. Use the earliest divergent state as a repair anchor
13. Do not repair the expectation to hide a fault
Chapters 16–20
16. Keep experiments isolated and clearly named
17. Explain the diagnosis in English and Chinese
18. Assess debugging with a ten-point rubric
A useful debugging question names the source version, initial state, request, expected result and actual result. “The chain is broken” supplies none of those. “This offline variant accepts B's request against owner A when probe P1 expects rejection” identifies a relationship you can inspect.
Keep the original observation before editing. If you change the fixture, contract and implementation together, a later green result may not explain what happened. The notebook should let another reader recreate the same mismatch under the same premises, then see what a repair changed.
This guide deliberately limits the experiment to the supplied note model. Authenticity is an input Boolean and published is a local field. Do not interpret a local parser or state-function failure as evidence about a real network. Equally, do not dismiss the learning task because it is small: the rule-to-observation connection is visible enough to diagnose completely.
Your first output is a one-sentence failure statement and a source route. If you do not understand the expected state, return to the simulator guide. If the expectation is clear but the implementation differs, continue with the diagnostic probes. The next action should follow the evidence gap, rather than expand into an unrelated lecture or an unplanned production change.
The reference begins from S: owner A, revision 2, published False. A request is accepted only with authentic True, caller equal to owner, matching expected revision and unpublished state. Acceptance increments revision once and sets published True; rejection leaves every tracked field unchanged.
The reported first failure follows authenticity, owner, revision, published. Replay uses each previous after-state as the next before-state. State and Request field validation are separate from application rejection. These are the contract relationships against which the supplied probes are judged.
The reference file blockchain_state_lab.py includes twelve passing unittest methods in the recorded Python 3.12.14 preparation run. This diagnostic companion adds a separate small probe set; it does not replace those tests or turn their earlier result into proof of complete correctness.
Save the exact reference beside the companion. The deliberately faulty functions are experimental variants for well-formed fixtures, not recommended replacement APIs and not examples of safe production patches. Their purpose is to violate one named relationship so you can observe how a test notices it. Keeping that role explicit prevents a learner from later copying a fault demonstration as the preferred implementation.
CHAPTER 3 OF 20 · Learn and check
3. Define four complete probes before seeing results
P1 applies caller B, expected revision 2 and authentic True independently to S. It expects a rejected Result with reason owner and both before and after equal to S. P2 applies A, expected 1 and authentic True independently to S, expecting rejection for revision and unchanged S.
P3 applies A, expected 2 and authentic True independently to S. It expects acceptance, reason accepted, before S and after owner A, revision 3, published True. These three probes compare the complete Result rather than only its accepted flag.
P4 starts once from S and sequentially processes A/2/True, A/2/True and A/3/True. It expects final A/3/True and the complete linked Results with flags True, False, False and reasons accepted, revision, published. The expected later before-states are the preceding after-state, not S.
The probe definitions are independent expectations from the written rule. They are not generated by each faulty variant's output. Preserve them in the notebook before running the experiment. If a learner cannot explain P4's third rejection, repair the replay reasoning first; otherwise they may edit a correct expectation to match a faulty programme and call that debugging.
The recorded experiment reports no failed probes for reference. M_owner fails P1 only. M_rejection fails P1, P2 and P4. M_double fails P3 and P4. M_reset fails P4 only. The next sections explain the controlled cause of each pattern.
These are observed outcomes for the supplied variants and probes, not universal signatures of every possible bug. A different defect could produce the same pattern, and an untested path could contain a fault without appearing in this matrix. Use a pattern to guide inspection, not to declare a unique root cause without checking the code.
The reference row means all four expected comparisons matched in this experiment. It does not establish every State, Request, list or malformed input. The deliberately faulty rows show that these selected checks can notice these selected deviations. That is useful, bounded evidence about the learning exercise.
Keep columns for probe, expected relationship, actual mismatch and candidate cause. A red cell is only the beginning of an explanation. The notebook becomes informative when it connects the cell to a specific violated condition or state update. The supplied code makes that connection inspectable because each experimental function is separately named and the original reference remains available.
| Variant | P1 | P2 | P3 | P4 |
|---|---|---|---|---|
| reference | Matches | Matches | Matches | Matches |
| M_owner | Mismatch | Matches | Matches | Matches |
| M_rejection | Mismatch | Mismatch | Matches | Mismatch |
| M_double | Matches | Matches | Mismatch | Mismatch |
| M_reset | Matches | Matches | Matches | Mismatch |
M_owner uses ignore_owner, which checks authenticity, revision and published but omits caller-to-owner equality. Against P1, B's request is therefore accepted even though owner remains A. Its after-state becomes A, revision 3, published True instead of unchanged S.
The violated relationship is permission, not supplied authenticity. P1's authenticity was True in both reference and variant. Do not repair the explanation by claiming B's signature failed. The programme has no signature algorithm, and the fixture deliberately holds this input constant.
P2 still rejects for revision, P3 still accepts correctly and P4's callers are all A, so those supplied probes do not reveal the omitted owner check. This explains the one-cell pattern without asserting that all other possible requests behave correctly.
A regression entry should say that the reference contract requires owner equality, identify the missing check and retain P1 as a witness. The repair target is the transition's acceptance condition. Merely changing the displayed reason, forcing every request to fail or replacing P1's caller with A would hide or alter the task rather than restore the specified relationship. Retest the witness and the wider reference suite after a separately labelled repair.
M_rejection calls the reference transition, then changes a rejected result's after-state to revision plus one. It can keep the accepted flag and reason correct while violating the rule that rejection preserves all tracked fields. This is why P1 and P2 compare complete Results.
For P1, expected after is A/2/False, but the variant gives A/3/False. P2 has the same revision increment despite its revision rejection. Both fail even though their decision flags remain False. A test checking only accepted would miss this particular difference.
In P4, the first request succeeds to A/3/True. The second rejects for revision but is then changed to A/4/True. The third expects revision 3, now sees 4, rejects for revision and is changed again to A/5/True. The flags still read True, False, False, while final state and the third reason differ from the reference.
The repair must preserve before-state on rejection, not merely adjust the final displayed number at the end of replay. An end-only correction could conceal incorrect intermediate states. Save the first mismatching transition, restore the update rule in a labelled implementation and retain the witness as a regression test. The complete replay comparison then checks whether the repair holds across the sequence.
M_double calls the reference and, when accepted, replaces the after revision with the before revision plus two. P3 still has accepted True and reason accepted, but produces A/4/True instead of A/3/True. The fault concerns the exact successful update, not whether the request had permission.
P1 and P2 reject, so the deliberate success-only change does not affect them. P4 is affected immediately by its first successful request. The later expected revisions are then compared with 4 instead of 3, changing the subsequent path and final state.
This illustrates why a first divergent state can explain later mismatches. Do not independently patch every later reason to resemble the reference while retaining the initial double increment. Locate the earliest transition that violates the declared update, then review its downstream effects.
A useful notebook entry records expected increment one, observed increment two, responsible success branch and retest set. Keep permission tests as well as the success witness: a repair should restore the update without accidentally removing a rejection condition. The matrix helps choose checks, but it does not justify narrowing the final retest to a single green cell and ignoring requirements that may have been affected by the change.
M_reset keeps the correct single-request transition for P1, P2 and P3. Its fault is in reset_every_step: every request is evaluated from the original S rather than from the current state. The isolated probes therefore match while P4 fails.
In P4, the first request succeeds from S to A/3/True. The identical second request also succeeds because it is incorrectly restarted from S. The third expects revision 3 against original revision 2, so it rejects for revision and returns S. The variant selects that last after-state as final, producing A/2/False.
The faulty replay has lost sequential linkage. Its later before-states do not track the preceding after-states. This is a different layer from a wrong acceptance predicate inside apply_request, so rewriting permission logic would not address the demonstrated problem.
The repair target is the replay loop's current-state assignment. Preserve independent fixtures as independent, but carry state forward within the explicitly sequential task. A learner who says every test should reset is confusing test isolation with the order inside one test fixture. Keep those two scopes distinct in the notebook and confirm the repaired sequence's full Results, not just the last Boolean or number.
The next native code block contains blockchain_state_debug_lab.py in full. It imports the reference State, Request, Result, apply_request and replay, then defines the four deliberately faulty variants and a deterministic probe runner. Both files belong in the same chosen local folder for this exercise.
The companion does not edit the reference file. Its functions are explicitly experimental, and its main entry prints the failed-probe lists. It also compares the observed matrix with the stated expected matrix, raising an assertion if the diagnostic exercise itself no longer produces those declared patterns.
Read diagnose before examining each mutant. The complete Result expectations for P1–P3 and complete replay expectation for P4 are visible there. This helps you see that the experiment is not asking every implementation to grade itself using its own answers.
The companion's deliberately simplified variants are used only with the valid supplied fixtures. Do not treat them as full replacement implementations with the reference API's validation guarantees. The lesson concerns four controlled deviations under a fixed experiment. Its clarity comes from preserving that contract, source identity and probe set, not from pretending a short fault matrix is a comprehensive software assurance system.
"""Deliberately faulty offline study variants; never a production patch."""
from dataclasses import replace
from blockchain_state_lab import State, Request, Result, apply_request, replay
def ignore_owner(state, request):
if not request.authentic:
return Result(False, "authenticity", state, state)
if request.expected_revision != state.revision:
return Result(False, "revision", state, state)
if state.published:
return Result(False, "published", state, state)
return Result(True, "accepted", state,
replace(state, revision=state.revision + 1, published=True))
def increment_rejection(state, request):
result = apply_request(state, request)
if not result.accepted:
return replace(result, after=replace(state, revision=state.revision + 1))
return result
def double_increment(state, request):
result = apply_request(state, request)
if result.accepted:
return replace(result, after=replace(result.after,
revision=state.revision + 2))
return result
def replay_with(step, initial, requests):
current, results = initial, []
for request in requests:
result = step(current, request)
results.append(result)
current = result.after
return current, tuple(results)
def reset_every_step(initial, requests):
results = tuple(apply_request(initial, request) for request in requests)
return (results[-1].after if results else initial), results
def diagnose(step, replay_function):
state = State("A", 2, False)
probes = [
("P1", Request("B", 2, True), Result(False, "owner", state, state)),
("P2", Request("A", 1, True), Result(False, "revision", state, state)),
("P3", Request("A", 2, True),
Result(True, "accepted", state, State("A", 3, True))),
]
failed = [name for name, request, expected in probes
if step(state, request) != expected]
requests = [Request("A", 2, True), Request("A", 2, True),
Request("A", 3, True)]
s1 = State("A", 3, True)
expected = (s1, (Result(True, "accepted", state, s1),
Result(False, "revision", s1, s1),
Result(False, "published", s1, s1)))
if replay_function(state, requests) != expected:
failed.append("P4")
return failed
def run_experiment():
variants = {
"reference": (apply_request, replay),
"M_owner": (ignore_owner,
lambda state, requests: replay_with(ignore_owner, state, requests)),
"M_rejection": (increment_rejection,
lambda state, requests: replay_with(increment_rejection, state, requests)),
"M_double": (double_increment,
lambda state, requests: replay_with(double_increment, state, requests)),
"M_reset": (apply_request, reset_every_step),
}
actual = {name: diagnose(*functions) for name, functions in variants.items()}
expected = {"reference": [], "M_owner": ["P1"],
"M_rejection": ["P1", "P2", "P4"],
"M_double": ["P3", "P4"], "M_reset": ["P4"]}
if actual != expected:
raise AssertionError((actual, expected))
return actual
if __name__ == "__main__":
for name, failures in run_experiment().items():
print(name + ": " + (", ".join(failures) if failures else "none"))
If you choose to execute it, keep the reference and companion files together and run python3 blockchain_state_debug_lab.py in that folder or using the actual path. It uses the local reference module and Python's standard library. No credentials, endpoint, wallet or network connection is required.
During preparation, the companion completed under Python 3.12.14 and printed reference: none; M_owner: P1; M_rejection: P1, P2, P4; M_double: P3, P4; M_reset: P4. These are failed probes for deliberately faulty variants, not an unsuccessful reference release.
The internal matrix assertion matching is distinct from all variants passing all probes. The experiment is successful when reference matches and the intended faults are detected in their expected ways. Calling every red mutant cell a problem to suppress would misunderstand the task.
Record your own source versions, runtime, command and output if you actually run it. If you only inspect code, label it code reading and prediction. The published run is evidence of the preparation workflow, not a claim that your device executed anything. A missing-module error, syntax error and mismatching probe output are also different observations; diagnose the appropriate layer before editing the acceptance rule.
python3 blockchain_state_debug_lab.py
Use eight fields: question, reference contract, fixture, expected result, actual result, first violated relationship, repair target and retest. For the M_owner example, the question is whether owner equality is preserved by the candidate transition. The fixture is S with B/2/True.
Expected is rejection for owner with unchanged S. Actual is acceptance with A/3/True. The first violated relationship is caller equal to current owner, and the repair target is the omitted owner condition before a successful update. Retest P1 and the reference acceptance, rejection and replay suite after any actual repair.
Add source and assistance labels. This is a worked diagnosis from the supplied deliberately faulty code, not a discovery about a live system. If a model explanation supplied the root cause, record that support before attempting a fresh case independently.
Do not overwrite the failed observation after correction. Preserve it with the experimental variant's identity, then append the repaired version's result. A regression notebook should explain the change from mismatch to expected behaviour. It should not become a polished history in which the original error disappears and a later reader cannot tell what the test was intended to prevent.
| Regression field | Worked M_owner / P1 entry |
|---|---|
| Question | Does candidate preserve owner equality? |
| Contract | Caller must equal owner |
| Fixture | S=A/2/False; B/2/True request |
| Expected | Reject owner; after S |
| Actual | Accepted; after A/3/True |
| Violated relation | Caller B != owner A |
| Repair target | Restore owner condition |
| Retest plan | P1 plus reference acceptance, rejection and replay suite |
CHAPTER 12 OF 20 · Learn and check
12. Use the earliest divergent state as a repair anchor
For M_rejection's P4, the first accepted step matches. The earliest wrong after-state appears after T2, where reference preserves revision 3 but the variant advances it to 4. T3's new revision failure follows from that earlier divergence.
For M_double, the first step already diverges to revision 4. For M_reset, the second step's before-state is wrong because it returns to S rather than using A/3/True. Different variants have different first divergences even when they share a failing P4 cell.
This comparison helps separate symptoms from their demonstrated dependency. A later wrong final state is important, but its cause may be an earlier update or input linkage. Trace before, request and after at each step before deciding which branch to change.
The method is local and evidence-led, not a guarantee that every software defect has one simple cause. In a larger system, missing observations can leave the earliest divergence unknown. Then the notebook should request the missing evidence rather than invent it. Here the complete offline traces make the selected relationships inspectable, providing a controlled practice setting before you study more complex infrastructure or incident evidence.
CHAPTER 13 OF 20 · Learn and check
13. Do not repair the expectation to hide a fault
If a candidate accepts B against owner A, changing P1 to expect acceptance changes the contract. That may be a deliberate new policy, but it is not a repair under the original rule. Label the new requirement, assess its consequences and preserve the old failure.
Similarly, replacing P4 with three independent tests would remove the sequential requirement rather than fix the replay. Dropping after-state comparisons would hide the rejection-increment fault. A shorter test suite is not automatically a clearer one if it discards the relationship that matters.
Before editing an expectation, ask whether the written contract changed or whether the candidate violated it. If the contract is ambiguous, record the ambiguity and resolve it explicitly. In this supplied exercise, the relevant rules are complete, so the expected results can be derived without guessing.
The specification-reading guide helps preserve requirement strength and conditions. The governance notebook helps distinguish a changed decision, an artifact and an observed run. Those wider methods support this local debugging discipline: a changed requirement, a changed implementation and a matching observation are different objects that must be connected, not treated as one label called fixed.
A repaired owner condition should be checked against P1 and valid-owner success, then the wider suite. A repaired rejection update should be checked for unchanged rejected state and sequential consequences. A corrected increment should preserve permission checks while restoring the exact successful update.
For replay linkage, retest complete before-after chains, final state and the empty sequence. The single-request transition may remain unchanged, but the calling loop's behaviour has changed. The retest plan should identify that scope rather than assume one green example covers every affected relationship.
The reference programme's twelve methods provide a broader local set than P1–P4, including field validation, reporting priority, input preservation and changed owner. Run them on an actual repaired reference-compatible implementation when that is your task. This article's supplied companion retains its deliberately faulty functions and does not pretend to be a patched production release.
Keep the baseline result, proposed change and later observation separate. “This retest would be required” is different from “This retest was executed.” Record only work actually performed. A clear plan is useful, but it should not be presented as successful execution evidence before the programme and tests have really been run in the identified environment.
| Change | Targeted checks | Keep visible |
|---|---|---|
| Owner predicate | P1 and valid-owner success | Full reference suite |
| Rejection update | Rejected after == before | Sequential effects |
| Successful increment | Exactly +1 | Permission rejections |
| Replay linkage | Before/after chain and empty sequence | Single-step behaviour |
CHAPTER 15 OF 20 · Learn and check
15. Recognise what the matrix does not establish
The four probes use a small set of well-formed State and Request objects. They do not test every malformed object, every long sequence, concurrency, persistence, network behaviour, cryptography or real authorisation infrastructure. Their matrix cannot support those missing claims.
Passing P1 does not establish all permission cases. Passing P4 does not prove every replay length or ordering. Detecting M_owner does not show that every omitted condition would be noticed. An untested defect can remain invisible, and different faults can share the same observed failure set.
Report this positively and precisely: the experiment distinguishes the supplied controlled variants through the stated probes. Keep the reference suite and additional questions visible rather than calling the small matrix a complete audit. Reading a Blockchain Audit Packet: Code Versions, Proof Scope and Upgrade Authority provides a technical route for assurance scope, while the security paper lab supports controlled threat and permission reasoning.
A useful notebook has an untested or unresolved column. It prevents the desire to finish the project from converting absent evidence into a pass. This is the same discipline used throughout the learning series: preserve what the evidence supports, name the missing connection and choose the next bounded task without inflating a local success into a universal result.
Use the separate companion file and its named variant functions. The reference remains intact, so a reader can return to the baseline without reconstructing overwritten code. The label deliberately faulty should remain visible wherever a variant is presented or stored.
These experiments are safe in scope because they are local synthetic functions with no external effects, not because any mutation activity is automatically appropriate. Do not use this guide as authority to alter a live service, weaken a control or test someone else's system. Such actions are outside this article's task.
Avoid real personal data, keys and account information in the notebook. The supplied A and B identifiers are sufficient. The programme's Boolean authenticity is not a request to collect or validate real identity documents, and the published field is not permission to send a real message.
Keep file identity, function identity, contract version and run result together. If a later reader sees only M_reset's output without its experimental role, they could mistake the fault demonstration for a recommended replay implementation. Good naming and retained context protect the meaning of the learning artifact as well as making your own next session easier to resume.
CHAPTER 17 OF 20 · Learn and check
17. Explain the diagnosis in English and Chinese
Preserve P1–P4, S, the field values and the first-failure order in both languages. Translate the reasoning, not the fixture. Rejection must not become a malformed object, and authentic True must not become a computed signature result merely because the explanation uses a broad everyday word.
A compact bilingual distinction is that a correct decision flag can coexist with an incorrect after-state: 接受或拒绝标记正确,不代表后态正确. M_rejection supplies the example. Another is that a correct single-step function can coexist with wrong replay linkage: 单步正确,不代表顺序连接正确. M_reset supplies that contrast.
Ask the learner to explain the earliest divergence and the rule it violates without copying the model. If they only name the variant or a red cell, request the before-state, request and expected after-state. This turns a memorised pattern into a relationship that can be checked.
The teach-back and portfolio guides provide methods for recording assistance and fresh attempts. Use the actual work completed, not another lesson's fictional score. Two language versions of the same source are learning aids, not independent factual proofs or separate execution observations. Keep the programme identity and run evidence stable across both explanations.
Use five categories worth two points each: reproduce the complete fixture; preserve the reference expectation; identify the earliest violated relationship; propose a targeted repair and justified retest; and state evidence limits. Award two for all relationships correct, one for partial understanding and zero for absence or contradiction.
A learner who lists the matrix correctly but cannot explain why P4 fails should not receive full diagnosis credit. A learner who changes P1 to accept B instead of restoring the owner condition loses expectation credit under the original contract. A learner who proposes a good retest but calls it already executed loses evidence credit.
This is a local educational assessment, not a security qualification or certification of debugging expertise. The companion's expected matrix assertion is a check of the exercise, not the learner's personal mastery score. Record what the learner actually predicted, inspected, ran or repaired.
Save the first diagnosis and a fresh variation after any assisted correction. For example, ask which probe would notice a wrong successful increment before showing M_double. If the connection transfers, record that bounded result. If not, return to the relevant transition or replay relationship instead of adding more variants simply to increase the apparent difficulty.
If the expected state is unclear, return to the simulator and the earlier state-replay guide. If field validity and permission are mixed, revisit the specification notebook and the model's constructors. If a test result is inflated into live assurance, use the application comparison and infrastructure evidence guides.
For real execution concepts, the technical routes From User Intent to Transaction Evidence: Construct, Authorize and Execute, Smart Contracts as State Machines: Check the Caller, Conditions and Limits and Diagnosing Failed Blockchain Transactions: Rejection, Revert and Call Boundaries keep their own conditions. For permission and displayed information, Token Approvals: Track Remaining Permission in an Allowance Ledger and Blockchain Confirmation Screens: Compare Displayed Intent with Signed Authority offer different evidence questions. Do not import their examples as hidden behaviour in this tiny programme.
The earlier offline data project remains useful for representation failures. A wrong hexadecimal interpretation is not the same as a wrong state transition, and a missing local module is not either algorithmic defect. The notebook should classify the observation before selecting a repair source.
Write one next task and one stopping point. You might independently predict a new probe, complete a reference-compatible repair in a separate copy or explain a changed initial owner. A well-defined continuation is more useful than indefinitely rereading all the linked material. The wider library supplies routes; the regression notebook preserves the exact relationship that your next task needs to test.
CHAPTER 20 OF 20 · Learn and check
20. Finish with a reproducible diagnostic statement
A model conclusion is: “Under the supplied offline probes, reference has no mismatches; M_owner fails P1, M_rejection fails P1/P2/P4, M_double fails P3/P4 and M_reset fails P4. The companion produced that matrix under Python 3.12.14 during preparation. These are deliberately faulty local variants, not live blockchain findings or proof of complete test coverage.”
For your own notebook, distinguish the published observation from your actual activity. Code reading, prediction, local execution and a separately implemented repair are different outputs. Keep the source versions and complete expectations so another reader can reproduce whichever result you report.
Attach the full reference, complete companion, probe definitions, failure trace, repair plan and run record. A reader can then follow a red cell to a violated rule and a specific next check. That is a strong learning outcome even though the experiment is deliberately small.
Return to the learning hub when another connection needs attention. Blockchain understanding grows through relationships you can explain and test under stated conditions. A regression notebook helps preserve those relationships across errors, corrections and later study, while keeping every claim tied to the evidence actually available.
Continue learning
Sources and scope
The note-state rules, fixtures, diagnostic variants and educational rubrics are original offline teaching exercises. Authenticity is a supplied Boolean, not computed verification. The programs are not blockchain implementations, audits or production patches. Linked technical articles retain their own examples and conditions. Sources and published routes checked on 15 October 2026. Reading and paper practice do not certify implementation competence.
