Upgrade FSC to v0.20.0 - #2357
Upgrade FSC to v0.20.0 #2357sid200727 wants to merge 5 commits into
Conversation
Bumps github.com/hyperledger-labs/fabric-smart-client from v0.18.0 to v0.19.0 across all eight modules. Three breaking changes land in this range, none of which reach Panurus: - fix(fabricx)! (FSC LFDT-Panurus#1673) changes ledger.Provider.Context and the NewLedger/NewManager return signatures. Panurus imports the fabricx finality package for its ListenerManager type but never calls the changed methods; the provider is only received as a parameter and passed through to wiring. - refactor(fabric)! (FSC LFDT-Panurus#1668) removes private chaincode support, which has no call sites here. - fix(membership)! (FSC LFDT-Panurus#1663) adds an error return to GetMSPIDs and IsIdemixMSP, neither of which is called here. All eight modules build and vet clean. The sherdlock test failures present on this branch are pre-existing on main and unrelated. Refs LFDT-Panurus#2351 Signed-off-by: Siddhi Khandelwal <siddhi.200727@gmail.com>
Bumps github.com/hyperledger-labs/fabric-smart-client from v0.19.0 to v0.20.0 across all eight modules, and fixes a runtime panic the upgrade surfaces. FSC LFDT-Panurus#1700 removed HasNext() from iterators.Empty. It was never part of the Iterator interface -- that guarantees only Next and Close -- but the slice and permutation iterators still have it, so sherdlock had come to depend on it through a type assertion: if err == nil && it.(interface{ HasNext() bool }).HasNext() { cachedFetcher returns a permutation on a cache hit and an empty iterator on a miss, so after the upgrade every cache miss panics. This is production code in mixedFetcher.UnspentTokensIteratorBy, and it compiles cleanly, so only the test run catches it. cachedFetcher already knows the outcome -- the ok from cache.Get -- so it now reports that alongside the iterator through an unexported unspentTokensIteratorBy. UnspentTokensIteratorBy stays a thin wrapper, leaving the TokenFetcher interface and its generated mocks untouched, and mixedFetcher no longer inspects an iterator it cannot portably inspect. FSC LFDT-Panurus#1711 (squirrel removal) also lands in this range and needs no source changes here; go mod tidy drops the stale indirect requirements. All eight modules build, vet and lint clean. The remaining sherdlock test failures are pre-existing on main and unrelated. Refs LFDT-Panurus#2351 Signed-off-by: Siddhi Khandelwal <siddhi.200727@gmail.com>
42216d1 to
141a87a
Compare
adecaro
left a comment
There was a problem hiding this comment.
Review: does this fully address #2351?
Approve, with non-blocking comments — the panic fix is correct and verified, two points from @Effi-S's earlier review rounds remain open at this commit.
Checked out fix-2351-bump-fsc-v0.20.0 at 141a87a and verified:
go build ./... (each of the 9 modules individually) -> clean, all 9
go vet ./token/services/selector/sherdlock/... -> clean
go test -count=1 ./token/services/selector/sherdlock/... -> pass
go test -race -count=1 ./token/services/selector/sherdlock/...-> pass, no races
golangci-lint run ./token/services/selector/sherdlock/... -> 0 issues
revert fetcher.go fix + re-run tests -> panics exactly as described
I also read the vendored FSC v0.20.0 source directly to confirm iterators.Empty's empty[K] struct really did drop HasNext() after FSC PR #1700, and grepped the repo for other callers of the same fragile it.(interface{ HasNext() bool }) pattern — found none outside this file.
Reverting fetcher.go's mixedFetcher.UnspentTokensIteratorBy back to the pre-fix type assertion and re-running the suite panics with panic: interface conversion: *iterators.empty[...] is not interface { HasNext() bool }: missing method HasNext at fetcher.go:110, so the existing test suite pins the bug rather than the diff inventing new coverage.
CI has not run yet on this commit — all checks except DCO show pending (fork PR awaiting workflow authorization) — so none of the above is corroborated by CI; all verification here is from local runs.
What it fixes
| # | Finding | Verified |
|---|---|---|
| 2351.1 | FSC v0.20.0 removed HasNext() from the empty iterator, causing a panic on cache miss |
✅ confirmed against vendored FSC source, reproduced the panic by reverting the fix |
| 2351.2 | Fix avoids the panic without widening the public TokenFetcher interface/mocks |
✅ confirmed — unspentTokensIteratorBy is unexported, UnspentTokensIteratorBy signature unchanged |
Both rows are solid; the underlying fix is small, correct, and test-covered.
Non-blocking
- Still open from your earlier review:
fabric-smart-client/integrationis left atv0.18.0in everygo.modthat references it (e.g.cmd/tokengen/go.mod:18), even though the root FSC module moved tov0.20.0here. I confirmedintegration/v0.20.0genuinely exists upstream viagit ls-remote --tags, so this isn't a "can't go further" case. - Still open from your earlier review: the cache-hit invariant (
cached=trueimplies the cached slice is non-empty) is enforced by construction ingroupTokensByKey/updateCache, not at theunspentTokensIteratorByboundary itself, and the updated test (fetcher_test.go:176-186) now only asserts thecachedflag rather than the iterator's actual content — so a future regression that violates the invariant would pass silently. - Hygiene: PR body says "Refs #2351" rather than
Fixes #2351/Closes #2351, so GitHub won't auto-link or close the issue on merge.
Recommendation
Good to merge as-is; the two open threads from @Effi-S are worth resolving in this PR or a fast follow-up, and the Fixes #2351 wording is a one-line fix to the PR body whenever convenient.
| return collections.NewEmptyIterator[*token2.UnspentTokenInWallet](), false, nil | ||
| } | ||
|
|
||
| // isCacheOverused checks if the cache has been queried too many times since the last refresh. |
There was a problem hiding this comment.
Design note: cache-hit invariant (cached=true implies non-empty) is enforced by construction elsewhere, not at this boundary.
cached here is just whether f.cache.Get found the key — it doesn't check the iterator actually has tokens. Today that's safe because groupTokensByKey (fetcher.go:294-308) only appends to m[key] when a token is found, and updateCache (fetcher.go:312-334) deletes any stale key not present in the newest batch — so no key can ever map to an empty slice. But nothing at this boundary enforces that; it's implicit in two other functions.
This is the same concern @Effi-S raised on this line in the prior review round — still open at this commit, restating with the concrete trace of where the invariant actually lives.
Suggestion: add a short comment here documenting the invariant, or assert on it directly (e.g. treat a cache hit with an empty slice as a bug rather than trusting it can't happen).
| it, cached, err := fetcher.unspentTokensIteratorBy(ctx, "wallet1", "USD") | ||
|
|
||
| require.NoError(t, err) | ||
| assert.NotNil(t, it) |
There was a problem hiding this comment.
Should fix: this now only asserts the cached flag, not that the iterator actually yields a token.
The old assertion (it.(interface{ HasNext() bool }).HasNext()) confirmed the cache hit actually produced tokens. The new one (assert.True(t, cached, ...)) would still pass if a future change let cached=true coincide with an empty iterator — exactly @Effi-S's concern from the prior review round on this test.
Suggestion: additionally assert on the iterator's content, e.g. tok, err := it.Next(); require.NoError(t, err); assert.NotNil(t, tok), so a regression in the invariant discussed on fetcher.go:362-372 would actually fail this test.
|
Thank you @adecaro for the detailed review, and for reproducing the panic against the vendored source, that's more verification than I'd done myself. |
|
Bumped fabric-smart-client/integration, it turned out to need more than the version line. FSC #1642 refactored the topology package, so Chaincode.Policy is gone (we were setting SignaturePolicy to the same value anyway), AddNamespaceWithUnanimity is replaced by AddNamespace with a topology.Unanimity policy, and AddNamespace now takes a typed EndorsementPolicy plus options. Three call sites, all migrated. Only go build verifies these locally the integration suites need a full network. |
Bumps fabric-smart-client/integration to v0.20.0 alongside the root module. It was left at v0.18.0 in the first pass because the version grep matched only the root module path. That submodule carries its own breaking changes, which the root module's conventional-commit markers do not cover. FSC LFDT-Panurus#1642 extracted namespace and policy handling out of topology.go: Chaincode.Policy is gone (SignaturePolicy already carried the same value here), AddNamespaceWithUnanimity is replaced by AddNamespace with a topology.Unanimity policy, and AddNamespace now takes a typed EndorsementPolicy and functional options rather than a rule string and variadic peers. A verbatim Signature policy carries no orgs, so AddNamespace cannot derive peers from it; the custom-policy path passes them explicitly via WithPeers to keep the previous behaviour. Also enforces the cache-hit invariant that mixedFetcher relies on. groupTokensByKey only creates a key when it finds a token, so a cached key cannot map to an empty slice today, but nothing at the read boundary checked it and permutatableIterator offers no way to check emptiness without consuming the iterator. updateCache now refuses to store an empty entry, and the cache-hit test asserts the iterator yields a token rather than only that the flag was set. Refs LFDT-Panurus#2351 Signed-off-by: Siddhi Khandelwal <siddhi.200727@gmail.com>
FSC LFDT-Panurus#1642 re-signatured Platform.UpdateChaincode from (name, version, path, file string) to (name, version string, opts ...topology.NamespaceOption). tcc.go declares a local fabricPlatform interface asserting the old form, so the type assertion in GenericBackend.Fabric compiled but panicked at runtime: interface conversion: *fabric.Platform is not cc.fabricPlatform: missing method UpdateChaincode The interface now declares the new signature, and the call site passes path and file as WithLegacyChaincode and WithPackageFile. Also swept the rest of the integration tree for interfaces asserted against FSC types. The only other one, deleteVaultPlatform in support.go, declares DeleteVault(string), which is unchanged in v0.20.0 and asserted with comma-ok in any case. Refs LFDT-Panurus#2351 Signed-off-by: Siddhi Khandelwal <siddhi.200727@gmail.com>
FSC LFDT-Panurus#1724 moved the fabric-x tool lookup into a fabric-x subdirectory of FAB_BINS, so the two toolchains can be installed side by side without their identically named configtxgen and cryptogen overwriting each other. The lookup is a subdirectory rather than a fallback: a missing fabric-x tool is an error instead of a silent run of fabric's. The fxconfig and configtxgen targets still installed into $(FAB_BINS), so after the v0.20.0 bump every fabricx suite panicked during artifact generation with 'could not find configtxgen in FAB_BINS directory .../bin/fabric-x'. They now install into $(FABRIC_X_BINS), mirroring FSC's own Makefile. Refs LFDT-Panurus#2351 Signed-off-by: Siddhi Khandelwal <siddhi.200727@gmail.com>
|
Hi @sid200727 , if it is okay, I'll close this. There were many things to change to make the integration tests passing again. Thanks for you effort. I learned from it 🙏 |
|
Of course, go ahead and close it. That's the right call, the integration side needed a working fabric-x environment to iterate on, and CI round-trips weren't a sensible way to get there. Glad the sherdlock fix and the UpdateChaincode / FABRIC_X_BINS findings were useful. |
|
thanks @sid200727 🙏 |
Closes #2351
Second of two PRs for the FSC bump. Stacks on #2356, which takes us from v0.18.0 to v0.19.0, merge that one first, or this diff will show both bumps.
The runtime panic
FSC #1700 removed
HasNext()fromiterators.Empty. It was never part of theIteratorinterface that guarantees onlyNext()andClose(),but thesliceandpermutationiterators still have it, which is presumably how the pattern crept in here:cachedFetcherreturns apermutationon a cache hit and an empty iterator on a miss. After the upgrade, every cache miss panics. This is production code inmixedFetcher.UnspentTokensIteratorBy, and it compiles cleanly, only the test run catches it.The fix
cachedFetcheralready knows the outcome: theokfromcache.Get. It now reports that alongside the iterator, through an unexportedunspentTokensIteratorBy.UnspentTokensIteratorBystays a thin wrapper over it, so theTokenFetcherinterface and its generated mocks are untouched, andmixedFetcherno longer inspects an iterator it has no portable way to inspect.I kept it to
cachedFetcherdeliberately, widening the interface method would have meant regeneratingmocks/token_fetcher.goand updating the stubs inmanager_test.go,ratelimit_test.go,selector_test.goandselector_iterator_test.go, which felt out of proportion for this.Other breaking changes in this range
FSC #1711 (squirrel removal) also lands here. As confirmed during that PR's review, it needs no source changes on our side,
go mod tidyjust drops the stale indirect requirements.Testing
-> All eight modules build,
go vetandgolangci-lint(v2.12.2, the pinned version) clean-> Verified the panic's provenance:
sherdlockpanics on v0.20.0 without this fix, and does not on v0.19.0, so the break arrives with this bump-> The remaining
sherdlockfailures and theidentity/configTestTranslatePathfailure are pre-existing onmainand unrelatedPossibly worth a follow-up
The same assertion pattern may exist elsewhere in Panurus, or in other FSC consumers. I only checked
sherdlockbecause that's what failed.Happy to open a separate issue if that seems worth sweeping for.