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.

Hyperledger Fabric Transaction Flow: Endorsement, Ordering and the Update That Does Not Apply

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 · Article BC045

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.

In Hyperledger Fabric, successful endorsement does not reserve the state that a proposal read. Ordering a transaction into a block does not guarantee that its proposed writes will update the current state. Peers still validate the transaction, including applicable endorsement requirements and read-version checks.

This separation explains a result that can otherwise look contradictory: two proposals simulate successfully against the same available quantity, both collect the required endorsements, and both appear in the ordered history, yet only one changes that quantity.

The lesson follows that result through a small fictional record system. The focus is the responsibility of each stage and the evidence an application needs before reporting success.

Choose your reading route

In this guide

Read the role map and the starting record versions. Follow T and U through simulation, then validate the ordered block one transaction at a time. Compare the reversed-order and missing-endorsement variations before attempting the exercises.

We use the Fabric release-2.5 documentation as a named reference and choose its Raft ordering service for the fictional deployment. This is not a description of every Fabric version or ordering implementation. There are no live identities, certificates, network changes or transactions in the exercise.

All quantities are invented application counters. A reservation in this ledger is a software record, not proof that a real item exists, a legal entitlement has transferred or a physical delivery has occurred.

Back to contents · Next section

1. Four responsibilities in one workflow

A client expresses an intended operation. Endorsing peers simulate the relevant chaincode operation and sign the resulting proposal response. The ordering service establishes an order and packages transactions into blocks. Committing peers validate transactions and apply valid write sets to current state.

The Fabric transaction-flow documentation separates simulation from the later ledger update. Its described workflow also includes a gateway or target peer coordinating the required responses and submission.

These are responsibilities, not necessarily four independent organisations. A peer can have both endorsement and commitment duties. An operator can control several components. A useful architecture diagram labels who performs each job and who controls the software carrying it out.

For our example, the coordinating application path is already functioning. We do not reproduce SDK calls. What matters is that each endorsement binds to the relevant simulated result, and later stages do not turn that result into an unconditional promise of application success.

Back to contents · Next section

2. Identity and policy supply different checks

Our channel is ArchiveChannel. Two fictional organisations, A and B, have properly configured membership information and authorised participants. The supplied endorsement policy requires valid endorsements from an eligible peer of A and an eligible peer of B on the matching result.

The Membership Service Provider documentation explains how configured membership information supports identity validation and organisational roles. Identity evidence must then be interpreted under the relevant policies; a recognised identity is not automatically authorised for every action.

For this worksheet, the policy is fixed throughout. There are no key-level policy overrides, private-data collection policies, configuration changes or certificate-status changes during the trace. Application authorisation checks also pass unless a variation says otherwise.

This explicit scope matters. “It has two signatures” is not enough: two signatures from A would not meet our A-and-B requirement. Nor would one signature on one simulation result and another signature on a different result constitute the matching endorsement packet assumed here.

Back to contents · Next section

3. Values and versions at the starting point

The relevant public world state has two keys in one chaincode namespace. K records available classroom booking units; H is an independent administrative counter.

  • K has value 5 and version (20,0).
  • H has value 10 and version (19,1).

Versions here use the pair of block number and transaction position. Positions are zero-based in this exercise. The pairs identify the committed updates that last modified the keys; they are not application quantities or a count of proposals that someone tried.

For example, K=5 does not imply its version is 5. Two keys can have the same value but different versions. A later valid write can leave a value numerically unchanged while still producing a new version.

The Fabric ledger documentation distinguishes the current world state from the transaction history. Our worksheet will need both: the history records what was ordered and validated, while current state tells us which valid writes are reflected now.

Back to contents · Next section

4. Simulate two competing reservations

The fictional Reserve(amount) operation first reads K, checks that its current value is at least amount, and proposes writing K minus amount. The amount must be a positive integer. All other program conditions are supplied as satisfied.

T requests 2 units. Its simulation reads K=5 at version (20,0), passes the check and produces a proposed write K=3. U requests 4 units, independently reads the same committed K=5 at version (20,0), passes and produces a proposed write K=1.

Both simulations happen before either update is committed. Both A and B return matching endorsements for each proposal. That does not mean six units have been reserved from a stock of five: no proposed application write has yet been applied.

The question is not whether 5−2 and 5−4 were calculated correctly. Both were. The question is whether each calculation’s read dependency still holds when the ordered transaction reaches validation.

Back to contents · Next section

5. Read sets remember versions, write sets carry proposed values

For T, the relevant read set contains K at version (20,0), and the write set contains K=3. For U, the read dependency is the same, but its write set contains K=1.

The Fabric read-write set documentation explains that the read set records committed key versions, while the write set records proposed new values. Validation takes preceding valid transactions into account, including preceding transactions within the same block.

