You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
> **Note:**`provider` here is a `NewTMSProvider`-wrapped `Provider` (see [Driver Metrics](../drivers/metrics.md#pitfall-labelnames-must-include-network-channel-namespace)), which binds `network`/`channel`/`namespace` on every metric via `.With(...)` before returning it. Every `CounterOpts`/`HistogramOpts` above must therefore declare those three as `LabelNames` in addition to its own label(s), or the metric panics with "inconsistent label cardinality" on first use. This is exactly the bug that crashed the DVP/DLog integration suite in `SignerRouter.Register` before it was fixed.
164
164
165
+
## Wallet Lifecycle and Recipient Data Caching
166
+
167
+
Anonymous owner wallets hand out a fresh pseudonym for every payment. Generating one is
168
+
expensive (an Idemix pseudonym plus a registry binding), so `AnonymousOwnerWallet` keeps a
169
+
pre-provisioned buffer of recipient data. Two caches implement that buffer:
170
+
171
+
| Cache | Buffers | Sized by |
172
+
|:------|:--------|:---------|
173
+
|`role.RecipientDataCache` (`token/services/identity/role/cache.go`) |`driver.RecipientData` (pseudonym + audit info) for one wallet |`wallets.owners[].cacheSize`, falling back to `wallets.defaultCacheSize` (see [configuration](../configuration.md)) |
174
+
|`idemix/cache.IdentityCache` (`token/services/identity/idemix/cache/cache.go`) |`idriver.IdentityDescriptor` for one Idemix key manager | same lookup, via `KeyManagerProvider.cacheSizeForID`|
175
+
176
+
Both follow the same contract:
177
+
178
+
***Provisioning is lazy.** The background goroutine is started by the first request, and
179
+
only when the configured size is greater than zero. With a size of zero the cache is
180
+
disabled and every request goes straight to the backend.
181
+
***Requests never wait on the cache.** A request that does not find a buffered entry
182
+
within a short timeout (5 ms) generates the data on the spot instead of blocking, so a
183
+
slow backend degrades latency rather than stalling the caller. A cancelled caller
184
+
context aborts the request immediately.
185
+
***A failing backend backs off, and is observable.** The provisioning loop logs the
186
+
failure, increments a counter and waits one second before retrying, so a broken
187
+
identity backend cannot turn pre-provisioning into a busy loop — and the condition can
188
+
be alerted on instead of only appearing in the logs.
189
+
***`Close()` is mandatory and idempotent.** It cancels the background context, which
190
+
terminates the provisioning goroutine even while it is parked on a full buffer or
191
+
inside a retry backoff. A cache that is never closed keeps its goroutine, its channel
192
+
and its backend closure alive for the lifetime of the process. After `Close()` the
193
+
cache still serves requests from the backend; it simply stops pre-provisioning.
194
+
195
+
### Cache metrics
196
+
197
+
| Metric | Type | Cache | Purpose |
198
+
|:-------|:-----|:------|:--------|
199
+
|`recipient_data_cache_level`| Gauge |`RecipientDataCache`| Entries currently buffered. Counted only once an entry is really in the buffer, so it cannot drift upward when the producer is blocked. |
200
+
|`recipient_data_provision_failures_total`| Counter |`RecipientDataCache`| Failed pre-provisioning attempts. A rising rate means the identity backend is failing and requests are falling back to the slower on-demand path. |
201
+
|`cache_level`| Gauge | idemix `IdentityCache`| As above, for Idemix identities. |
202
+
|`cache_provision_failures_total`| Counter | idemix `IdentityCache`| As above, for Idemix identities. |
203
+
204
+
> **Note:** these providers are `NewTMSProvider`-wrapped, so every `GaugeOpts`/`CounterOpts`
205
+
> above must declare `network`, `channel` and `namespace` in `LabelNames` — omitting them
206
+
> panics with "inconsistent label cardinality" on first use. See
0 commit comments