Skip to content

fix(fabricx): dynamically fetch namespace version for PP deployment - #2294

Open
SurbhiAgarwal1 wants to merge 1 commit into
LFDT-Panurus:mainfrom
SurbhiAgarwal1:fix/2256-pp-deployer-nsversion
Open

SurbhiAgarwal1 wants to merge 1 commit into
LFDT-Panurus:mainfrom
SurbhiAgarwal1:fix/2256-pp-deployer-nsversion

Conversation

@SurbhiAgarwal1

Copy link
Copy Markdown
Contributor

Summary

This PR fixes a bug in token/services/network/fabricx/tms/deployer.go where the public-parameters deployment transaction was hardcoding NsVersion: 0. This caused deployment transactions to be invalidated by the committer on chains where the token namespace endorsement policy had been updated at least once (e.g., after adding a new endorsing organization).

Fix Details

  • Modified PublicParametersService to implement a new FetchNamespaceVersion function which dynamically queries the current namespace version.
  • Updated deployPublicParametersRaw to query and fetch the namespace's current version before building the deployment transaction.
  • Passed the dynamically fetched nsVersion into createPublicParametersTx instead of hardcoding 0.
  • Added a fallback to default to 0 if the version cannot be fetched, ensuring backward compatibility.
  • Added comprehensive unit tests in deployer_test.go to ensure NsVersion is properly populated dynamically.

Fixes #2256

@SurbhiAgarwal1
SurbhiAgarwal1 force-pushed the fix/2256-pp-deployer-nsversion branch from 7cd8203 to 0230bc9 Compare August 23, 2026 08:32

@AkramBitar AkramBitar left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SurbhiAgarwal1,

Thanks for taking this on — fetching the real namespace version is the right fix for #2256, and the code reads cleanly.

My main concern is that the version can still silently end up as 0, which is exactly the bug being fixed:

  1. Two silent fallbacks to 0 — a failed type assertion and a swallowed fetch error (deployer.go:126, :130). Either one reproduces #2256 with no diagnostics.
  2. The test doesn't cover the fix — it never calls deployPublicParametersRaw, so reverting the change leaves it green.
  3. A second source of truth for NsVersion — GetNamespacePolicies().Version here vs GetState("_meta", ns).Version everywhere else in the stack.

Details inline. 1 and 2 feel like blockers; 3 is worth a decision.

Comment thread token/services/network/fabricx/tms/deployer.go Outdated
Comment thread token/services/network/fabricx/tms/deployer.go
Comment thread token/services/network/fabricx/tms/deployer.go Outdated
Comment thread token/services/network/fabricx/tms/deployer_test.go Outdated
Comment thread token/services/network/fabricx/pp/service.go Outdated
Comment thread token/services/network/fabricx/pp/service.go Outdated
@SurbhiAgarwal1

Copy link
Copy Markdown
Contributor Author

Hi @AkramBitar, I've addressed all your feedback:

  1. Type assertion removed -ppFetcher is now *pp.PublicParametersService (concrete type), compiler guarantees FetchNamespaceVersion is always available, no silent fallback to 0
  2. Error no longer swallowed - deployPublicParametersRaw now returns the fetch error immediately
  3. Single source of truth - FetchNamespaceVersion uses qs.GetState("_meta", namespace) with protowire varint decoding, same as the fabricx vault marshaller
  4. Unregistered namespace - returns a clear error when _meta entry is missing
  5. TOCTOU retry -added a single retry that re-fetches the version and resubmits on failure
  6. Test fixed - now drives deployPublicParametersRaw through a stub Submitter and covers the error + retry cases. Reverting the fix fails the test.
  7. Dead guard removed -if policies != nil removed

Thanks for the thorough review!

@SurbhiAgarwal1
SurbhiAgarwal1 force-pushed the fix/2256-pp-deployer-nsversion branch from 46b776d to 2ee36a4 Compare August 31, 2026 18:46
@Effi-S
Effi-S self-requested a review September 9, 2026 08:50
Comment thread token/services/network/fabricx/tms/deployer_test.go Outdated
// derive NsVersion for ordinary token transactions — a single source of truth.
//
// Returns an error when the namespace has no "_meta" entry so a misconfigured or
// unregistered namespace is surfaced at deploy time rather than silently submitting

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: godoc was not updated to reflect latest changes

Comment thread token/services/network/fabricx/tms/deployer.go
// Version bytes are encoded as a protobuf varint — same as UnmarshalVersion in
// platform/fabricx/core/vault/marshal.go.
version, _ := protowire.ConsumeVarint(value.Version)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should Check the returned length < 0 and surface an error.

Copilot AI lite review requested due to automatic review settings September 15, 2026 09:55

This comment was marked as spam.

@SurbhiAgarwal1
SurbhiAgarwal1 force-pushed the fix/2256-pp-deployer-nsversion branch from a10f5fd to 6cec159 Compare September 15, 2026 10:18
@AkramBitar

Copy link
Copy Markdown
Contributor

Hello @SurbhiAgarwal1

Thanks a lot for all the efforts that you put in this PR.
Could you please have a look why these tests fails.
Also, did you have the chance to resolve all the above comments? Is that PR ready for additional review round?

Regards,
Akram

@SurbhiAgarwal1
SurbhiAgarwal1 force-pushed the fix/2256-pp-deployer-nsversion branch from 1af0ec6 to 0be5cd4 Compare September 25, 2026 07:23
@AkramBitar
AkramBitar force-pushed the fix/2256-pp-deployer-nsversion branch from 0be5cd4 to 03184c7 Compare September 28, 2026 04:20
@AkramBitar