Do not confuse the evidence carried by the read set with the value used during simulation. The program read value 5 to calculate its result; the relevant concurrency check records the version of that read. The worksheet omits range queries and other query semantics so that this single-key dependency stays visible.

The read is essential. Our operation deliberately reads K before writing it. This lesson does not claim that every pair of writes to a key is automatically rejected merely because both mention the same key; the actual read dependencies and validation rules determine that outcome.

Back to contents · Next section

6. Add an independent proposal

V reads H=10 at version (19,1) and proposes H=11. It obtains the same required A-and-B matching endorsements. V does not read or write K, and neither T nor U reads or writes H.

The three packets now exist: T proposes K=3, U proposes K=1, and V proposes H=11. Their signatures, identities and other validity requirements are supplied as correct in the main case.

Including V makes the trace more informative than saying “the second transaction always fails”. A transaction later in the block can remain valid if its own dependencies are unchanged. Position alone is not the failure condition.

It also separates conflict from general service failure. U’s stale read does not mean the whole block must be discarded or that an unrelated H update must stop. The validation result belongs to the relevant transaction.

Back to contents · Next section

7. Ordering fixes a sequence, not successful application

The ordering service produces block 21 containing T at position 0, U at position 1 and V at position 2. This is a supplied outcome. We do not infer it from which client clicked first or whose proposal reached one server first.

The Fabric ordering-service documentation distinguishes ordering from peer-side transaction validation. For ordinary application transactions, the orderer does not re-run the chaincode to decide whether each proposed application update remains valid.

The fictional service uses the release-2.5 Raft option, with crash-fault assumptions and the required functioning quorum and communication conditions supplied. Raft is not being presented as Byzantine-fault tolerance, and membership permissioning does not remove the need to state fault assumptions.

This lesson assumes a correctly agreed block order under those conditions. It does not claim that any response from an orderer, or any arbitrary failure pattern, guarantees successful delivery and application of a transaction.

Back to contents · Next section

8. Validate block 21 from left to right

T is first. Its required endorsements pass, and K still has version (20,0). Its read dependency matches. T is valid, so its write makes K=3 with version (21,0).

U is next. Its endorsements still pass, but its read set expects K at (20,0). The valid preceding T has advanced K’s version to (21,0). U therefore fails the read-version check. Its proposed K=1 is not applied, and it does not create a new version for K.

V follows. H still has version (19,1), because the other two packets did not change it. V passes its relevant checks and writes H=11 with version (21,2).

After the block, current state is K=3 at (21,0) and H=11 at (21,2). The per-transaction results are valid, invalid, valid. The version of H includes position 2 even though only two transactions in the block applied writes; transaction position is not renumbered to count only successful transactions.

Back to contents · Next section

9. Why the invalid transaction remains visible

U remains in the ordered block, accompanied by its invalid validation result. That historical presence is different from application-state success. A reader who finds U’s identifier in the block has not yet proved that K became 1.

This distinction is supported by the release-2.5 ordering documentation’s account of peer validation: invalid transactions remain in the block history but do not update ledger state. The history can therefore explain the unsuccessful attempt without pretending it consumed booking units.

A useful application report should say which status it actually observed. “Proposal endorsed”, “submitted”, “included in ordered block” and “committed with valid status” are different milestones. The first three cannot stand in for the last.

Even a valid ledger update has limited meaning. It proves the configured system accepted the software operation under its rules and assumptions; it does not make a classroom counter into independent evidence about physical inventory.

Back to contents · Next section

10. Reverse the order and recompute

Return to the original state and the same independently simulated packets. In a separate variation, block 21 orders U first, T second and V third. This is an alternative history for comparison, not a reorganisation of the completed main case.

U now finds the expected K version and applies K=1 at (21,0). T then encounters the changed version and is invalid; its proposed K=3 is not applied. V remains valid and updates H to 11 at (21,2).

The final K value is 1 rather than 3. Both outcomes are understandable once the chosen order is known. Endorsements alone did not decide which reservation would take effect.

Notice that no peer needs to “repair” T by silently calculating a different result during commitment. The packet contains a particular endorsed simulation result. Changing the operation’s input state and result calls for a fresh proposal path, not rewriting the meaning of the old endorsements.

Back to contents · Next section

11. A failed endorsement requirement changes the trace

Return again to the original state and order T, U, V. This time suppose T lacks B’s required endorsement, while U and V retain their valid A-and-B packets. Assume the deficient T packet nevertheless reaches the ordered block.

T fails the applicable endorsement requirement and does not update K. U then sees K still at (20,0), so its read-version check can pass. Under the other supplied conditions, U applies K=1 at version (21,1). V still applies H=11 at (21,2).

This variation shows why validation must distinguish failure reasons. In the main case, T was valid and made U stale. Here T is invalid and leaves K unchanged, allowing U’s old read dependency to remain current.

The Fabric endorsement-policy documentation makes endorsement checks a validation responsibility. Our fixed A-and-B example avoids the more elaborate policy combinations a real deployment may use.

Back to contents · Next section

12. Retrying requires a new decision

After the main case, K=3. If U’s user still requests 4 units, a fresh simulation reads 3 and fails the program’s availability condition. Collecting newer evidence cannot make 3 sufficient for a request of 4.

If an authorised user instead chooses a new request for 1 unit, a new proposal can read K=3 at (21,0) and propose K=2. Suppose it obtains the required endorsements and is the next valid update at block 22 position 0, with no intervening change. Then K becomes 2 at (22,0).

Those are different user decisions and different proposal contexts. An application should not silently reduce the requested amount simply to make a retry succeed. Nor should it claim success merely because it resubmitted bytes or received an acknowledgement.

Before deciding what to do, distinguish a known invalid status from an unknown outcome after a timeout. A missing response alone does not prove the original operation failed. This worksheet does not prescribe a production retry algorithm; it teaches why outcome checking and intent preservation matter.

Back to contents · Next section

13. Same value does not mean same version

Consider another separate variation before T is validated. A valid intervening transaction reads K=5 and writes K=5 again, producing a newer version. The value did not change, but T’s old read-version dependency no longer matches.

Under the supplied version-check rule, T can fail even though re-reading the displayed value would still show 5. The check concerns the committed version observed during simulation, not a comparison of the old and new numbers alone.

That result is not an arithmetic error. It is the consequence of the chosen concurrency-control evidence. A diagnosis saying “there was no change because the number is still five” would miss the intervening valid update.

When investigating a stale proposal, retain the version and block context alongside the value. A latest-state screen showing only a number is too weak to reconstruct which dependency the proposal actually used.

Back to contents · Next section

14. Exercise: report what really happened

Use the main case unless a question names a variation. All unspecified validity conditions pass.

  1. Both T and U have A-and-B endorsements before ordering. Has K already decreased?
  2. After main block 21, which K value and version are current?
  3. Why does V use version (21,2) rather than (21,1)?
  4. In the missing-B-endorsement variation, why can U become valid?
  5. If the old U packet is found in the main block, may the application report a successful four-unit reservation?
  6. In a fresh request after the main case, can the original four-unit intention succeed merely by obtaining new endorsements?
  7. If an intervening valid update writes K=5 again under a new version, does equality of the value preserve T’s old read dependency?

Answers and reasoning

  1. No. Endorsement simulation has produced signed proposed results; it has not applied those writes to current state. K remains 5 at the stated starting version until a valid update is committed.

2. K=3 at (21,0). T applied; U was invalid and did not apply its proposed K=1. H separately becomes 11 at (21,2).

3. V occupies position 2 in the ordered block. Invalid U still occupies position 1. Versions use the committing transaction’s position rather than a compressed index of successful updates.

4. T’s invalid endorsement result means T does not change K. U’s expected version (20,0) therefore still matches, allowing U to apply at position 1 under the supplied conditions.

5. No. U’s block presence must be read with its invalid status. It records the attempt, not successful application of its write set.

6. No. The new simulation sees only 3 available and the specified program rejects a request for 4. Changing the requested amount would require a new authorised intention.

7. No. The version changed even though the value did not. The old read-version dependency is stale under the given rule.

Back to contents · Next section

15. Frequently asked questions

Do committing peers simply re-run every proposal on the newest state?

That is not the workflow model taught here. Peers validate the endorsed result and its dependencies, then apply valid write sets. A stale endorsed result does not become a different operation merely because its original result no longer applies.

Does permissioned membership guarantee honest participants?

No. It identifies participants under configured rules. The deployment still needs explicit policies, fault assumptions and administrative controls. Our selected Raft ordering model is crash-fault tolerant, not a blanket guarantee against malicious ordering nodes.

Does an invalid transaction erase the whole block?

Not in this trace. U receives an invalid transaction status and does not update world state; the block history retains it, while valid T and V apply their writes.

Back to contents · Next section

Sources and next reading

Primary sources checked on 12 October 2026, Singapore time, using the Fabric release-2.5 documentation route:

  • Transaction flow: proposal simulation, endorsement and later commitment responsibilities.
  • Read-write set semantics: read versions, proposed write values and validation against preceding valid updates. The exercise uses direct key reads, not range or rich queries.
  • The ordering service: separation of ordering and peer validation, invalid transaction retention, and the selected Raft crash-fault model. Broad comparative or unconditional finality language is not needed for this lesson.
  • Endorsement policies: applicable endorsement requirements and their validation. Our policy remains fixed and has no overrides.
  • Membership Service Provider: configured identity and organisational membership concepts.
  • Ledger: current world state and transaction history as distinct views.

Review the earlier trust-model and transaction-evidence lessons if identity, policy or status reporting is unfamiliar. The next lesson compares attached-chain designs by the location of execution, data, finality and exit authority, rather than accepting a category label as a security guarantee.

Back to contents