Skip to content

fabricx: VersionKeeper resets on restart — endorser permanently fails with MVCC conflicts after any on-chain PP update #2255

Description

@tinystone007

Summary

token/services/network/fabricx/pp/versionkeeper.go models the public-parameters version as an in-process counter, and the first UpdateVersion() call is treated as initialization (no increment). Verified present on main as of 2026-08-18.

Every token transaction the endorser translates attaches a versioned read of the setup hash key (token/services/network/fabricx/endorsement/rwset.go, AddReadAt(MarshalVersion(ppVersion))). So the effective value is keeper = V_now − V_at_process_start: correct only for processes started when the chain's setup key was still at version 0.

Effect

Once the on-chain public parameters have been updated at least once (setup key row version ≥ 1), any endorser that (re)starts afterwards is permanently broken: its first lookup-poll observation counts as "initialization", the counter stays behind by exactly the number of updates it did not witness, and every transaction it endorses is rejected with ABORTED_MVCC_CONFLICT. There is no operational recovery — further PP updates keep the delta constant.

Reproduction (live, Fabric-X 4-party network)

  1. Deploy PP v_next on-chain (tokengen update output, setup key row 0→1). Running endorsers observe the change live and keep working (counter = 1, matches).
  2. Restart one endorser. Its next endorsed transaction lands on-chain with status ABORTED_MVCC_CONFLICT, while an endorser that was not restarted commits the identical transfer fine.
  3. No sequence of restarts/redeploys recovers the restarted endorser.

Suggested fix

Initialize VersionKeeper from the actual on-chain row version of the setup key (available via the query service) instead of counting observations from process start.

Related: the PP deployment transaction in tms/deployer.go hardcodes NsVersion: 0 (filed separately) — same family of "version assumed to be 0 forever" issues that only surface once a chain has history.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions