Skip to content

docs(tokens): tokengen docs, fix curl_with_retry, partial xdev progress - #36

Closed
atharrva01 wants to merge 8 commits into
hyperledger:mainfrom
atharrva01:feature/issue-66-tokengen-docs-xdev-htlc
Closed

atharrva01 wants to merge 8 commits into
hyperledger:mainfrom
atharrva01:feature/issue-66-tokengen-docs-xdev-htlc

Conversation

@atharrva01

@atharrva01 atharrva01 commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes out three gaps flagged in issue #66's deliverables: tokengen documentation, a real bug in the e2e harness that was masking failures on every platform, and PLATFORM=xdev's e2e tests — which now pass end to end.

  • Tokengen docs: a new "Public parameters (tokengen)" section under Development — what go tool tokengen generates and why every TMS (and the fabric3 chaincode image) needs to agree on it byte-for-byte, that make setup already runs it automatically, how to inspect an existing parameters file, and when to regenerate by hand. Consolidates the one existing passing mention into a link to this section.
  • curl_with_retry never actually retried a failure: if CMD; then return 0; fi followed by local exit_code=$? always captured 0, not CMD's real exit code — bash resets $? to 0 for an if whose condition is false when no branch executes. Confirmed with an isolated repro before trusting it, then again against the real function with a stubbed curl. This means curl_with_retry has silently returned success after exhausting every retry since it was written, so every CI run using it (every platform) hasn't actually been asserting what it looks like it asserts. Fixed by capturing the exit code inside an explicit else, where $? still reflects the failed command.
  • Now that a fabricx CI failure would actually be visible, HTLC_TEST=1 is turned on for the fabricx matrix leg — the real, honest verification for whether HTLC works on Fabric-X, since that network can't be fully reproduced locally (ansible-provisioned infrastructure) the way fabric3 can.

PLATFORM=xdev: now passes end to end

Three config/version-drift bugs, fixed early on:

  1. configtx.yaml set Application.MetaNamespaceVerificationKeyPath, a field fabric-x-common removed in Feb 2026 (commit d03614c, PR #74, resolving fabric-x-common issue #58) in anticipation of a LifecycleEndorsementPolicy replacement that was never actually built. Confirmed via GitHub code search: the field exists nowhere in fabric-x/fabric-x-common, released or on main. configtxgen no longer errors with it removed; there's no replacement key to add.
  2. fxconfig's CLI changed from flags (--channel, --orderer, --mspID, --mspConfigPath, --pk) to a config file / FXCONFIG_* env vars entirely — the old flags don't exist anymore.
  3. compose-xdev.yml pinned the test-committer image at 0.1.7 while the Go module graph is already on fabric-x-committer v1.0.4 — the same version-drift class as the chaincode Dockerfile's Panurus commit pin fixed in the v0.22.0 bump. Bumped to match.

That got configtxgen/fxconfig namespace create working, but the app itself still couldn't reach a running network — reported here as an unroot-caused "orderer connection times out." It turned out to be two unrelated bugs, not one, and not an upstream gap:

  • The hand-rolled compose-xdev.yml test-committer had no TLS configured, while the committer image requires mTLS on committer-sidecar/committer-query-service and the mock orderer alike. Every connection was a plaintext client hitting a TLS listener.
  • Once TLS was fixed, FSC's generic broadcaster (platform/fabric/core/generic/ordering/bft.go) refused to submit anything at all: it hard-requires a 4-orderer BFT quorum, which a single mock orderer can never provide.

I'd filed fabric-x-common#202 believing LifecycleEndorsementPolicy was a missing upstream feature. That was wrong, and I'm correcting it separately: it's an ordinary Signature policy, same as classic Fabric. devnet/configtx.yaml already sets it exactly this way, and a clean make -C devnet init-namespace commits and lists the namespace with no upstream changes needed. Both real bugs were local.

Since both bugs are TLS/quorum-shaped and devnet/ already solves them correctly, this drops the hand-rolled compose-xdev.yml/configtx.yaml/crypto-config.yaml entirely and delegates PLATFORM=xdev's network lifecycle to devnet (../devnet), used unmodified via its own documented integration pattern, running its real 4-party Arma orderer instead of a single mock orderer.

Two further bugs surfaced once the network itself worked:

  • A genuine Panurus bug. endorser/service/fsc.go's Init() called DeployTMSs(), which (Panurus v0.18.0, token/services/network/fabricx/tms/deployer.go) fetches the public parameters it's about to deploy from the ledger itself — the same reader used to load an already-existing TMS. On a namespace that's never been initialized, that read returns nothing, and the deployer commits that nothing right back: a bootstrap that can never bootstrap. Confirmed directly against the committer (the setup key's hash matched sha256(""), not the real ~22KB parameters file), and confirmed no caller anywhere in Panurus's own code or tests exercises DeployTMSs/DeployTMS/DeployTMSWithPP, so this had never been exercised end to end before. Fixed by reading the parameters from the local file core.yaml already points at (token.tms.mytms.publicParameters.path) and calling DeployTMSWithPP directly.
  • FSC-native endorsement identity binding. The same mechanism fabric3 already needed (BindEndorsingIdentities in common/fsc.go) was never wired up for xdev: issuer/owner1/owner2 need a local copy of each endorser's Fabric identity under a matching MSP label for a response signed by that identity to be recognized as coming from the expected P2P party. Added.