Copy link
Copy Markdown
Contributor

Hello @SurbhiAgarwal1

Any update with this PR?

Regards,
Akram

@SurbhiAgarwal1

Copy link
Copy Markdown
Contributor Author

Hi @AkramBitar @Effi-S,

Apologies for the delay!

Yes, all previous review comments from @Effi-S have been addressed:

  1. Direct method testing: deployer_test.go now tests the actual production deployPublicParametersRaw method directly (the test shim was removed).
  2. Scoped retries: Submission retries are now strictly scoped to version mismatch / MVCC conflicts via isVersionMismatchError rather than transient errors, preventing duplicate submissions.
  3. Varint validation & Godoc: Added length validation (n < 0) when decoding the varint version in FetchNamespaceVersion, and updated the documentation.
  4. Base sync: The branch is up-to-date with main and all 210 CI checks are green.

The PR is ready for your review and approval. Thank you!

@AkramBitar AkramBitar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Four blockers from the previous two rounds are still open in the final commit 03184c7ab.

1. Test doesn't cover the fix — regression possible (Blocker)

The stubs (mockPPService, captureSubmitter, mockPPServiceFn) are so decoupled from the real pp.PublicParametersService that reverting FetchNamespaceVersion in deployer.go to return 0 keeps every test green. TestDeployPublicParametersRaw_UsesVersionFromFetcher drives the real deployPublicParametersRaw, which is good, but because the fetcher is a hand-rolled stub, there is no proof the real wiring works. The test needs to drive the real pp.PublicParametersService (backed by a stub query service returning a known _meta version) so that reverting the FetchNamespaceVersion call in the deployer actually breaks it.

2. isVersionMismatchError retries on non-version errors, risking duplicate PP submission (Blocker)

Effi-S's comment is unaddressed. The matcher includes "validation failed" and "invalidated" — strings broad enough to match transient submit errors. Submit blocks on finality and can return a timeout even when the tx already committed. Retrying in that case resubmits against an already-initialized namespace, causing a conflicting BlindWrite on the same keys. Scope the retry to version-mismatch/policy-epoch errors only — the narrowest strings that unambiguously identify a policy-epoch rejection.

3. protowire.ConsumeVarint negative-length check missing (Blocker)

Effi-S's comment (service.go:97) is unaddressed in the final diff. A malformed or truncated _meta version byte slice returns n < 0 from ConsumeVarint; the current code only checks n < 0 inside FetchNamespaceVersion — re-read the diff: the check if n < 0 is present in service.go, but Effi-S flagged that it should surface an error rather than silently returning 0. Verify the error path is wired and tested.

4. Two sources of truth for NsVersion — not resolved (Blocker)

The original review asked whether the implementation should use GetState("_meta", ns) (same key/encoding the fabricx vault marshaller uses for ordinary token txs) rather than GetNamespacePolicies. The final diff does use _meta in service.go, but neither the godoc nor the inline comment was updated to reflect that decision, and the thread was never acknowledged. Please confirm this is intentional and update the godoc in FetchNamespaceVersion to describe the _meta key and varint encoding explicitly.


Two open nits (not blockers):

  • (0, nil) for a namespace that was never registered on-chain is indistinguishable from a legitimate version-0 namespace — worth at least a Debugf so a misconfigured namespace surfaces at deploy time.
  • Godoc on FetchNamespaceVersion still references the old GetNamespacePolicies approach in places; needs a pass to match the implementation.

…FDT-Panurus#2256)

Signed-off-by: Surbhi Agarwal <SurbhiAgarwal1@users.noreply.github.com>
@SurbhiAgarwal1
SurbhiAgarwal1 force-pushed the fix/2256-pp-deployer-nsversion branch from 03184c7 to 3cdf12f Compare October 7, 2026 10:49
@SurbhiAgarwal1

Copy link
Copy Markdown
Contributor Author

Hi @AkramBitar @Effi-S,

I have addressed all four blockers and nits from the latest review round:

  1. Direct Wiring in Tests (Blocker 1): deployer_test.go now wires the real production *pp.PublicParametersService backed by a mock QueryService rather than decoupled stubs (mockPPService / mockPPServiceFn were removed). Reverting FetchNamespaceVersion to return 0 or bypassing it causes TestDeployPublicParametersRaw_UsesVersionFromFetcher to fail.
  2. Narrowed isVersionMismatchError (Blocker 2): Removed broad strings ("validation failed" and "invalidated"), scoping the matcher strictly to explicit version and policy epoch rejections ("version mismatch", "invalid version", "MVCC_READ_CONFLICT", "ABORTED_MVCC_CONFLICT", "policy epoch mismatch", "policy version mismatch"). Added a table test verifying that non-version errors (timeouts, committer invalidations, etc.) do not retry.
  3. Varint Error Return & Negative Length Tests (Blocker 3): Checked n < 0 from protowire.ConsumeVarint returning an explicit errors.Errorf. Added subtests in service_test.go covering both truncated varints (n = -1) and overflowing varints (n = -2).
  4. Godoc & Single Source of Truth (Blocker 4 & Nits): Updated FetchNamespaceVersion Godoc to describe the _meta key lookup and varint decoding matching the fabricx vault marshaller, removed references to GetNamespacePolicies, and added logger.Debugf when _meta is missing on initial deploy.
  5. Base Sync: Rebased cleanly on latest main with all merge conflicts resolved.

All tests, go vet, and golangci-lint pass cleanly. Thank you!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fabricx: PP deployment tx hardcodes NsVersion 0 — redeploy rejected once the namespace policy was ever updated

5 participants