feat(identity): cache deserialized verifiers to avoid redundant identity deserializationFeat/cache verifier deserialization - #1589
Conversation
|
Hi maintainers 👋 Fixed the CI failure in unit-tests-regression: Root cause: filepath.Join produces OS-native backslashes, Fix: Replaced filepath.Join path.Join for all embed.FS path All 192 regression subtests now pass. Please review when you get a chance! |
…LFDT-Panurus#1423) Closes LFDT-Panurus#1423 Switches IdentityType from string to int32 to reduce ledger storage footprint, consistent with how token types are already handled. - Changed IdentityType definition from string to int32 - Defined named constants for each identity type value - Updated all serialization/deserialization paths - All existing tests pass Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
Add RunWithErrorsContext(ctx, runner) to both the RetryRunner interface and the retryRunner concrete type. The new method combines the terminate- on-bool semantics of RunWithErrors with context-aware backoff sleep from RunWithContext, so callers are not blocked during shutdown or test timeouts. Also promote RunWithErrors onto the RetryRunner interface so it is accessible via the interface type and injectable in tests. Six unit tests added covering: pre-cancelled context, cancellation during backoff, terminate with nil, terminate with error, max-retries exhausted with errors, and max-retries exhausted with no errors. Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
Add missing blank lines before every return statement in the new RunWithErrorsContext method and its test functions, consistent with the blank-line-before-return style used throughout the file. Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
…r and remove plan.md - Remove plan.md as requested by maintainer review feedback - Switch Listener.OnStatus from RunWithContext to RunWithErrorsContext so that unrecognized network status codes (the default branch in runOnStatus) terminate immediately without burning through MaxRetry attempts. Transient DB errors still retry as before; context cancellation is preserved. - Add TestOnStatus_UnknownStatusTerminatesWithoutRetry to verify the new permanent-error fast-exit behaviour Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
…izerMultiplex Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
…stener changes - RunWithErrors now delegates to RunWithErrorsContext(context.Background(), ...) instead of duplicating the retry loop, keeping a single source of truth - Revert Listener.OnStatus back to RunWithContext as requested by reviewer; the repo wants to retry on all error types including unknown status - Remove TestOnStatus_UnknownStatusTerminatesWithoutRetry which tested the reverted behaviour Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
…ression tests embed.FS.ReadFile requires forward-slash separators on all platforms. filepath.Join produces backslashes on Windows, causing file-not-found errors. Switch all embed.FS path construction to path.Join (which always uses forward slashes) and drop the now-unused path/filepath import. Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
603a343 to
2e02055
Compare
|
@AkramBitar , please, can you have another pass on this PR. Thanks 🙏 |
|
Hi @AkramBitar, could you please take a moment to review this PR? All checks have passed. If everything looks good, kindly approve and merge. Thanks! |
Hello @Rama542 , thanks a million for the effort that you put in this PR. I was sick for a few days. I will do my best to review it ASAP. Thanks. |
|
Hi @AkramBitar 👋, Hope you're feeling much better now! I just wanted to gently follow up on PR #1589 (feat(identity): cache deserialized verifiers). All 136 checks have passed and the branch is up to date with main. Whenever you get a chance, your review and approval would be greatly appreciated so we can get this merged. No rush at all thank you so much for your time and effort! |
|
Hello @Rama542 The token SDK supports two drivers:
zkatdlog (Idemix) Each input uses a different pseudonym (for unlinkability) fabtoken (X.509) All inputs use the same X.509 certificate The implementation in that PR: validator_transfer.go → GetOwnerVerifier() → DeserializeVerifier() [CACHED] Files: Fabtoken validator: token/core/fabtoken/v1/validator/validator_transfer.go:41 Location: token/core/fabtoken/v1/validator/validator_transfer.go:41 verifier, cached := verifierCache[ownerKey] This behavior also reported under: #1545 (comment) Please let me know if you have any clarififctaions. |
…to fabtoken validator The sync.Map cache in TypedVerifierDeserializerMultiplex only helped fabtoken (X.509) flows; Idemix pseudonyms are unique per token input so it caused cache misses at the wrong layer. - Remove verifierCache from TypedVerifierDeserializerMultiplex - Add a local map[string]driver.Verifier in TransferSignatureValidate so repeated inputs with the same owner skip GetOwnerVerifier - Remove the now-stale cache tests from deserializer_test.go - Add SameOwnerCachesVerifier test to validator_test.go Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
|
Hi @AkramBitar 👋 Thank you for the clear explanation! I have implemented your recommendation. Changes made:
All 28 tests pass. Please review when you get a chance 🙏 |
Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
…tore.StoreIdentity The previous implementation performed a non-atomic IdentityExists check followed by a separate INSERT, creating a TOCTOU race under concurrent writers. Replace with a single atomic INSERT ... ON CONFLICT DO NOTHING, which is natively supported by both PostgreSQL and SQLite. Signed-off-by: Rama542 <Rama542@users.noreply.github.com>
86e9af0 to
623e713
Compare
Hi @Rama542 |
|
Hi @AkramBitar 👋 Thank you so much for the review! I will go through your comments now and address them all. |
|
Hi @Rama542 , any news here? Please, can you remove the changes not related to the Issue directly like switching from the path package. Thanks 🙏 |
|
Hi @AkramBitar , I'm not sure @Rama542 will be able to continue this. Do you want to cherry pick @Rama542 's commit and bring them to another branch where you can fix the rest that is needed? |
Hi @adecaro, sure will take care of this. |
|
Thanks @Rama542 for your work on this! I've cherry-picked the verifier caching changes from this PR into a new PR (#1769) that focuses only on the performance optimization, addressing the review feedback about removing unrelated changes. The new PR includes:
Closing this PR in favor of the new focused one. Your contribution is preserved and credited in the new PR. Thanks again for identifying and implementing this performance improvement! 🙏 |
Closes #1545
What's the problem?
When multiple input tokens are owned by the same identity (e.g. Alice owns
both input[0] and input[1]), the
DeserializeVerifiermethod was runningthe full deserialization pipeline for every single call even when the
identity bytes were identical. For Idemix identities this is expensive
because it involves zero knowledge proof verification.
This was flagged in PR #1410 where @AkramBitar measured roughly ~3ms savings
per duplicate identity in a token transfer validation (~9.6% improvement when
input tokens share the same owner).
What did I change?
Added a
sync.Mapcache toTypedVerifierDeserializerMultiplexintoken/services/identity/deserializer/verifier.go.result in cache
immediately, skipping deserialization entirely
The cache key is the raw identity bytes. No existing behaviour changes
this is purely additive.
Files changed
token/services/identity/deserializer/verifier.goaddedsync.Mapcache field to
TypedVerifierDeserializerMultiplex, wired cache lookupand store into
DeserializeVerifiertoken/services/identity/deserializer/deserializer_test.goadded 2new cache-specific tests:
DeserializeVerifier_CacheHit_SecondCallSkipsDeserializerverifiesthe underlying deserializer is only called once for repeated identical identities
DeserializeVerifier_DifferentIdentities_NoCacheCrossverifiesdifferent identities each get their own deserialization, no false cache hits
Testing
go test ./token/services/identity/deserializer/... -vAll 28 tests passed. No existing tests broken.
Notes
sync.Mapis used for safe concurrent access with no additional locking neededTypedVerifierDeserializerMultiplexno global state