PLATFORM=xdev HTLC_TEST=1 ./scripts/test.sh now passes end to end: issue, balance, transfer, transaction history (correct Pending→Confirmed transitions), redeem, and the full HTLC suite (lock, claim, timeout, reclaim, rejected-claim-after-reclaim) — the same assertions fabric3 already passes, all green.

Test plan

  • go build/go vet clean on both the default and fabricx build tags
  • curl_with_retry's fix verified both in an isolated repro and against the real function with a stubbed curl (returns the real failure code instead of silently succeeding)
  • Full clean PLATFORM=fabric3 ./scripts/test.sh passes end to end, including the HTLC block (regression check — nothing above touches fabric3's own path)
  • Full clean PLATFORM=xdev HTLC_TEST=1 ./scripts/test.sh passes end to end: issue/transfer/redeem/transaction-history/HTLC lock/claim/timeout/reclaim, every assertion green, reproduced from a clean make teardown clean + fresh make setup start

Adds a dedicated "Public parameters (tokengen)" section under
Development: what go tool tokengen generates and why every TMS (and the
fabric3 chaincode image) needs to agree on it, that make setup already
runs it automatically via scripts/gen_crypto.sh's gen_parameters(), how
to inspect an existing parameters file, and when you'd regenerate by
hand. Consolidates the one existing passing mention of the print
command into a link to this section instead of repeating it.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
`if CMD; then return 0; fi` followed by `local exit_code=$?` always
captured 0, not CMD's real exit code: bash resets $? to 0 for an `if`
whose condition is false when no branch executes, a different (and
realer) mechanism than it first looks like. Confirmed with an isolated
repro before trusting it, and confirmed again on the real function with
a stubbed curl. curl_with_retry has silently returned success after
exhausting every retry since it was written, which means every CI run
that uses it (every platform) has not actually been asserting what it
looks like it asserts.

Fixed by capturing the exit code inside an explicit `else`, where $?
still reflects the failed command.

Now that a fabricx CI failure would actually be visible, turn HTLC_TEST
on for the fabricx matrix leg -- the real, honest verification for
whether HTLC works on Fabric-X, since it can't be fully reproduced
locally (ansible-provisioned infrastructure) the way fabric3 and (once
a separate follow-up lands) xdev can.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
Not a complete fix -- xdev still doesn't reach a running network, see
below -- but three confirmed, independently-verified bugs are fixed
along the way, left in since each is correct on its own:

- configtx.yaml set Application.MetaNamespaceVerificationKeyPath, a
  field fabric-x-common removed in Feb 2026 (commit d03614c, PR #74,
  resolving fabric-x-common issue #58) in anticipation of a
  LifecycleEndorsementPolicy replacement that was never actually built.
  Confirmed via GitHub code search: the field exists nowhere in
  fabric-x/fabric-x-common, released or on main. configtxgen no longer
  errors with it removed; there is no replacement key.
- fxconfig's CLI interface changed from flags (--channel, --orderer,
  --mspID, --mspConfigPath, --pk) to a config file / FXCONFIG_* env
  vars entirely; the old flags don't exist anymore. fabricx_dev.mk's
  start-fabric target is rewritten against the current interface
  (namespace create --policy=... --endorse --submit). Verified this
  gets namespace creation to actually succeed against a live network.
- compose-xdev.yml pinned the test-committer image at 0.1.7 while the
  Go module graph is already on fabric-x-committer v1.0.4 -- the same
  version-drift class as the chaincode Dockerfile's Panurus commit pin
  fixed in the v0.22.0 bump. Bumped to match.

What's still broken, not yet root-caused: after the image bump, the
orderer connection on port 7050 now times out (context deadline
exceeded) even though the container's own logs show it listening
before fxconfig tries to connect -- possibly a TLS/mTLS requirement the
newer image has that the older one didn't. HTLC is deliberately NOT
enabled by default for xdev in test.sh yet; that's the next step once
this is resolved.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
The previous commit's "orderer connection times out" was never an upstream
gap - it was two bugs in the hand-rolled compose-xdev.yml setup:

- devnet's committer services require mTLS; compose-xdev.yml's test-committer
  had none configured, so every connection attempt failed with a plaintext/TLS
  protocol mismatch ("error reading server preface: EOF").
- Once TLS was fixed, FSC's generic broadcaster
  (platform/fabric/core/generic/ordering/bft.go) refused to submit at all: it
  requires a 4-orderer BFT quorum, which a single mock orderer can never
  provide.

fabric-x-common#202, filed against that commit, is wrong for the same reason:
LifecycleEndorsementPolicy is an ordinary Signature policy, not a missing
feature - devnet's own configtx.yaml sets it exactly this way, and a clean
`make -C devnet init-namespace` commits and lists the namespace with no
upstream changes needed.

This replaces the hand-rolled network with devnet (../devnet) itself, used
unmodified via its own documented integration pattern (fabricx_dev.mk calls
`make -C devnet init/start/stop`), running its real 4-party Arma orderer
instead of the single-container dev mode. Every node's core.yaml gets
devnet's TLS material and the per-endpoint tls: blocks the fabricx driver's
notificationService/queryService actually read on this pre-v0.22.0 branch,
plus channel: arma -> mychannel to match devnet's genesis.

Also wires up FSC-native endorsement for xdev: issuer/main.go's and
owner/main.go's existing BindEndorsingIdentities call (the same mechanism
fabric3 already uses) needs a local copy of each endorser's Fabric identity
under a matching MSP label, which xdev never had.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
…not the ledger

endorser/service/fsc.go's Init() called DeployTMSs(), which (Panurus v0.18.0,
token/services/network/fabricx/tms/deployer.go) fetches the parameters to
deploy from the ledger itself - the same reader used to load an *existing*
TMS. On a namespace that's never been initialized that read returns nothing,
and the deployer commits that nothing right back: a bootstrap that can never
bootstrap. Confirmed directly against the committer: the setup key's hash
matched sha256(""), not the real 22KB parameters file.

No caller anywhere in Panurus's own code or tests exercises DeployTMSs/
DeployTMS/DeployTMSWithPP, so this had never been exercised end to end
before.

Fixed by reading the public parameters from the local file core.yaml's
token.tms.mytms.publicParameters.path already points at - that key's own
comment says as much ("The endorser has the public parameters so it can
commit them to the ledger") - and calling DeployTMSWithPP directly.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
tms_channel() still returned "arma", the hand-rolled xdev setup's channel
name before the previous commits moved it to devnet's "mychannel". Caused
every HTLC request's tmsId to target a channel that no longer exists.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
…x job

cp_fabricx.sh was shared by both PLATFORM=fabricx (the Ansible-driven
network CI actually runs) and the old hand-rolled PLATFORM=xdev. The
devnet migration rewrote its body for devnet's crypto layout (User1
identities, TLS client certs, endorser1/endorser2 msps) and changed its
default CRYPTO_DIR to ../devnet/crypto, breaking it for fabricx_ansible.mk,
which calls the same script with no override and still needs the
original ansible-fetched layout (endorser@org1.example.com,
channel_admin@org1.example.com, under ./out/control-node/.../crypto).

CI failed on exactly this:
  cp: cannot stat '../devnet/crypto/.../User1@org1.example.com/msp'

Split the script in two: cp_fabricx.sh is restored verbatim to its
pre-xdev form for fabricx_ansible.mk, and the devnet-specific logic
moves to a new cp_xdev.sh, which fabricx_dev.mk now calls instead.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
…bricx

conf/ is used by both PLATFORM=fabricx (the real Ansible-driven network)
and PLATFORM=xdev (devnet). The earlier devnet migration edited the shared
conf/*/core.yaml files for devnet's needs (TLS on, channel "mychannel",
endorser1-endorsing/endorser2-endorsing MSP entries) without noticing
fabricx needed the original content (TLS off, channel "arma") - and I
compounded that by restoring conf/*/core.yaml from the repo's very first
commit (bd7d1bb) instead of the last commit before the devnet migration
(d9ed16b), skipping two intermediate fixes to the queryService config
schema. That stale schema crashed every app container:

  unmarshal queryService: '' expected a map or struct, got "slice"

Fixed by restoring conf/*/core.yaml from the correct commit (byte-identical
to PR#30's last merged state, confirmed with a diff) and giving xdev its
own conf-xdev/ - mirroring fabric3.mk's existing conf-f3/ - instead of
overloading conf/. fabricx_dev.mk now points CONF_ROOT at conf-xdev.

Also fixed in endorser/service/fsc.go: Init() hardcoded the TMS channel to
"mychannel" (devnet's name), which broke bootstrapping on the real fabricx
network (channel "arma"). It now reads network/channel/namespace from
core.yaml's token.tms block, so the same binary works on both platforms.

Verified locally: PLATFORM=fabricx comes up with every app container
healthy and /readyz responding ok, confirmed via two from-scratch
teardown+clean+setup+start cycles.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
@atharrva01

Copy link
Copy Markdown
Contributor Author

Splitting this into two focused PRs — it bundled three unrelated changes (docs, a test-harness bug fix, and the xdev devnet migration), which made it harder to review and meant the smaller/safer pieces were waiting on the bigger one.

Closing this one in favor of those two.

@atharrva01 atharrva01 closed this Oct 16, 2026
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.

1 participant