diff --git a/.golangci.yaml b/.golangci.yaml index 9d1ad11336..ed5e79877a 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -163,6 +163,11 @@ linters: # (not OpenWriteSession on the main store). - path: internal/storage/readstore/ linters: [forbidigo] + # The usagestore is a peer secondary store to readstore, dedicated to the + # usagebuilder projections. It manages its own Pebble DB and uses + # NewWriteSessionFromDB by the same rationale. + - path: internal/storage/usagestore/ + linters: [forbidigo] # Tests use OpenWriteSession to seed data; the structural guarantee is on # production paths. - path: _test\.go$ diff --git a/AGENTS.md b/AGENTS.md index e7d2de157c..140a0bc89e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,9 +14,11 @@ This document contains rules and conventions for AI agents working on this codeb 4. **Pebble writes only from the hot path or declared lifecycle paths** — `*dal.Store.OpenWriteSession()` is the only producer of `*dal.WriteSession`. Outside the FSM hot path, only declared lifecycle paths may call it: `internal/bootstrap/config_validation.go`, `internal/infra/backup/`, `internal/infra/attributes/prepare.go`. This is enforced by a `forbidigo` rule in `.golangci.yaml`; new call sites must be added to the exclusions block with a justification. 5. **Never delete cache entries outside of rotations** — Cache entries must only be evicted during generation rotations (Gen0 → Gen1 → discard). Deleting individual entries breaks the cache prediction mechanism (bloom filters, tombstones). 6. **Every FSM `Registry.X.Get(...)` must have a matching preload, declared by the component that proposes the command** — The FSM apply path reads from the in-memory cache; a cache miss turns the read into a silent no-op. Each component that emits a proposal (the metadata converter, the index builder, the cluster-config reconciler, the idempotency-eviction scheduler, the mirror worker, admission) is responsible for declaring its own `preload.Needs` covering every key its apply path will read. There is NO central proposal→needs registry — coupling the preload package to every proposal type creates a single point that easily falls behind. The component knows what it reads; the component declares it. The shared `proposeTechnical` helper takes a `*preload.Needs` parameter the caller fills in (pass nil or an empty `Needs` when the apply path has no cache-keyed reads, e.g. cluster config / idempotency eviction). The preload populates the cache via `MirrorPreload` with a fresh value read at propose time (Pebble fallback on cache miss), and `PredictedIndex` catches mutations between propose and apply. + + **Volume preload is load-bearing for the `LedgerLog.new_kept_volumes` / `ephemeral_volumes` split.** Admission MUST preload the current value of every `(account, asset)` volume touched by an order, including postings resolved from numscript execution. The FSM classifies a volume as "newly created" by checking `Old.IsDefined()` (or the zero-placeholder via `isVolumePreloadZero`) at merge time — a silent cache miss on an existing volume produces a false-new classification, mis-routes the tuple between the `new_kept_volumes` / `ephemeral_volumes` / `purged_volumes` per-log lists, and inflates `usagestore.CounterVolume`. Because `usagestore` is a rebuildable peer side-store held **outside** checker scope (invariant #8 verifies only primary-Pebble-store projections), no checker pass would surface the drift; it persists until an explicit usage rebuild. That absence of a backstop makes the preload correctness even more load-bearing, not less. This is not opportunistic (unlike the metadata preload that was removed after the indexbuilder stopped needing it): balance checks, Uint256 arithmetic and numscript resolution all require the current volume value, so the preload is structurally mandatory. If a future refactor considers alleviating volume preload, `VolumeCount` must be re-hosted first (via computed-on-read or a subsystem-side seen-keys table) — see EN-1422 for the design rationale. 7. **Never silently skip a "should not happen" branch** — A branch that is reachable only if an invariant is violated (nil where the contract says non-nil, a state we believe unreachable, a cache miss after a guaranteed preload, etc.) MUST surface a loud signal: `return fmt.Errorf("invariant: ...")` so it bubbles up, or `assert.Unreachable(...)` for SUT-level invariants exercised under antithesis. A silent `return nil` / `continue` on these branches hides real bugs — particularly catastrophic in the FSM apply path, where a no-op desyncs nodes from each other. Branches that represent genuine runtime conditions (cache miss as an expected outcome, stale proposal, deleted entity) keep their soft `return nil`. The distinction is whether the case is *expected* (soft skip OK) or *impossible by design* (must fail loudly). The comment must say *why* the case is impossible so a reader can decide whether to add a hard fail or relax the rule. -8. **The audit log is the only source of truth — every other persisted dataset is a projection and must be verified by the checker** — Only `AuditEntry` (zone `Cold`, sub `Audit`) is cryptographically bound, via the hash chain that `state.BuildHashedHeaderPayload` + `processing.HashGenerator` produce and `checker.verifyAuditHashChain` verifies on every Check() run. Everything else stored in Pebble — `Log`, `AuditItem`, `AppliedProposal`, `LedgerLog.PurgedVolumes`, attribute caches (`Volume`, `Metadata`, `Transaction`, `Reference`, `Boundary`, etc.), reversion bitsets, idempotency keys, mirror cursors, chapters, bloom filters, signing keys, the read-side index — is a *projection* of orders that already live in the audit chain. Projections are rebuildable from the audit on demand, so we deliberately do NOT extend the hash chain to cover them (refactor over hash binding — see `feedback_audit_is_source_of_truth`). In exchange, **`internal/application/check/checker.go` MUST verify every projection it persists**: re-derive the value the projection should hold by replaying the audit (`ReplayLedgerLog`, `SimulateEphemeralPurge`, `partitionVolumes`, etc.) and compare to what is stored, emitting the matching `CHECK_STORE_ERROR_TYPE_*` event on divergence. A projection that the checker does not verify is a tampering vector — adding a new persisted projection without a matching compare* / collect* pass in the checker is the violation. Two scope refinements: (a) this applies to the **primary FSM store** — the single store `Check()` opens and walks; **peer secondary stores** (the `readstore` inverted index today; the `usagestore` counters forthcoming with EN-1334) are out of *main-store checker* scope *by construction* since `Check()` never opens them. That scope carve-out is **not** a claim they are integrity-safe: the readstore serves READY indexes directly to business-visible queries with no scan fallback, and its automated detect/drop/rebuild is **not yet wired** (tracked under `EN-1323`), so a corrupted or tampered index is a **current open integrity gap on the peer-store side** — a per-replica rebuild-health concern of the index builder, not an invariant-#8 main-store concern. Out of the main-store checker's mandate, not out of every integrity concern. (b) A primary-store projection may be exempted from a dedicated pass only when it is either (i) deterministically rebuildable from still-retained verified state through a real, *wired* rebuild path — not rebuildable merely in principle — or (ii) purely informational and intentionally carried across restore (cf. `BuildStatus`). These are distinct bases: of the *Known projection gaps* below, `DefaultEnforcementMode` and `SubAttrLedgerMetadata` qualify under (i) via `RebuildDelta`, while `EphemeralEvictedCount` / `TransientUsedCount` qualify under (ii) — they are NOT rebuilt by `RebuildDelta`, so the wired-rebuild basis must not be claimed for them. The current passes are `compareVolumes`, `compareMetadata`, `compareTransactions`, `compareExclusionProjections` (AppliedProposal.TransientVolumes + LedgerLog.PurgedVolumes), `checkReversionInvariants`, `verifySealingHash`, `compareIdempotencyOutcomes` (frozen idempotency outcomes in SubIdempKeys vs the hash-chained AuditFailure/AuditSuccess that wrote them — the failure kind is re-derived from the chain-bound reason via `domain.KindForReason`, never stored), and `compareIndexes` (SubAttrIndex registry vs CreateIndex/DropIndex/RemovedMetadataFieldType/DeleteLedger logs — covers presence + identity; BuildStatus is intentionally excluded because it is purely informational on the cluster-wide registry entry — queries gate on the per-replica `IndexVersionState.CurrentVersion`, not on BuildStatus), and `compareMirrorV2LogID` (stored `LedgerBoundaries.last_mirror_v2_log_id` **==** `max(audited MirrorIngest.v2_log_id)` per ledger — a full equality check, `CHECK_STORE_ERROR_TYPE_MIRROR_V2LOGID_MISMATCH` on ANY divergence; the FSM enforces a contiguous applied prefix so at rest the two must be exactly equal, and the baseline floor is seeded from archived `Boundary` rows now included in the compact baseline snapshot; pre-field clusters are unsupported, no backfill leniency), and `compareSchema` (per-ledger `LedgerInfo.MetadataSchema` vs the replayed CreateLedger.initial_schema + SetMetadataFieldType/RemovedMetadataFieldType logs; under archived chapters the boundary schema is seeded from the baseline checkpoint, which carries LedgerInfo for this purpose), and `compareAccountTypes` (per-ledger `LedgerInfo.AccountTypes` vs the replayed AddAccountType/RemoveAccountType logs, baseline-seeded under archiving like the schema), and `compareLedgerPresence` (the live ledger set in the store must match the audit-derived set both ways: every audit-live ledger — CreateLedger with no later DeleteLedger, or a non-deleted baseline ledger under archiving — must have a *live* stored `LedgerInfo` else `MISSING_LEDGER` (covers an entry deleted outright OR tampered to a soft-deleted tombstone, which the compareSchema/compareAccountTypes loops skip), and every live stored `LedgerInfo` must be audit-backed else `UNAUDITED_LEDGER` (an injected empty ledger row carries no schema/types for the projection passes to flag). The audit-derived set is NEVER seeded from the live store — under archiving it comes from the baseline checkpoint, keeping the check independent of the data it verifies), and `compareReferences` (the SubAttrReference reference→txID uniqueness index vs the references replayed from CreatedTransaction/RevertedTransaction logs, baseline-seeded under archiving; verified both ways — missing, unaudited, and retargeted rows are all flagged; rows for deleted or cleanup-pending ledgers are skipped since they legitimately linger until a covering purge runs deleteLedgerData), and `compareBoundaries` (per-ledger `LedgerBoundaries` vs the checker’s re-derivation: NextTransactionId/NextLogId/PostingCount/RevertCount from the replayed logs plus the chain-bound AuditItem order effects — mirror fill-gap advances and NumscriptExecutionCount live on the orders, not the ledger-log stream — baseline-seeded under archiving; VolumeCount/MetadataCount/ReferenceCount are compared against a recount of the stored attribute rows they summarize, which their own passes verify entry-by-entry, so the chain is rows↔audit, counter↔rows; EphemeralEvictedCount/TransientUsedCount are intentionally excluded — informational, carried across restore, cf. BuildStatus), and `compareReversions` (the per-ledger reversion bitsets — `ZonePerLedger`/`SubPLReversions`, the projection the FSM's already-reverted gate reads — vs the reverted set derived from baseline tx-row markers plus the replayed RevertedTransaction logs; exact equality both ways — a lost bit re-admits a double revert, an unaudited bit blocks a legitimate one; driven purely by audit-derived state — no persisted marker (pending-cleanup included) can exempt a live ledger, stored rows for non-live ledgers are flagged since DeleteLedger deletes them at apply on both the live path and the replay, and undecodable rows are reported); extend the list as new persisted projections land. **Known projection gaps**: `LedgerBoundaries.EphemeralEvictedCount` / `TransientUsedCount` are excluded from `compareBoundaries` and carried across restore rather than re-derived — informational counters (cf. BuildStatus); `LedgerInfo.DefaultEnforcementMode` and the ledger-metadata attribute (`SubAttrLedgerMetadata`) have no compare pass yet (both are rebuilt on restore by RebuildDelta). +8. **The audit log is the only source of truth — every other persisted dataset is a projection and must be verified by the checker** — Only `AuditEntry` (zone `Cold`, sub `Audit`) is cryptographically bound, via the hash chain that `state.BuildHashedHeaderPayload` + `processing.HashGenerator` produce and `checker.verifyAuditHashChain` verifies on every Check() run. Everything else stored in Pebble — `Log`, `AuditItem`, `AppliedProposal`, `LedgerLog.PurgedVolumes`, attribute caches (`Volume`, `Metadata`, `Transaction`, `Reference`, `Boundary`, etc.), reversion bitsets, idempotency keys, mirror cursors, chapters, bloom filters, signing keys, the read-side index — is a *projection* of orders that already live in the audit chain. Projections are rebuildable from the audit on demand, so we deliberately do NOT extend the hash chain to cover them (refactor over hash binding — see `feedback_audit_is_source_of_truth`). In exchange, **`internal/application/check/checker.go` MUST verify every projection it persists**: re-derive the value the projection should hold by replaying the audit (`ReplayLedgerLog`, `SimulateEphemeralPurge`, `partitionVolumes`, etc.) and compare to what is stored, emitting the matching `CHECK_STORE_ERROR_TYPE_*` event on divergence. A projection that the checker does not verify is a tampering vector — adding a new persisted projection without a matching compare* / collect* pass in the checker is the violation. Two scope refinements: (a) this applies to the **primary FSM store** — the single store `Check()` opens and walks; **peer secondary stores** (the `readstore` inverted index today; the `usagestore` counters forthcoming with EN-1334) are out of *main-store checker* scope *by construction* since `Check()` never opens them. That scope carve-out is **not** a claim they are integrity-safe: the readstore serves READY indexes directly to business-visible queries with no scan fallback, and its automated detect/drop/rebuild is **not yet wired** (tracked under `EN-1323`), so a corrupted or tampered index is a **current open integrity gap on the peer-store side** — a per-replica rebuild-health concern of the index builder, not an invariant-#8 main-store concern. Out of the main-store checker's mandate, not out of every integrity concern. (b) A primary-store projection may be exempted from a dedicated pass only when it is either (i) deterministically rebuildable from still-retained verified state through a real, *wired* rebuild path — not rebuildable merely in principle — or (ii) purely informational and intentionally carried across restore (cf. `BuildStatus`). These are distinct bases: of the *Known projection gaps* below, `DefaultEnforcementMode` and `SubAttrLedgerMetadata` qualify under (i) via `RebuildDelta` (`BuildStatus` on the index registry is the canonical (ii) example). The current passes are `compareVolumes`, `compareMetadata`, `compareTransactions`, `compareExclusionProjections` (AppliedProposal.TransientVolumes + LedgerLog.PurgedVolumes), `checkReversionInvariants`, `verifySealingHash`, `compareIdempotencyOutcomes` (frozen idempotency outcomes in SubIdempKeys vs the hash-chained AuditFailure/AuditSuccess that wrote them — the failure kind is re-derived from the chain-bound reason via `domain.KindForReason`, never stored), and `compareIndexes` (SubAttrIndex registry vs CreateIndex/DropIndex/RemovedMetadataFieldType/DeleteLedger logs — covers presence + identity; BuildStatus is intentionally excluded because it is purely informational on the cluster-wide registry entry — queries gate on the per-replica `IndexVersionState.CurrentVersion`, not on BuildStatus), and `compareMirrorV2LogID` (stored `LedgerBoundaries.last_mirror_v2_log_id` **==** `max(audited MirrorIngest.v2_log_id)` per ledger — a full equality check, `CHECK_STORE_ERROR_TYPE_MIRROR_V2LOGID_MISMATCH` on ANY divergence; the FSM enforces a contiguous applied prefix so at rest the two must be exactly equal, and the baseline floor is seeded from archived `Boundary` rows now included in the compact baseline snapshot; pre-field clusters are unsupported, no backfill leniency), and `compareSchema` (per-ledger `LedgerInfo.MetadataSchema` vs the replayed CreateLedger.initial_schema + SetMetadataFieldType/RemovedMetadataFieldType logs; under archived chapters the boundary schema is seeded from the baseline checkpoint, which carries LedgerInfo for this purpose), and `compareAccountTypes` (per-ledger `LedgerInfo.AccountTypes` vs the replayed AddAccountType/RemoveAccountType logs, baseline-seeded under archiving like the schema), and `compareLedgerPresence` (the live ledger set in the store must match the audit-derived set both ways: every audit-live ledger — CreateLedger with no later DeleteLedger, or a non-deleted baseline ledger under archiving — must have a *live* stored `LedgerInfo` else `MISSING_LEDGER` (covers an entry deleted outright OR tampered to a soft-deleted tombstone, which the compareSchema/compareAccountTypes loops skip), and every live stored `LedgerInfo` must be audit-backed else `UNAUDITED_LEDGER` (an injected empty ledger row carries no schema/types for the projection passes to flag). The audit-derived set is NEVER seeded from the live store — under archiving it comes from the baseline checkpoint, keeping the check independent of the data it verifies), and `compareReferences` (the SubAttrReference reference→txID uniqueness index vs the references replayed from CreatedTransaction/RevertedTransaction logs, baseline-seeded under archiving; verified both ways — missing, unaudited, and retargeted rows are all flagged; rows for deleted or cleanup-pending ledgers are skipped since they legitimately linger until a covering purge runs deleteLedgerData), and `compareBoundaries` (per-ledger `LedgerBoundaries` vs the checker’s re-derivation: only NextTransactionId/NextLogId are verified here — derived from the replayed logs plus the chain-bound AuditItem order effects (mirror fill-gap advances live on the orders, not the ledger-log stream), baseline-seeded under archiving; the mirror high-water `last_mirror_v2_log_id` is verified separately by `compareMirrorV2LogID`. The per-ledger usage counters — `PostingCount`, `RevertCount`, `NumscriptExecutionCount`, `VolumeCount`, `MetadataCount`, `ReferenceCount`, `EphemeralEvictedCount`, `TransientUsedCount` — no longer live on `LedgerBoundaries`: `LedgerBoundaries` now reserves tags 3-10 for them and they moved to the `usagestore` peer secondary store (EN-1334 / EN-1420), out of main-store checker scope **by construction** (per the peer-store carve-out in scope refinement (a) above), their integrity being a peer-store rebuild-health concern — reconverged by the online usagebuilder fold + `usagestore.Reset()` on rollback — rather than an invariant-#8 main-store concern), and `compareReversions` (the per-ledger reversion bitsets — `ZonePerLedger`/`SubPLReversions`, the projection the FSM's already-reverted gate reads — vs the reverted set derived from baseline tx-row markers plus the replayed RevertedTransaction logs; exact equality both ways — a lost bit re-admits a double revert, an unaudited bit blocks a legitimate one; driven purely by audit-derived state — no persisted marker (pending-cleanup included) can exempt a live ledger, stored rows for non-live ledgers are flagged since DeleteLedger deletes them at apply on both the live path and the replay, and undecodable rows are reported); extend the list as new persisted projections land. **Known projection gaps**: `LedgerInfo.DefaultEnforcementMode` and the ledger-metadata attribute (`SubAttrLedgerMetadata`) have no compare pass yet (both are rebuilt on restore by RebuildDelta). 9. **Never bypass the FSM coverage gate** — Every cache-attribute read on the FSM hot path MUST go through `Scope.GetX(...)` so the per-order `coverage_bits` admit it. Reading the underlying `Registry.X.KeyStore().M` (or any other parent-cache iterator) directly skips the gate and produces non-deterministic FSM behavior: the gate is what binds the order to the admission-declared preload set, and a direct read silently sees keys the proposer never declared. There is NO documented exception — paths that need to iterate (e.g. cascade-on-delete) MUST either declare the relevant `preload.Needs` upfront, defer the work to a lifecycle path (`batch.deleteLedgerData` + `MarkLedgerForCleanup`), or be rejected at design review. New helpers that scan the parent KeyStore from inside an order/TU handler are the violation, even when wrapped in a method on `WriteSet`. The coverage gate exists precisely so admission's declared key set is the FSM's only legitimate read horizon — under no circumstances should the apply path widen it on the fly. diff --git a/cmd/ledgerctl/ledgers/stats.go b/cmd/ledgerctl/ledgers/stats.go index aafcfa5576..0103b9770b 100644 --- a/cmd/ledgerctl/ledgers/stats.go +++ b/cmd/ledgerctl/ledgers/stats.go @@ -75,7 +75,6 @@ func runStats(cmd *cobra.Command, _ []string) error { pterm.Printf("Postings: %d\n", stats.GetPostingCount()) pterm.Printf("Logs: %d\n", stats.GetLogCount()) pterm.Printf("Volumes: %d\n", stats.GetVolumeCount()) - pterm.Printf("Metadata: %d\n", stats.GetMetadataCount()) pterm.Printf("References: %d\n", stats.GetReferenceCount()) pterm.Printf("Reverts: %d\n", stats.GetRevertCount()) pterm.Printf("Numscript execs: %d\n", stats.GetNumscriptExecutionCount()) diff --git a/docs/technical/architecture/overview.md b/docs/technical/architecture/overview.md index 4ee262fdae..4c83c00ec7 100644 --- a/docs/technical/architecture/overview.md +++ b/docs/technical/architecture/overview.md @@ -154,17 +154,17 @@ Per-ledger boundaries use the `LedgerBoundaries` protobuf message from `raft_cmd message LedgerBoundaries { fixed64 next_transaction_id = 1; fixed64 next_log_id = 2; - fixed64 volume_count = 3; - fixed64 metadata_count = 4; - fixed64 reference_count = 5; - fixed64 posting_count = 6; - fixed64 ephemeral_evicted_count = 7; - fixed64 transient_used_count = 8; - fixed64 revert_count = 9; - fixed64 numscript_execution_count = 10; } ``` +> Every per-ledger counter — postings, reverts, numscript executions, references, ephemeral evictions, transient volumes, **and volumes** — lives in the usagebuilder side-store (`internal/application/usagebuilder`, `internal/storage/usagestore`). All counters are derived from the audit chain: event counts (posting / revert / numscript-exec / reference) come from replaying orders; transient counts come from `AppliedProposal.TransientVolumes`; ephemeral and volume counts come from three DISJOINT per-log lists that the FSM populates on every `LedgerLog`: +> +> - `purged_volumes` — draining evictions (was non-zero in Pebble, now zero, entry deleted at commit) +> - `new_kept_volumes` — persistent-new (created + survives past commit) +> - `ephemeral_volumes` — pure ephemeral (created + evicted same log) +> +> Volume count delta per log = `len(new_kept_volumes) − len(purged_volumes)`. Pure ephemeral tuples contribute +0 (was zero, is zero) and are tracked only for the index builder's skip logic and for the ephemeral-eviction counter. Splitting ephemeral out of `purged_volumes` avoids the 2× byte cost that a naive union-encoding would pay on ephemeral-heavy workloads. `LedgerBoundaries` carries only the two ID generators that drive apply-time allocation decisions. `metadata_count` is intentionally not exposed — the admission preload no longer injects old metadata values so cardinality cannot be reliably derived at the FSM level; it will come back on a sound foundation later. + > **Note:** The `State` / `LedgerState` proto messages sometimes shown in older documentation are conceptual models, not actual proto definitions. The real FSM state is spread across the `Machine` struct fields and its `StateRegistry`. ### Benefits of Single Raft diff --git a/docs/technical/architecture/subsystems/usage/README.md b/docs/technical/architecture/subsystems/usage/README.md new file mode 100644 index 0000000000..318ed94bb5 --- /dev/null +++ b/docs/technical/architecture/subsystems/usage/README.md @@ -0,0 +1,19 @@ +# Usage + +The background worker (`internal/application/usagebuilder`) that turns committed audit entries into per-ledger housekeeping counters — postings, reverts, numscript executions, references, ephemeral evictions, transient uses, live volume cardinality — plus per-Numscript-template invocation records. Runs on every node — leader and followers — independently, mirroring the indexer's decoupling from the FSM hot path: the FSM commits and signals; the usagebuilder reads its own Pebble read handle and writes to a dedicated secondary store (`internal/storage/usagestore`). + +The projections it maintains are exposed by the API — `GET /v3/{ledger}/stats` for the aggregate counters, `GET /v3/{ledger}/numscripts/{name}/usage` for per-template invocation counts. + +## Documents + +| Document | Description | +|----------|-------------| +| [usagebuilder.md](usagebuilder.md) | Pipeline mechanics: builder loop, audit-chain tailing, per-batch commit, log-payload consumption. | +| [counters.md](counters.md) | Counter definitions, storage keys, `LedgerLog.{purged,new_kept,ephemeral}_volumes` split, formula for each counter. | + +## Related + +- [FSM](../fsm/) — emits the `LedgerLog.new_kept_volumes` / `ephemeral_volumes` / `purged_volumes` annotations the usagebuilder consumes. Depends on the volume preload contract (see AGENTS.md invariant #6). +- [Indexer](../indexer/) — sibling subsystem with the same audit-tailing shape, but writes to a different secondary store (`readstore`). +- [Checker](../checker/) — verifies the projections against the audit chain (`compareExclusionProjections` for ephemeral/transient tuples). +- [Storage](../storage/) — the usage store is a peer Pebble instance to the readstore, WAL disabled, own comparer, own Pebble tuning. diff --git a/docs/technical/architecture/subsystems/usage/counters.md b/docs/technical/architecture/subsystems/usage/counters.md new file mode 100644 index 0000000000..e0b5c2d6e4 --- /dev/null +++ b/docs/technical/architecture/subsystems/usage/counters.md @@ -0,0 +1,144 @@ +# Counters and Storage Schema + +This page documents the projections the usagebuilder materialises: what each counter counts, how the FSM plumbs the source data through the log payload, and how the counters are keyed in the usagestore. + +These counters live in the **usagestore**, a peer secondary store. Per the checker-scope framing (CLAUDE.md invariant #8), a peer secondary store is out of the **main-store checker's** scope *by construction* — `Check()` never opens the usagestore — so the checker does **not** verify these counters. Their integrity is a per-replica rebuild-health concern (rebuildable from the audit on demand), not a main-store invariant-#8 projection. + +For the pipeline that populates these keys, see [usagebuilder.md](usagebuilder.md). + +## Counter Catalogue + +Every counter is keyed by `(ledger, counter_id)` in the usagestore (`internal/storage/usagestore/keys.go`) — one byte per counter, stable on-disk identifiers, never renumbered. + +| ID | Name | Source | Delta per event | +|----|------|--------|-----------------| +| `0x01` | `CounterPosting` | `Transaction.Postings` (`CreatedTransaction`) + `RevertTransaction.Postings` (`RevertedTransaction`) | `+len(Postings)` per applicable log | +| `0x02` | `CounterRevert` | `RevertTransactionOrder` unmarshalled from `AuditItem.SerializedOrder` (covers both direct and mirror-ingested reverts) | `+1` per **successful** revert (gated on the produced log being a `RevertedTransaction`; a skipped order — `OrderSkipped` log — counts nothing) | +| `0x03` | `CounterNumscriptExecution` | `CreateTransactionOrder` with a non-empty `Script.Plain` or a non-nil `NumscriptReference` | `+1` per **successful** order (gated on a produced `CreatedTransaction`; skips count nothing) | +| `0x04` | `CounterReference` | `CreateTransactionOrder.Reference != ""` | `+1` per **successful** order (gated on a produced `CreatedTransaction`; skips count nothing) | +| `0x05` | `CounterEphemeralEvicted` | `len(LedgerLog.EphemeralVolumes)` per log — the pure-ephemeral tuples (new + purged same log) | `+len(EphemeralVolumes)` | +| `0x06` | `CounterTransientUsed` | `len(AppliedProposal.TransientVolumes[ledger].Volumes)` — batch-level, keyed by audit sequence | `+len(TransientVolumes[ledger])` per proposal | +| `0x07` | `CounterVolume` | `len(LedgerLog.NewKeptVolumes) − len(LedgerLog.PurgedVolumes)` per log | net change in live volume-key cardinality | + +Missing keys read as `0`. Every counter clamps at zero on underflow via `applyDelta` — a subsystem bug that emits a spurious `−1` cannot drive the counter into an out-of-band representation. + +## Template Usage + +Per-Numscript-template records live under a separate key shape: + +``` +[usagestore prefix][ledger 64B][template_name] → TemplateUsage { fixed64 count; Timestamp last_used } +``` + +Populated when a `CreateTransactionOrder` carries a non-nil `NumscriptReference`. `last_used` is the order's `Timestamp` (deterministic — same on every replica). Multiple invocations in the same batch fold via max on `last_used` and sum on `count`. + +Read path: `GET /v3/{ledger}/numscripts/{name}/usage` (`internal/adapter/http/handlers_get_numscript_usage.go`) — returns the persisted `TemplateUsage` proto or a zero-valued one when the template has never been invoked (not a 404). + +## The Log-Payload Contract + +Six of the seven counters plus template usage need FSM-side annotations on the log or the audit chain. Two categories: + +- **Straight from the raw order** (posting, revert, numscript-exec, reference, template usage): no FSM enrichment needed — the fields are already on `raftcmdpb.CreateTransactionOrder` / `RevertTransactionOrder`, which the usagebuilder unmarshalls from `AuditItem.SerializedOrder`. +- **Volume annotations on the log** (ephemeral evicted, volume count): the FSM computes three DISJOINT per-log lists during `WriteSet.Merge` and injects them into the `LedgerLog` message. + +### `LedgerLog` volume annotations + +`misc/proto/common.proto` — three disjoint fields on `LedgerLog`: + +```protobuf +message LedgerLog { + LedgerLogPayload data = 1; + Timestamp date = 2; + fixed64 id = 3; + repeated TouchedVolume purged_volumes = 4; // DRAINING only + repeated TouchedVolume new_kept_volumes = 5; // new + survives + repeated TouchedVolume ephemeral_volumes = 6; // new + purged same log +} +``` + +The three sets partition every volume update the log touched into DISJOINT categories: + +| Category | Prior value | Post-commit state | Field | +|----------|-------------|-------------------|-------| +| Draining | non-zero in Pebble | evicted (zero balance) | `purged_volumes` | +| New + kept | undefined or zero placeholder | persisted | `new_kept_volumes` | +| Pure ephemeral | undefined or zero placeholder | evicted (zero balance) | `ephemeral_volumes` | +| Normal update | defined + non-zero | still persisted (updated value) | (none — no annotation needed) | +| Transient | any | never persisted | (none — carried on `AppliedProposal.TransientVolumes` at batch level) | + +### Why disjoint (and not overlapping) + +An earlier encoding included ephemeral tuples in BOTH `purged_volumes` (as "evicted") and `new_volumes` (as "newly created"). Every ephemeral (account, asset) tuple paid its wire cost twice. On workloads with high ephemeral throughput (payout fan-out, escrow pass-throughs — 100+ ephemeral accounts per transaction is normal), the doubling adds a few MB/s of WAL / audit-chain growth for no functional benefit — the ephemeral net delta on `VolumeCount` is +0. + +The disjoint encoding pays exactly `len(ephemeral)` per log instead of `2 × len(ephemeral)`. The three lists are still complete: consumers that need "everything evicted from Pebble" take the union (see [indexer consumer](#indexer-consumer)); the volume-count formula becomes clean subtraction (`new_kept − purged`) with ephemeral contributing zero. + +### FSM emission + +`internal/infra/state/write_set.go` computes the three sets during `Merge`: + +1. `partitionVolumes(volumeUpdates)` (existing) yields `partResult.{kept, purged, transient}`. +2. `splitPurged(partResult.purged)` (new, in `write_set_new_volumes.go`) partitions `purged` further into: + - **ephemeral**: `!Old.IsDefined() || isVolumePreloadZero(Old.Value())` — the key had no prior state, was touched, immediately purged. + - **draining**: `Old.IsDefined() && !isVolumePreloadZero(Old.Value())` — had a prior non-zero balance, drained to zero, evicted. +3. `makeNewKeptKeySet(partResult.kept)` (new) yields the subset of `kept` where `Old` was undefined / zero-placeholder — i.e. new persistent volumes. +4. `buildTouchedByLog(volumes.Slots(), setX)` (new, generalised from the previous `buildPurgedByLog`) intersects the per-order touched-volume tracking with each of the three sets to produce the per-log annotation lists. Deduplication + deterministic sort by (account, asset) keeps the log payload byte-identical across nodes. + +The three lists are injected into each `LedgerLog` inside the same `createdLogs` build loop that also injects `purged_volumes`. Note the audit hash chain does **not** cover `LedgerLog` content — it binds the audit header plus each item's order index, log sequence, and serialized order (see [Checker consumer](#checker-consumer) for what this means for tamper detection of the derived counters). + +### The preload contract this depends on + +The classification "new vs existing" is decided by the preloaded prior value at merge time — specifically `Update.Old.IsDefined()` combined with the zero-placeholder check. This is safe **because volume preload is structurally required by the FSM**: balance checks, Uint256 arithmetic and numscript resolution all read the current volume value, so admission has to preload every touched key. That contract is documented as invariant #6 in AGENTS.md. + +The comparable metadata preload was removed opportunistically once the indexer no longer needed it — the corresponding `MetadataCount` counter had to be dropped (see the EN-1420 commit) because `Old.IsDefined()` no longer distinguished "new key" from "overwrite" on the metadata merge. The volume analog holds because the FSM cannot function without those old values. + +## Usagestore Layout + +``` +[template_prefix][ledger 64B][template_name] → TemplateUsage proto +[counter_prefix][ledger 64B][counter_id 1B] → uint64 BE +[0xFE][0x01] → progress cursor (uint64 BE, last consumed audit sequence) +``` + +Full keyspace conventions in `internal/storage/usagestore/keys.go`. The `[ledger 64B]` block is zero-padded fixed-width (`dal.LedgerNameFixedSize`) so the comparer can extract a per-ledger prefix for bloom-filter scoping — same technique as the readstore. + +## Consumers + +### API — `GetLedgerStats` reader + +`internal/application/ctrl/controller_default.go` — opens a single `usagestore.Snapshot` and routes all seven counter Gets through it. See [usagebuilder.md § Snapshot on the reader side](usagebuilder.md#snapshot-on-the-reader-side). + +### API — template usage endpoint + +`internal/adapter/http/handlers_get_numscript_usage.go` → `ctrl.Controller.GetTemplateUsage` → `usagestore.GetTemplateUsage`. Single point-read against the live store (no snapshot needed for a single-value query). + +### Indexer consumer + +`internal/application/indexbuilder/applied_proposal_sync.go`'s `extractPurgedVolumes` returns the UNION of `LedgerLog.PurgedVolumes ∪ LedgerLog.EphemeralVolumes` because both categories share the same downstream treatment (Pebble entry gone → skip acct→tx mapping). The protowire fast path (`protowire_postings.go`) parses field 6 alongside field 4 and exposes `GetEphemeralVolumes` on `parsedLog`. + +### Checker consumer + +`compareExclusionProjections` (`internal/application/check/checker.go`) accumulates `PurgedVolumes` and `EphemeralVolumes` from every log into the stored projection set, then compares against the exclusion set derived by replaying the audit chain (`AppliedProposal.TransientVolumes` union). Both eviction lists have identical semantics for the checker — the split is a pure log-payload compaction, not an invariant change. This pass verifies the exclusion projection *in the primary store* — the set the indexbuilder consumes. + +### Why the usagestore counters are not a checker target (design decision, not a gap) + +The checker (invariant #8) verifies projections persisted **in the primary Pebble store** — the store it operates on: `Volume`, `Metadata`, `Transaction`, `Reference`, `Boundary`, idempotency outcomes, the index registry, and the exclusion projection above. The usagestore is a **distinct, peer secondary Pebble instance** (`/usage/`) holding a *derived cache* of counters, rebuilt from the audit chain by the boot/tick fold, which folds forward from the persisted cursor (from an empty cursor, i.e. `usagestore.Reset()` or a wiped `/usage/`, that replays from audit sequence 0). There is no automatic rollback rewind — the audit chain is append-only, so the cursor never sits ahead of the head. Its authoritativeness is explicitly bounded by "eventually consistent with the FSM". + +Consequently, the three volume-annotation categories are deliberately **not** given a dedicated usagestore checker pass: + +- `NewKeptVolumes` has **no** primary-store consumer — it feeds only `CounterVolume` in the usagestore. +- The primary-store-relevant signal, the exclusion set `PurgedVolumes ∪ EphemeralVolumes` consumed by the indexbuilder, **is** already verified by `compareExclusionProjections` above. The indexbuilder consumes the union and is indifferent to the Purged-vs-Ephemeral split, so the union is the correct verification granularity for the primary store. + +Corruption of a usagestore counter is therefore a *rebuild*, not an integrity incident: the recovery contract is "drop and replay from the audit chain", and the audit chain itself **is** cryptographically verified (`verifyAuditHashChain`). Serving a derived, rebuildable value through `GetLedgerStats` / `GetTemplateUsage` does not make it authoritative primary-store state. Extending audit-derived tamper coverage to the usagestore counters (which would require threading a new-volume collector through the shared `internal/domain/replay` package, also used by backup restore) is a separately-scoped effort tracked under EN-1422 — not a prerequisite for this subsystem. + +## Metrics + +Registered in `misc/devenv/monitoring-dashboards/jsonnet/lib/metrics.libsonnet`: + +| Metric | Description | +|--------|-------------| +| `usage.builder.last_indexed_sequence` | Highest audit sequence the builder has committed for this replica. | +| `usage.builder.audit_last_sequence` | Highest audit sequence present in Pebble on this replica. | +| `usage.builder.lag` | Difference between the two (indicator of the eventual-consistency window). | +| `usagestore.level.bytes` / `memtable.bytes` / `cache.hits` / `cache.misses` | Pebble-internal metrics for the usagestore instance (parallel to the readindex namespace). | + +The three progress gauges are registered through `tailworker.RegisterTailGauges` — the same helper the audit indexer uses — so the naming pattern (`{ns}.last_indexed_sequence`, `{ns}.{source}_last_sequence`, `{ns}.lag`) stays consistent across every tail-worker subsystem. diff --git a/docs/technical/architecture/subsystems/usage/usagebuilder.md b/docs/technical/architecture/subsystems/usage/usagebuilder.md new file mode 100644 index 0000000000..e47a1fddd9 --- /dev/null +++ b/docs/technical/architecture/subsystems/usage/usagebuilder.md @@ -0,0 +1,142 @@ +# Usagebuilder Pipeline + +## Overview + +The **usagebuilder** (`internal/application/usagebuilder`) is the background goroutine that turns committed audit entries into per-ledger housekeeping counters + per-Numscript-template invocation records. It runs on every node, tails the FSM audit chain, and writes to the **usagestore** — a Pebble instance dedicated to usage projections, peer to the read store. + +This page covers the pipeline mechanics. For the **what** of counters (definitions, storage keys, log-payload plumbing), see [counters.md](counters.md). + +## Why the audit chain, not the log stream + +The subsystem tails `AuditEntry + AuditItem` (`ZoneCold` / `SubColdAudit` + `SubColdAuditItem`), not `ZoneCold` / `SubColdLog`. The reason is Numscript template usage: the log's `CreatedTransaction` payload does not carry the `NumscriptReference` of the order — only the resolved postings and metadata. The reference survives on `AuditItem.SerializedOrder`, which is the deterministic serialised bytes of the original `raftcmdpb.Order`. Reading the audit chain lets the usagebuilder unmarshal the order, extract `NumscriptReference.Name` for template tracking, and decide whether the order should feed the numscript-execution counter. + +For counters that live on the log directly (posting count, purge lists), the usagebuilder fetches the specific log at `AuditItem.LogSequence` via `query.ReadLogBySequence` — a single point read on the hot Pebble cache. + +## Builder Lifecycle + +### Wake-up + +```mermaid +flowchart LR + FSM["FSM Commit
infra/state/machine.go"] -->|NotifyLogsCommitted| SIG["signal.Notifications.LogCommitted
name:\"usage\" FanOut target"] + SIG -->|select case| LOOP["Builder.loop()"] + TICK["100 ms Ticker"] -->|fallback case| LOOP +``` + +| Trigger | Source | +|---------|--------| +| FSM commit signal | `signal.Notifications.LogCommitted.C()` — fired by the FSM via `NotifyLogsCommitted(lastSeq)`. The FanOut in `bootstrap/module.go` dispatches to a dedicated `name:"usage"` `Notifications` so the usagebuilder does not compete with the indexer, events, or mirror consumers. | +| 100 ms fallback ticker | `time.NewTicker(100 * time.Millisecond)` in `Builder.loop()`. Same rationale as the indexer's — bound query staleness even if the signal layer is starved. | +| Cancellation | `ctx.Done()` (wired through `worker.Worker`). | + +### Constructor injection for notifications + +Unlike the indexer (which uses `SetNotifications` after construction), the usagebuilder receives its `*signal.Notifications` through the `NewBuilder` constructor — the fx graph passes the correctly-tagged `Notifications` at wire time. See `feedback_constructor_injection` in the project memory: setters create a hidden init protocol that constructor parameters do not. + +### Boot + +On `Start()`, the builder: + +1. Reads the persisted progress cursor from `usagestore` (key `[0xFE][0x01]` — highest processed audit sequence). +2. Samples the current audit-chain head via `query.ReadLastAuditSequence` on a short-lived read handle. The handle is closed immediately to release the `dbMu.RLock` so a concurrent `RestoreCheckpoint` is not blocked while the builder is idle. +3. Runs an **initial catch-up pass** with a larger batch size (`max(configured, 2_000)`), split into 5-second slices so a single Pebble snapshot is not held for the full catch-up duration on large stores. Between slices the snapshot is released; between passes cache-warmed reads keep it cheap. + +## `processAuditEntries` — Batched Commit + +```mermaid +flowchart TB + A[Open Pebble read handle on FSM main store] --> B[Open audit-chain cursor at persisted seq] + B --> C{Iterate AuditEntry} + C -->|Success outcome| D[Fetch AppliedProposal by audit_seq] + C -->|Failure outcome| C + D --> E[Feed TransientVolumes → CounterTransientUsed] + E --> F[Read AuditItems for entry] + F --> G{Iterate items} + G -->|LogSequence == 0| G + G -->|non-zero| H[Unmarshal SerializedOrder → raftcmdpb.Order] + H --> I[dispatchOrder — switch on Apply payload] + I --> J[Fetch log via ReadLogBySequence for posting / volume counts] + J --> K[Accumulate counter + template deltas in batchState] + K --> G + G -->|EOF for entry| C + C -->|batchCount reached OR EOF| L[commitBatch: apply deltas + advance cursor] +``` + +`internal/application/usagebuilder/process_audit.go`. + +### Pass 1 — collect + +- Opens a direct Pebble read handle on the FSM main store (`b.pebbleStore.NewDirectReadHandle()`). +- Opens an audit-entry cursor at `cursor + 1` (`query.ReadAuditEntries(ctx, handle, &cursor)`). +- For each entry: + - Failure outcomes are skipped — no state change to project. + - For successful entries, fetches the matching `AppliedProposal` (`query.ReadAppliedProposal(ctx, handle, entry.GetSequence())`) once. Its `TransientVolumes` map (per-ledger) feeds `CounterTransientUsed` — a single per-entry Get that avoids re-reading it per item. + - Reads all `AuditItem` rows for the entry (`query.ReadAuditItems`). + - For each item with `LogSequence != 0` (skipping idempotent replays and non-log-producing orders), unmarshals `SerializedOrder` and dispatches on the order variant. `dispatchCreateTransaction` and `dispatchRevertTransaction` fetch the produced log via `ReadLogBySequence` to extract resolved posting count + the three volume-annotation lists — see [counters.md](counters.md) for the fields. +- All deltas accumulate into a per-batch `batchState` (per-ledger counter map + per-(ledger, template) usage map). + +### Pass 2 — commit + +`commitBatch` does read-modify-write against the usagestore in a single Pebble batch: + +1. For each `(ledger, counterID)` in the batch state, `Get` the current counter, apply the signed delta with `applyDelta` (clamps at zero on underflow), `PutCounter` the new value. +2. For each `(ledger, template)` template delta, `Get` the current `TemplateUsage` proto, fold the batch aggregation into it (add counts, take max of `last_used` timestamps), `PutTemplateUsage`. +3. `WriteProgress(batch, lastAuditSeq)` — persists the cursor in the **same batch** as the counter mutations. +4. `batch.Commit()`. + +The invariant is the same as the indexer's two-pass commit: cursor and counter deltas move atomically. A crash mid-batch either commits both or neither — the loop resumes cleanly on restart. + +### Batch sizing + +Default is 200 audit entries per commit (`DefaultBatchSize` in `builder.go`). Higher during initial catch-up (`max(configured, 2_000)`). The trade-off is Pebble fsync frequency vs snapshot lifetime — the same one the indexer solves with `catchUpBudget = 5 * time.Second`. + +## Snapshot on the reader side + +`GetLedgerStats` reads seven counters (posting, revert, numscript-exec, reference, ephemeral, transient, volume) plus optional template-usage records. If each `GetCounter` opened its own Pebble read, a concurrent usagebuilder commit could land between two `Get`s and produce a partial view (e.g. VolumeCount reflects a commit that PostingCount does not). To avoid this the API opens a single `usagestore.Snapshot` and routes all reads through it: + +```go +snap := ctrl.usageStore.NewSnapshot() +defer snap.Close() +stats.PostingCount, _ = snap.GetCounter(ledger, usagestore.CounterPosting) +// … all six other event counters read from the same snap +``` + +`Snapshot` wraps `*pebble.Snapshot` and re-exposes the read helpers. Writes stay batched atomically on the usagebuilder side; reads see a consistent point-in-time view. + +## Failure semantics + +| Failure mode | What survives | What replays | +|--------------|---------------|--------------| +| Usagebuilder crash mid-batch | Cursor at last successful commit; committed counter deltas are durable | Loop restarts, reads persisted cursor, resumes from `cursor + 1`. | +| Cold-storage archival of an early chapter | Nothing lost — counters already applied by the usagebuilder are persisted in usagestore | Cursor stays past the archived range; no re-processing. | +| Ledger deletion (audit log `DeleteLedger`) | Usagestore range-deletes every counter + template row keyed on the ledger via `DeleteLedger(batch, ledgerName)` | Re-created ledgers start at zero counters; audit-chain history for the old incarnation is idempotent to re-process. | +| Primary store rolled back beneath the persisted cursor | Nothing — `usagestore.Reset()` drops every counter + template row and clears the cursor | The next boot/tick replays from audit sequence 0 into the freshly-reset store. | + +## Cutover semantics + +The migration that introduced this subsystem (EN-1420 / EN-1422) moved every non-ID-generator counter off `LedgerBoundaries` and onto the usagestore. On production upgrade, each ledger's counters **reset to 0** and repopulate from the earliest audit entry still reachable in Pebble. Historic pre-upgrade values are lost — accepted trade-off. Fresh ledgers boot with a genesis-derived count that matches the FSM. + +## Snapshot / restore + +The usagestore is not part of Pebble snapshots or backups: it is a projection that is trivially rebuildable from the audit chain. On restore, the running usagebuilder catches up organically from wherever its persisted cursor points; if the primary store was rolled back beneath that cursor, `usagestore.Reset()` fires on the next boot/tick and the projection repopulates from audit sequence 0. + +The audit chain remains the source of truth in every case. + +> **3.0 limitation.** There is no offline drop-and-rebuild-from-scratch command. The now-removed `ledgerctl store rebuild-usage` replayed the audit chain from sequence 0 over the self-purging primary store, which undercounts `VolumeCount` once a chapter has been archived (the volumes touched by archived entries are gone from the reachable audit). Rather than ship a rebuild that lies, offline rebuild is deferred to 3.1, where it will seed `VolumeCount` from live `SubAttrVolume` state instead of replaying archived history. In 3.0, reconvergence relies exclusively on the online boot/tick fold + `Reset()`. + +## Integrity verification (checker scope) + +The usagestore is **deliberately excluded from `internal/application/check/checker.go`**. Invariant #8 ("every persisted projection must be verified by the checker") is scoped to projections that live in the **primary** Pebble store — the store that participates in Pebble snapshots, backups and cold-storage, and that an operator cannot rebuild without stopping the cluster. The usagestore, like the read store (`readstore`), is a physically separate secondary Pebble instance at `/usage/`: it is never snapshotted, never backed up, and is rebuildable from the audit chain via the online boot/tick fold (and `usagestore.Reset()` on rollback detection). A tampered or corrupted usagestore is therefore not a durable integrity vector — the next fold reconstructs it from the hash-chained audit, which the checker *does* verify. Extending the checker to walk a peer store would couple it to a subsystem it has no authority over and duplicate the rebuild logic that already re-derives every counter from the same source of truth. + +## Summary + +| Concern | Mechanism | File | +|---------|-----------|------| +| Loop skeleton | `tailworker.TailWorker` — shared boot/tick/wake driver used by every tail-worker subsystem (audit indexer, usagebuilder, …) | `internal/pkg/tailworker/tailworker.go` | +| Wake-up | Dedicated `name:"usage"` `Notifications` from the FSM FanOut fed into the tailworker's `Wake` channel + `TickInterval` fallback | `builder.go` | +| Source | Audit chain (`ReadAuditEntries` + `ReadAuditItems`), not the log stream — needed for Numscript template ref survival | `process_audit.go` | +| Atomicity | `WriteProgress` shares the same Pebble batch as counter / template mutations | `process_audit.go`, `usagestore/store.go` | +| Read consistency | Multi-counter reads via `usagestore.NewSnapshot()` | `usagestore/snapshot.go`, `ctrl/controller_default.go` | +| Isolation | Dedicated Pebble instance at `/usage/`, own comparer, WAL disabled | `usagestore/{store,comparer,keys}.go` | +| Metrics | `tailworker.RegisterTailGauges` — 3 shared gauges (`last_indexed_sequence`, `audit_last_sequence`, `lag`) | `builder.go`, `internal/pkg/tailworker/gauges.go` | +| Rebuild | Online boot/tick fold from the persisted cursor; `usagestore.Reset()` drops rows + replays from 0 on rollback detection (offline rebuild-from-scratch deferred to 3.1 — see Snapshot / restore) | `builder.go`, `usagestore/store.go` | diff --git a/docs/technical/contributing/api-comparison.md b/docs/technical/contributing/api-comparison.md index d2a46151fe..777ff923bf 100644 --- a/docs/technical/contributing/api-comparison.md +++ b/docs/technical/contributing/api-comparison.md @@ -373,6 +373,7 @@ The numscript library allows saving, retrieving, and managing reusable numscript **Endpoints:** - `GET /v3/{ledgerName}/numscripts` - List all saved numscripts for a ledger - `GET /v3/{ledgerName}/numscripts/{name}?version=` - Get a numscript by name (optional version query param) +- `GET /v3/{ledgerName}/numscripts/{name}/usage` - Get invocation count and last-used timestamp for a template - `PUT /v3/{ledgerName}/numscripts/{name}` - Save a numscript (create new version or overwrite latest) - `DELETE /v3/{ledgerName}/numscripts/{name}` - Delete a numscript @@ -395,6 +396,15 @@ When retrieving a numscript via `GET /v3/{ledgerName}/numscripts/{name}`, the `v - `version` (string): Semver version (e.g. `"1.0.0"`) - `createdAt` (string, date-time): Timestamp +**Usage tracking (`GET /v3/{ledgerName}/numscripts/{name}/usage`):** + +Returns per-template invocation counters and the timestamp of the most recent invocation. Populated asynchronously by the `usagebuilder` subsystem, which tails the FSM audit chain and writes to a dedicated secondary Pebble store (`/usage/`). Values are eventually consistent with the FSM and may lag by up to one usagebuilder tick interval (~100 ms). + +A never-invoked template returns a zero-valued response (not 404), so clients handle "never used" uniformly: +- `count` (uint64): Number of times the template has been invoked. `0` means not yet invoked (or the usagebuilder has not caught up). +- `lastUsed` (string, date-time, nullable): Timestamp of the most recent invocation. Absent when count is 0. + +On a fresh ledger the counter builds up organically from cursor=0. On an existing ledger whose audit chain has been partially archived to cold storage, only invocations still present in the primary Pebble store are counted. ### Filter input formats (dual-format contract, EN-1511) Every filtered surface — the list endpoints (`GET .../transactions`, @@ -752,7 +762,7 @@ Read endpoints comparison with the original ledger: | `GET /v3/{ledgerName}/accounts/{address}/volumes` | ❌ | ✅ | Get account volumes | | `GET /v3/{ledgerName}/volumes` | ✅ | ✅ | Aggregate volumes (per-asset, supports prefix filtering) | | `GET /v3/{ledgerName}/logs` | ✅ | ✅ | List per-ledger logs. Supports `?after=` for pagination | -| `GET /v3/{ledgerName}/stats` | ✅ | ✅ | Ledger statistics (account + transaction count) | +| `GET /v3/{ledgerName}/stats` | ✅ | ✅ | Ledger usage statistics (transaction, volume, reference, posting, log, revert, Numscript-execution, ephemeral-evicted and transient-used counts) | | `GET /v3/{ledgerName}` | ✅ | ✅ | Get ledger info | | `POST /v3/{ledgerName}/promote` | ✅ | ❌ | Promote mirror ledger to normal mode | | `GET /v3/` | ✅ | ✅ | List all ledgers | @@ -768,6 +778,7 @@ Read endpoints comparison with the original ledger: | `POST /v3/{ledgerName}/prepared-queries/{queryName}/execute` | ✅ | ❌ | Execute a prepared query | | `GET /v3/{ledgerName}/numscripts` | ✅ | ❌ | List all numscripts for a ledger | | `GET /v3/{ledgerName}/numscripts/{name}?version=` | ✅ | ❌ | Get numscript (semver version, empty = latest) | +| `GET /v3/{ledgerName}/numscripts/{name}/usage` | ✅ | ❌ | Get invocation count + last-used timestamp | | `PUT /v3/{ledgerName}/numscripts/{name}` | ✅ | ❌ | Save numscript (semver versioned) | | `DELETE /v3/{ledgerName}/numscripts/{name}` | ✅ | ❌ | Delete numscript | | `GET /v3/{ledgerName}/account-types` | ✅ | ❌ | List account types | @@ -869,7 +880,7 @@ The POC provides a gRPC API for internal service communication (Raft node forwar | `Discovery` | Return server capabilities (response signing config) and build info (`ServerInfo`: version, commit, build date, Go version) | ✅ | | `AnalyzeAccounts` | Analyze accounts and suggest Chart of Accounts | ✅ | | `GetIndexStatus` | Read index builder progress (lag, file size) | ✅ | -| `GetLedgerStats` | Get aggregate statistics (account + transaction count) | ✅ | +| `GetLedgerStats` | Get aggregate usage statistics (transaction, volume, reference, posting, log, revert, Numscript-execution, ephemeral-evicted and transient-used counts) | ✅ | | `AggregateVolumes` | Per-asset aggregated volumes for filtered accounts | ✅ | | `InspectIndex` | Inspect metadata index (distinct values, facets, summary) | ✅ | diff --git a/internal/adapter/grpc/bucket_service_client_generated_test.go b/internal/adapter/grpc/bucket_service_client_generated_test.go index 79aa42cd32..3ec3224ae5 100644 --- a/internal/adapter/grpc/bucket_service_client_generated_test.go +++ b/internal/adapter/grpc/bucket_service_client_generated_test.go @@ -1098,6 +1098,50 @@ func (c *MockBucketServiceClientGetSecondaryMetricsCall) DoAndReturn(f func(cont return c } +// GetTemplateUsage mocks base method. +func (m *MockBucketServiceClient) GetTemplateUsage(ctx context.Context, in *servicepb.GetTemplateUsageRequest, opts ...grpc.CallOption) (*commonpb.TemplateUsage, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetTemplateUsage", varargs...) + ret0, _ := ret[0].(*commonpb.TemplateUsage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateUsage indicates an expected call of GetTemplateUsage. +func (mr *MockBucketServiceClientMockRecorder) GetTemplateUsage(ctx, in any, opts ...any) *MockBucketServiceClientGetTemplateUsageCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, in}, opts...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateUsage", reflect.TypeOf((*MockBucketServiceClient)(nil).GetTemplateUsage), varargs...) + return &MockBucketServiceClientGetTemplateUsageCall{Call: call} +} + +// MockBucketServiceClientGetTemplateUsageCall wrap *gomock.Call +type MockBucketServiceClientGetTemplateUsageCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockBucketServiceClientGetTemplateUsageCall) Return(arg0 *commonpb.TemplateUsage, arg1 error) *MockBucketServiceClientGetTemplateUsageCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockBucketServiceClientGetTemplateUsageCall) Do(f func(context.Context, *servicepb.GetTemplateUsageRequest, ...grpc.CallOption) (*commonpb.TemplateUsage, error)) *MockBucketServiceClientGetTemplateUsageCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockBucketServiceClientGetTemplateUsageCall) DoAndReturn(f func(context.Context, *servicepb.GetTemplateUsageRequest, ...grpc.CallOption) (*commonpb.TemplateUsage, error)) *MockBucketServiceClientGetTemplateUsageCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // GetTransaction mocks base method. func (m *MockBucketServiceClient) GetTransaction(ctx context.Context, in *servicepb.GetTransactionRequest, opts ...grpc.CallOption) (*servicepb.GetTransactionResponse, error) { m.ctrl.T.Helper() diff --git a/internal/adapter/grpc/client_bucket.go b/internal/adapter/grpc/client_bucket.go index a12a461e25..ab0463ac44 100644 --- a/internal/adapter/grpc/client_bucket.go +++ b/internal/adapter/grpc/client_bucket.go @@ -418,6 +418,13 @@ func (g *BucketGrpcClient) GetNumscript(ctx context.Context, ledger, name string }) } +func (g *BucketGrpcClient) GetTemplateUsage(ctx context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + return g.client.GetTemplateUsage(ctx, &servicepb.GetTemplateUsageRequest{ + Ledger: ledger, + Name: name, + }) +} + func (g *BucketGrpcClient) ListNumscripts(ctx context.Context, ledger string) ([]*commonpb.NumscriptInfo, error) { // Follow x-next-cursor across pages — see ListSigningKeys for the // rationale (this client may wrap a routed leader controller whose diff --git a/internal/adapter/grpc/controller_generated_test.go b/internal/adapter/grpc/controller_generated_test.go index 26698dee8a..b72b69315c 100644 --- a/internal/adapter/grpc/controller_generated_test.go +++ b/internal/adapter/grpc/controller_generated_test.go @@ -747,6 +747,45 @@ func (c *MockControllerGetNumscriptCall) DoAndReturn(f func(context.Context, str return c } +// GetTemplateUsage mocks base method. +func (m *MockController) GetTemplateUsage(ctx context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateUsage", ctx, ledger, name) + ret0, _ := ret[0].(*commonpb.TemplateUsage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateUsage indicates an expected call of GetTemplateUsage. +func (mr *MockControllerMockRecorder) GetTemplateUsage(ctx, ledger, name any) *MockControllerGetTemplateUsageCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateUsage", reflect.TypeOf((*MockController)(nil).GetTemplateUsage), ctx, ledger, name) + return &MockControllerGetTemplateUsageCall{Call: call} +} + +// MockControllerGetTemplateUsageCall wrap *gomock.Call +type MockControllerGetTemplateUsageCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockControllerGetTemplateUsageCall) Return(arg0 *commonpb.TemplateUsage, arg1 error) *MockControllerGetTemplateUsageCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockControllerGetTemplateUsageCall) Do(f func(context.Context, string, string) (*commonpb.TemplateUsage, error)) *MockControllerGetTemplateUsageCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockControllerGetTemplateUsageCall) DoAndReturn(f func(context.Context, string, string) (*commonpb.TemplateUsage, error)) *MockControllerGetTemplateUsageCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // GetTransaction mocks base method. func (m *MockController) GetTransaction(ctx context.Context, ledgerName string, transactionID uint64) (*commonpb.Transaction, *string, error) { m.ctrl.T.Helper() diff --git a/internal/adapter/grpc/server_bucket.go b/internal/adapter/grpc/server_bucket.go index eb3c190607..d3ecb8bbc6 100644 --- a/internal/adapter/grpc/server_bucket.go +++ b/internal/adapter/grpc/server_bucket.go @@ -1431,6 +1431,25 @@ func (impl *BucketServiceServerImpl) GetNumscript(ctx context.Context, req *serv return c.GetNumscript(ctx, req.GetLedger(), req.GetName(), req.GetVersion()) } +// GetTemplateUsage returns the invocation counter + last-used timestamp for +// a Numscript template. Reads are served from the usagebuilder side-store, +// which is eventually consistent with the FSM — no ReadOptions barrier is +// honored on this endpoint (a min-log-sequence wait wouldn't help, since +// the usagebuilder cursor is decoupled from the log cursor). +func (impl *BucketServiceServerImpl) GetTemplateUsage(ctx context.Context, req *servicepb.GetTemplateUsageRequest) (*commonpb.TemplateUsage, error) { + if _, err := internalauth.Authenticate(ctx, impl.authCfg, internalauth.ScopeQueriesRead); err != nil { + return nil, err + } + + c, cleanup, err := impl.readController(ctx, 0) + if err != nil { + return nil, err + } + defer cleanup() + + return c.GetTemplateUsage(ctx, req.GetLedger(), req.GetName()) +} + func (impl *BucketServiceServerImpl) ListNumscripts(req *servicepb.ListNumscriptsRequest, stream servicepb.BucketService_ListNumscriptsServer) error { ctx, span := bucketTracer.Start(stream.Context(), "grpc.ListNumscripts") defer span.End() diff --git a/internal/adapter/http/backend_generated_test.go b/internal/adapter/http/backend_generated_test.go index ed92321b7c..d049c3a829 100644 --- a/internal/adapter/http/backend_generated_test.go +++ b/internal/adapter/http/backend_generated_test.go @@ -787,6 +787,45 @@ func (c *MockBackendGetNumscriptCall) DoAndReturn(f func(context.Context, string return c } +// GetTemplateUsage mocks base method. +func (m *MockBackend) GetTemplateUsage(ctx context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateUsage", ctx, ledger, name) + ret0, _ := ret[0].(*commonpb.TemplateUsage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateUsage indicates an expected call of GetTemplateUsage. +func (mr *MockBackendMockRecorder) GetTemplateUsage(ctx, ledger, name any) *MockBackendGetTemplateUsageCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateUsage", reflect.TypeOf((*MockBackend)(nil).GetTemplateUsage), ctx, ledger, name) + return &MockBackendGetTemplateUsageCall{Call: call} +} + +// MockBackendGetTemplateUsageCall wrap *gomock.Call +type MockBackendGetTemplateUsageCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockBackendGetTemplateUsageCall) Return(arg0 *commonpb.TemplateUsage, arg1 error) *MockBackendGetTemplateUsageCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockBackendGetTemplateUsageCall) Do(f func(context.Context, string, string) (*commonpb.TemplateUsage, error)) *MockBackendGetTemplateUsageCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockBackendGetTemplateUsageCall) DoAndReturn(f func(context.Context, string, string) (*commonpb.TemplateUsage, error)) *MockBackendGetTemplateUsageCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // GetTransaction mocks base method. func (m *MockBackend) GetTransaction(ctx context.Context, ledgerName string, transactionID uint64) (*commonpb.Transaction, *string, error) { m.ctrl.T.Helper() diff --git a/internal/adapter/http/handler.go b/internal/adapter/http/handler.go index cb3509bed5..130e32bbb1 100644 --- a/internal/adapter/http/handler.go +++ b/internal/adapter/http/handler.go @@ -108,6 +108,7 @@ func NewHandler(logger logging.Logger, backend Backend, authCfg internalauth.Aut r.Get("/{ledgerName}/logs", server.handleListLedgerLogs) r.Get("/{ledgerName}/numscripts", server.handleListNumscripts) r.Get("/{ledgerName}/numscripts/{name}", server.handleGetNumscript) + r.Get("/{ledgerName}/numscripts/{name}/usage", server.handleGetNumscriptUsage) r.Get("/{ledgerName}/indexes", server.handleListLedgerIndexes) r.Get("/{ledgerName}/indexes/{canonicalId}", server.handleGetIndex) r.Get("/{ledgerName}/indexes/{canonicalId}/status", server.handleGetIndexEntryStatus) diff --git a/internal/adapter/http/handlers_get_ledger_stats.go b/internal/adapter/http/handlers_get_ledger_stats.go index 0a2283e126..4a6cdbcdd5 100644 --- a/internal/adapter/http/handlers_get_ledger_stats.go +++ b/internal/adapter/http/handlers_get_ledger_stats.go @@ -10,7 +10,6 @@ import ( type ledgerStatsJSON struct { TransactionCount uint64 `json:"transactionCount"` VolumeCount uint64 `json:"volumeCount"` - MetadataCount uint64 `json:"metadataCount"` ReferenceCount uint64 `json:"referenceCount"` PostingCount uint64 `json:"postingCount"` LogCount uint64 `json:"logCount"` @@ -24,7 +23,6 @@ func toLedgerStatsJSON(stats *commonpb.LedgerStats) *ledgerStatsJSON { return &ledgerStatsJSON{ TransactionCount: stats.GetTransactionCount(), VolumeCount: stats.GetVolumeCount(), - MetadataCount: stats.GetMetadataCount(), ReferenceCount: stats.GetReferenceCount(), PostingCount: stats.GetPostingCount(), LogCount: stats.GetLogCount(), diff --git a/internal/adapter/http/handlers_get_ledger_stats_test.go b/internal/adapter/http/handlers_get_ledger_stats_test.go index 6722e5e086..0245a168b8 100644 --- a/internal/adapter/http/handlers_get_ledger_stats_test.go +++ b/internal/adapter/http/handlers_get_ledger_stats_test.go @@ -29,7 +29,6 @@ func TestHandleGetLedgerStats_Success(t *testing.T) { return &commonpb.LedgerStats{ TransactionCount: 100, VolumeCount: 42, - MetadataCount: 10, ReferenceCount: 5, PostingCount: 200, }, nil @@ -48,7 +47,6 @@ func TestHandleGetLedgerStats_Success(t *testing.T) { wrapper := decodeResponse[BaseResponse[ledgerStatsJSON]](t, w) require.Equal(t, uint64(100), wrapper.Data.TransactionCount) require.Equal(t, uint64(42), wrapper.Data.VolumeCount) - require.Equal(t, uint64(10), wrapper.Data.MetadataCount) require.Equal(t, uint64(5), wrapper.Data.ReferenceCount) require.Equal(t, uint64(200), wrapper.Data.PostingCount) } @@ -75,7 +73,6 @@ func TestHandleGetLedgerStats_EmptyLedger(t *testing.T) { wrapper := decodeResponse[BaseResponse[ledgerStatsJSON]](t, w) require.Equal(t, uint64(0), wrapper.Data.TransactionCount) require.Equal(t, uint64(0), wrapper.Data.VolumeCount) - require.Equal(t, uint64(0), wrapper.Data.MetadataCount) require.Equal(t, uint64(0), wrapper.Data.ReferenceCount) require.Equal(t, uint64(0), wrapper.Data.PostingCount) } diff --git a/internal/adapter/http/handlers_get_numscript_usage.go b/internal/adapter/http/handlers_get_numscript_usage.go new file mode 100644 index 0000000000..78d62484c2 --- /dev/null +++ b/internal/adapter/http/handlers_get_numscript_usage.go @@ -0,0 +1,71 @@ +package http + +import ( + "errors" + "net/http" + "time" + + "github.com/go-chi/chi/v5" + + "github.com/formancehq/ledger/v3/internal/proto/commonpb" +) + +// templateUsageJSON is the camelCase JSON DTO for TemplateUsage. It +// matches the OpenAPI contract for `GET /v3/{ledger}/numscripts/{name}/usage`: +// +// { "count": , "lastUsed": "" } +// +// Emitting the raw protobuf struct would leak snake_case field tags +// (`last_used`) and the wire encoding of Timestamp (`{data: }`) — +// neither of which is what the API contract promises. +type templateUsageJSON struct { + Count uint64 `json:"count"` + LastUsed *string `json:"lastUsed,omitempty"` +} + +func toTemplateUsageJSON(usage *commonpb.TemplateUsage) *templateUsageJSON { + out := &templateUsageJSON{Count: usage.GetCount()} + + // Gate on nil only: a non-nil Timestamp is a real value even when Data==0 + // (the Unix epoch, 1970-01-01T00:00:00Z). nil already encodes "never + // used" via the omitempty pointer — folding Data==0 into that branch + // would silently drop a legitimate epoch lastUsed from the response. + if ts := usage.GetLastUsed(); ts != nil { + // Timestamp.Data is Unix microseconds — use the canonical AsTime() + // converter (time.UnixMicro) rather than treating Data as nanoseconds. + formatted := ts.AsTime().UTC().Format(time.RFC3339Nano) + out.LastUsed = &formatted + } + + return out +} + +// handleGetNumscriptUsage handles GET /{ledgerName}/numscripts/{name}/usage. +// Returns the invocation counter + last-used timestamp populated by the +// usagebuilder subsystem. Values are eventually consistent with the FSM +// (may lag by up to one usagebuilder tick). A never-invoked template on +// an existing ledger returns a zero-valued response, not a 404 — clients +// treat 0 uniformly. Unknown / soft-deleted ledgers surface a 404 (via +// the underlying controller). +func (s *Server) handleGetNumscriptUsage(w http.ResponseWriter, r *http.Request) { + ledgerName, ok := requireLedgerName(w, r) + if !ok { + return + } + + name := chi.URLParam(r, "name") + if name == "" { + writeBadRequest(w, "INVALID_REQUEST", errors.New("numscript name is required")) + + return + } + + usage, err := s.backend.GetTemplateUsage(r.Context(), ledgerName, name) + if err != nil { + handleError(w, r, err) + + return + } + + writeOK(w, toTemplateUsageJSON(usage)) +} diff --git a/internal/adapter/http/handlers_get_numscript_usage_test.go b/internal/adapter/http/handlers_get_numscript_usage_test.go new file mode 100644 index 0000000000..7cc55f8a18 --- /dev/null +++ b/internal/adapter/http/handlers_get_numscript_usage_test.go @@ -0,0 +1,279 @@ +package http + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + logging "github.com/formancehq/go-libs/v5/pkg/observe/log" + + internalauth "github.com/formancehq/ledger/v3/internal/adapter/auth" + "github.com/formancehq/ledger/v3/internal/pkg/version" + "github.com/formancehq/ledger/v3/internal/proto/commonpb" +) + +// TestToTemplateUsageJSON_EpochLastUsed is the regression guard for the +// dropped-epoch bug: a non-nil lastUsed at Data==0 (the Unix epoch) must be +// emitted, not silently omitted. nil is the only "never used" sentinel. +func TestToTemplateUsageJSON_EpochLastUsed(t *testing.T) { + t.Parallel() + + out := toTemplateUsageJSON(&commonpb.TemplateUsage{ + Count: 3, + LastUsed: &commonpb.Timestamp{Data: 0}, + }) + + require.NotNil(t, out.LastUsed, "a non-nil epoch timestamp must be present, not omitted") + assert.Equal(t, "1970-01-01T00:00:00Z", *out.LastUsed, "Data==0 is the Unix epoch, formatted from microseconds") + assert.Equal(t, uint64(3), out.Count) +} + +// TestToTemplateUsageJSON_NilLastUsedOmitted confirms nil (never invoked) +// still drops lastUsed from the JSON (omitempty on the pointer). +func TestToTemplateUsageJSON_NilLastUsedOmitted(t *testing.T) { + t.Parallel() + + out := toTemplateUsageJSON(&commonpb.TemplateUsage{Count: 0}) + require.Nil(t, out.LastUsed) + + raw, err := json.Marshal(out) + require.NoError(t, err) + assert.JSONEq(t, `{"count":0}`, string(raw), "nil lastUsed must be omitted, not serialized as null") +} + +// TestToTemplateUsageJSON_MicrosecondUnitAndCamelCase locks the two sibling +// contract points flemzord flagged alongside the epoch bug: +// - the DTO serializes camelCase (`lastUsed`, `count`) with no raw protobuf +// tags (`last_used`) or wire encoding (`{data: }`); +// - Timestamp.Data is interpreted as microseconds, not nanoseconds. +func TestToTemplateUsageJSON_MicrosecondUnitAndCamelCase(t *testing.T) { + t.Parallel() + + // 1_700_000_000_000_000 µs = 2023-11-14T22:13:20Z. If Data were treated + // as nanoseconds the year would collapse to 1970. + out := toTemplateUsageJSON(&commonpb.TemplateUsage{ + Count: 42, + LastUsed: &commonpb.Timestamp{Data: 1_700_000_000_000_000}, + }) + + require.NotNil(t, out.LastUsed) + assert.Equal(t, "2023-11-14T22:13:20Z", *out.LastUsed, "Data must be read as microseconds") + + raw, err := json.Marshal(out) + require.NoError(t, err) + assert.JSONEq(t, `{"count":42,"lastUsed":"2023-11-14T22:13:20Z"}`, string(raw), + "DTO must be camelCase with no raw protobuf field names or wire encoding") +} + +// TestHandleGetNumscriptUsage_Success drives the handler end-to-end through the +// generated MockBackend: it asserts the writeOK envelope wraps the +// toTemplateUsageJSON payload (count + camelCase lastUsed), and that the handler +// forwards {ledgerName} and {name} to the backend unchanged. +func TestHandleGetNumscriptUsage_Success(t *testing.T) { + t.Parallel() + + backend := NewMockBackend(gomock.NewController(t)) + backend.EXPECT().GetTemplateUsage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + require.Equal(t, "my-ledger", ledger) + require.Equal(t, "payout", name) + + return &commonpb.TemplateUsage{ + Count: 7, + LastUsed: &commonpb.Timestamp{Data: 1_700_000_000_000_000}, + }, nil + }).AnyTimes() + srv := newTestServer(t, backend) + + w := httptest.NewRecorder() + r := newRequest(t, http.MethodGet, "/my-ledger/numscripts/payout/usage", nil, map[string]string{ + "ledgerName": "my-ledger", + "name": "payout", + }) + + srv.handleGetNumscriptUsage(w, r) + + require.Equal(t, http.StatusOK, w.Code) + + wrapper := decodeResponse[BaseResponse[templateUsageJSON]](t, w) + require.Equal(t, uint64(7), wrapper.Data.Count) + require.NotNil(t, wrapper.Data.LastUsed) + assert.Equal(t, "2023-11-14T22:13:20Z", *wrapper.Data.LastUsed) +} + +// TestHandleGetNumscriptUsage_NeverInvoked confirms the zero-valued contract: a +// never-invoked template on an existing ledger yields count 0 and an omitted +// lastUsed, not a 404 (the controller returns a zero TemplateUsage). +func TestHandleGetNumscriptUsage_NeverInvoked(t *testing.T) { + t.Parallel() + + backend := NewMockBackend(gomock.NewController(t)) + backend.EXPECT().GetTemplateUsage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string) (*commonpb.TemplateUsage, error) { + return &commonpb.TemplateUsage{}, nil + }).AnyTimes() + srv := newTestServer(t, backend) + + w := httptest.NewRecorder() + r := newRequest(t, http.MethodGet, "/my-ledger/numscripts/unused/usage", nil, map[string]string{ + "ledgerName": "my-ledger", + "name": "unused", + }) + + srv.handleGetNumscriptUsage(w, r) + + require.Equal(t, http.StatusOK, w.Code) + + wrapper := decodeResponse[BaseResponse[templateUsageJSON]](t, w) + require.Equal(t, uint64(0), wrapper.Data.Count) + require.Nil(t, wrapper.Data.LastUsed, "never-invoked template must omit lastUsed") +} + +// TestHandleGetNumscriptUsage_MissingName asserts that an empty {name} URL param +// is rejected with 400 INVALID_REQUEST before the backend is ever consulted. +func TestHandleGetNumscriptUsage_MissingName(t *testing.T) { + t.Parallel() + + // No EXPECT() on the backend: gomock fails the test if GetTemplateUsage is + // called, proving the handler short-circuits on the missing name. + srv := newTestServer(t, NewMockBackend(gomock.NewController(t))) + + w := httptest.NewRecorder() + r := newRequest(t, http.MethodGet, "/my-ledger/numscripts//usage", nil, map[string]string{ + "ledgerName": "my-ledger", + "name": "", + }) + + srv.handleGetNumscriptUsage(w, r) + + require.Equal(t, http.StatusBadRequest, w.Code) + + errResp := decodeResponse[ErrorResponse](t, w) + assert.Equal(t, "INVALID_REQUEST", errResp.ErrorCode) +} + +// TestHandleGetNumscriptUsage_MissingLedgerName asserts requireLedgerName gates +// an empty {ledgerName} with a 400 before touching the backend. +func TestHandleGetNumscriptUsage_MissingLedgerName(t *testing.T) { + t.Parallel() + + srv := newTestServer(t, NewMockBackend(gomock.NewController(t))) + + w := httptest.NewRecorder() + r := newRequest(t, http.MethodGet, "/numscripts/payout/usage", nil, map[string]string{ + "ledgerName": "", + "name": "payout", + }) + + srv.handleGetNumscriptUsage(w, r) + + require.Equal(t, http.StatusBadRequest, w.Code) + + errResp := decodeResponse[ErrorResponse](t, w) + assert.Equal(t, "INVALID_REQUEST", errResp.ErrorCode) +} + +// TestHandleGetNumscriptUsage_LedgerNotFound confirms the handler routes a +// controller not-found through handleError into a 404. +func TestHandleGetNumscriptUsage_LedgerNotFound(t *testing.T) { + t.Parallel() + + backend := NewMockBackend(gomock.NewController(t)) + backend.EXPECT().GetTemplateUsage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string) (*commonpb.TemplateUsage, error) { + return nil, commonpb.NewNotFoundError("ledger %s not found", "missing") + }).AnyTimes() + srv := newTestServer(t, backend) + + w := httptest.NewRecorder() + r := newRequest(t, http.MethodGet, "/missing/numscripts/payout/usage", nil, map[string]string{ + "ledgerName": "missing", + "name": "payout", + }) + + srv.handleGetNumscriptUsage(w, r) + + require.Equal(t, http.StatusNotFound, w.Code) +} + +// TestHandleGetNumscriptUsage_BackendError confirms a generic backend error is +// sanitized into a 500 via handleError's fallthrough. +func TestHandleGetNumscriptUsage_BackendError(t *testing.T) { + t.Parallel() + + backend := NewMockBackend(gomock.NewController(t)) + backend.EXPECT().GetTemplateUsage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string) (*commonpb.TemplateUsage, error) { + return nil, errors.New("usage store unavailable") + }).AnyTimes() + srv := newTestServer(t, backend) + + w := httptest.NewRecorder() + r := newRequest(t, http.MethodGet, "/my-ledger/numscripts/payout/usage", nil, map[string]string{ + "ledgerName": "my-ledger", + "name": "payout", + }) + + srv.handleGetNumscriptUsage(w, r) + + require.Equal(t, http.StatusInternalServerError, w.Code) +} + +// TestHandleGetNumscriptUsage_NoLeaderError confirms a not-a-leader error maps +// to 503 (mirrors the sibling stats handler test). +func TestHandleGetNumscriptUsage_NoLeaderError(t *testing.T) { + t.Parallel() + + backend := NewMockBackend(gomock.NewController(t)) + backend.EXPECT().GetTemplateUsage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string) (*commonpb.TemplateUsage, error) { + return nil, commonpb.ErrNoLeader + }).AnyTimes() + srv := newTestServer(t, backend) + + w := httptest.NewRecorder() + r := newRequest(t, http.MethodGet, "/my-ledger/numscripts/payout/usage", nil, map[string]string{ + "ledgerName": "my-ledger", + "name": "payout", + }) + + srv.handleGetNumscriptUsage(w, r) + + require.Equal(t, http.StatusServiceUnavailable, w.Code) +} + +// TestHandleGetNumscriptUsage_FullRouteIntegration exercises the route through +// NewHandler + a real HTTP request, proving GET +// /v3/{ledgerName}/numscripts/{name}/usage is wired and the path params reach +// the handler. +func TestHandleGetNumscriptUsage_FullRouteIntegration(t *testing.T) { + t.Parallel() + + backend := NewMockBackend(gomock.NewController(t)) + backend.EXPECT().GetTemplateUsage(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + require.Equal(t, "my-ledger", ledger) + require.Equal(t, "payout", name) + + return &commonpb.TemplateUsage{Count: 3}, nil + }).AnyTimes() + + handler := NewHandler(logging.Testing(), backend, internalauth.AuthConfig{}, version.Info{}) + + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/v3/my-ledger/numscripts/payout/usage", nil) + + handler.ServeHTTP(w, r) + + require.Equal(t, http.StatusOK, w.Code) + + wrapper := decodeResponse[BaseResponse[templateUsageJSON]](t, w) + require.Equal(t, uint64(3), wrapper.Data.Count) +} diff --git a/internal/application/check/checker.go b/internal/application/check/checker.go index cbd7ee1f2a..7471226380 100644 --- a/internal/application/check/checker.go +++ b/internal/application/check/checker.go @@ -540,13 +540,20 @@ func (c *Checker) Check(ctx context.Context, callback func(*servicepb.CheckStore verifySkippedOrder(ledgerName, seq, payload.Apply.GetLog().GetData(), expectedSkippable, chainBound, hasArchivedChapters, baselineReferencesAvailable, baselineChainStateAvailable, callback) - // Accumulate the LedgerLog.PurgedVolumes side of the - // stored projection while we have the log in hand; - // AppliedProposal.TransientVolumes is added in a - // single pass below. + // Accumulate the LedgerLog eviction lists (draining + // = PurgedVolumes, pure ephemeral = EphemeralVolumes) + // into the stored projection while we have the log + // in hand; AppliedProposal.TransientVolumes is added + // in a single pass below. Both eviction lists share + // the same "excluded from normal state" semantics + // — the split exists to compact log payloads on + // ephemeral-heavy workloads (EN-1422). for _, v := range payload.Apply.GetLog().GetPurgedVolumes() { addStored(ledgerName, v.GetAccount(), v.GetAsset(), v.GetColor()) } + for _, v := range payload.Apply.GetLog().GetEphemeralVolumes() { + addStored(ledgerName, v.GetAccount(), v.GetAsset(), v.GetColor()) + } } } } @@ -5216,9 +5223,11 @@ func trackTxID(m map[string]*bitset.Bitset, ledgerName string, txID uint64) { // advanceExpectedBoundaries mirrors the live apply's boundary advancement for // one replayed ledger log: NextLogId past the log id, and — for transaction -// logs — NextTransactionId past the created id plus the posting / revert -// counters. Mirror fill-gap advances and numscript counts ride on the order, -// not the log; collectAuditOrderBoundaryEffects folds those in. +// logs — NextTransactionId past the created id. Mirror fill-gap advances ride +// on the order, not the log; collectAuditOrderBoundaryEffects folds those in. +// The per-ledger usage counters (posting / revert / numscript / volume / +// metadata / reference) live in the usagestore peer secondary store and are +// out of main-store checker scope, so they are not advanced here. func advanceExpectedBoundaries(expected map[string]*raftcmdpb.LedgerBoundaries, ledger string, log *commonpb.LedgerLog) { b, ok := expected[ledger] if !ok { @@ -5230,11 +5239,7 @@ func advanceExpectedBoundaries(expected map[string]*raftcmdpb.LedgerBoundaries, b.NextLogId = next } - var ( - txID uint64 - postings int - isRevert bool - ) + var txID uint64 switch d := log.GetData().GetPayload().(type) { case *commonpb.LedgerLogPayload_CreatedTransaction: @@ -5243,14 +5248,14 @@ func advanceExpectedBoundaries(expected map[string]*raftcmdpb.LedgerBoundaries, return } - txID, postings = tx.GetId(), len(tx.GetPostings()) + txID = tx.GetId() case *commonpb.LedgerLogPayload_RevertedTransaction: revertTx := d.RevertedTransaction.GetRevertTransaction() if revertTx == nil { return } - txID, postings, isRevert = revertTx.GetId(), len(revertTx.GetPostings()), true + txID = revertTx.GetId() default: return } @@ -5258,21 +5263,15 @@ func advanceExpectedBoundaries(expected map[string]*raftcmdpb.LedgerBoundaries, if next := txID + 1; next > b.GetNextTransactionId() { b.NextTransactionId = next } - - b.PostingCount += uint64(postings) - - if isRevert { - b.RevertCount++ - } } // collectAuditOrderBoundaryEffects iterates the post-archive AuditItem rows -// and folds the order-level boundary effects (mirror fill-gap advances, -// numscript executions) into the expected boundaries — the same fold -// backup.RebuildDelta performs on restore. Items with log_sequence 0 (failed -// proposals, idempotent replays) or at/below the archive boundary contribute -// nothing; effects for ledgers without an expectation (deleted, or flagged -// UNKNOWN_LEDGER during replay) are skipped. +// and folds the order-level boundary effects (mirror fill-gap advances) into +// the expected boundaries — the same fold backup.RebuildDelta performs on +// restore. Items with log_sequence 0 (failed proposals, idempotent replays) or +// at/below the archive boundary contribute nothing; effects for ledgers +// without an expectation (deleted, or flagged UNKNOWN_LEDGER during replay) +// are skipped. func (c *Checker) collectAuditOrderBoundaryEffects(reader dal.PebbleReader, archiveEndSeq uint64, expected map[string]*raftcmdpb.LedgerBoundaries) error { iter, err := reader.NewIter(&pebble.IterOptions{ LowerBound: []byte{dal.ZoneCold, dal.SubColdAuditItem}, @@ -5318,44 +5317,21 @@ func (c *Checker) collectAuditOrderBoundaryEffects(reader dal.PebbleReader, arch b.NextTransactionId = next } } - - if effects.IsNumscript { - b.NumscriptExecutionCount++ - } } return iter.Error() } -// countLedgerAttributeKeys counts the stored keys under a ledger's canonical -// prefix in the attribute zone. -func countLedgerAttributeKeys[V proto.Message](attr *attributes.Attribute[V], reader dal.PebbleReader, ledger string) (uint64, error) { - si, err := attr.NewStreamingIter(reader, domain.LedgerScopedPrefix(ledger)) - if err != nil { - return 0, err - } - - defer func() { _ = si.Close() }() - - var count uint64 - for si.Next() { - count++ - } - - return count, si.Err() -} - // compareBoundaries verifies each ledger's stored LedgerBoundaries against the -// checker's re-derivation. The id fields and replay-derivable counters -// (NextTransactionId, NextLogId, PostingCount, RevertCount, -// NumscriptExecutionCount) come from the replayed logs plus the chain-bound -// audit-order effects, baseline-seeded under archiving. The net key counters -// (VolumeCount, MetadataCount, ReferenceCount) are compared against a recount -// of the stored attribute rows they summarize — the rows themselves are -// verified entry-by-entry by compareVolumes / compareMetadata / -// compareReferences, so the verification chain is rows↔audit, counter↔rows. -// EphemeralEvictedCount / TransientUsedCount are informational and excluded -// (cf. compareIndexes' BuildStatus exclusion). +// checker's re-derivation. Only the id fields (NextTransactionId, NextLogId) +// are verified here — they come from the replayed logs plus the chain-bound +// audit-order effects, baseline-seeded under archiving; the mirror high-water +// (last_mirror_v2_log_id) is verified separately by compareMirrorV2LogID. The +// per-ledger usage counters (PostingCount, RevertCount, +// NumscriptExecutionCount, VolumeCount, MetadataCount, ReferenceCount) no +// longer live on LedgerBoundaries — they moved to the usagestore peer +// secondary store and are out of main-store checker scope by construction +// (their integrity is a peer-store rebuild-health concern, not invariant #8). func (c *Checker) compareBoundaries(ctx context.Context, reader dal.PebbleReader, expected map[string]*raftcmdpb.LedgerBoundaries, callback func(*servicepb.CheckStoreEvent)) error { stored := make(map[string]*raftcmdpb.LedgerBoundaries) @@ -5400,21 +5376,6 @@ func (c *Checker) compareBoundaries(ctx context.Context, reader dal.PebbleReader continue } - volumeRows, err := countLedgerAttributeKeys(c.attrs.Volume, reader, name) - if err != nil { - return fmt.Errorf("counting stored volumes for ledger %q: %w", name, err) - } - - metadataRows, err := countLedgerAttributeKeys(c.attrs.Metadata, reader, name) - if err != nil { - return fmt.Errorf("counting stored metadata for ledger %q: %w", name, err) - } - - referenceRows, err := countLedgerAttributeKeys(c.attrs.References, reader, name) - if err != nil { - return fmt.Errorf("counting stored references for ledger %q: %w", name, err) - } - fields := []struct { field string expected uint64 @@ -5422,12 +5383,6 @@ func (c *Checker) compareBoundaries(ctx context.Context, reader dal.PebbleReader }{ {"nextTransactionId", exp.GetNextTransactionId(), st.GetNextTransactionId()}, {"nextLogId", exp.GetNextLogId(), st.GetNextLogId()}, - {"postingCount", exp.GetPostingCount(), st.GetPostingCount()}, - {"revertCount", exp.GetRevertCount(), st.GetRevertCount()}, - {"numscriptExecutionCount", exp.GetNumscriptExecutionCount(), st.GetNumscriptExecutionCount()}, - {"volumeCount", volumeRows, st.GetVolumeCount()}, - {"metadataCount", metadataRows, st.GetMetadataCount()}, - {"referenceCount", referenceRows, st.GetReferenceCount()}, } for _, f := range fields { diff --git a/internal/application/check/checker_test.go b/internal/application/check/checker_test.go index c595426f25..d477a3cb83 100644 --- a/internal/application/check/checker_test.go +++ b/internal/application/check/checker_test.go @@ -222,31 +222,11 @@ func (e *testEngine) processAndCommit(orders ...*raftcmdpb.Order) []*commonpb.Lo require.NoError(e.t, err) } - // Write ledger boundaries with the net key counters the real WriteSet - // maintains via updateBoundaryCounters — each counter equals the number - // of stored rows under the ledger's canonical prefix. + // Write ledger boundaries. The main-store boundary row carries only the id + // fields (NextTransactionId / NextLogId) and the mirror high-water; the + // per-ledger usage counters moved to the usagestore peer secondary store + // and are out of main-store checker scope. for name, b := range e.boundaries { - prefix := string(domain.LedgerScopedPrefix(name)) - b.VolumeCount, b.MetadataCount, b.ReferenceCount = 0, 0, 0 - - for key, vp := range e.volumes { - if strings.HasPrefix(key, prefix) && (vp.GetInput() != nil || vp.GetOutput() != nil) { - b.VolumeCount++ - } - } - - for key := range e.metadata { - if strings.HasPrefix(key, prefix) { - b.MetadataCount++ - } - } - - for key := range e.references { - if strings.HasPrefix(key, prefix) { - b.ReferenceCount++ - } - } - _, err := e.attrs.Boundary.Set(batch, domain.LedgerKey{Name: name}.Bytes(), b) require.NoError(e.t, err) } diff --git a/internal/application/ctrl/controller.go b/internal/application/ctrl/controller.go index bbbea29d78..ebafb97fce 100644 --- a/internal/application/ctrl/controller.go +++ b/internal/application/ctrl/controller.go @@ -79,6 +79,13 @@ type Controller interface { GetNumscript(ctx context.Context, ledger, name string, version string) (*commonpb.NumscriptInfo, error) ListNumscripts(ctx context.Context, ledger string) ([]*commonpb.NumscriptInfo, error) + // GetTemplateUsage returns the invocation counter and last-used timestamp + // for a Numscript template. Reads from the usagebuilder side-store, so + // values may lag the live FSM by up to one tick interval. Returns a + // zero-valued TemplateUsage when the template has never been invoked (or + // the usagebuilder has not caught up to any of its invocations yet). + GetTemplateUsage(ctx context.Context, ledger, name string) (*commonpb.TemplateUsage, error) + // Cluster-wide config operations (read-only) GetChapterSchedule(ctx context.Context) (string, error) GetEventsSinks(ctx context.Context) ([]*commonpb.SinkConfig, []*commonpb.SinkStatus, error) diff --git a/internal/application/ctrl/controller_default.go b/internal/application/ctrl/controller_default.go index 0a0919a09c..eaef052544 100644 --- a/internal/application/ctrl/controller_default.go +++ b/internal/application/ctrl/controller_default.go @@ -30,6 +30,7 @@ import ( "github.com/formancehq/ledger/v3/internal/query" "github.com/formancehq/ledger/v3/internal/storage/dal" "github.com/formancehq/ledger/v3/internal/storage/readstore" + "github.com/formancehq/ledger/v3/internal/storage/usagestore" ) const ( @@ -99,9 +100,17 @@ type DefaultController struct { store *dal.Store attrs *attributes.Attributes readStore *readstore.Store + usageStore *usagestore.Store receiptSigner *receipt.Signer coldReader *coldstorage.ColdReader + // historical is true on clones produced by WithStores — reads are then + // served from a point-in-time checkpoint. usage counters are excluded + // from historical responses because the usagestore does not participate + // in the query-checkpoint mechanism; serving live values inside an + // otherwise historical response would produce a non-deterministic view. + historical bool + applyDuration metric.Int64Histogram } @@ -116,6 +125,7 @@ func NewDefaultController( logger logging.Logger, attrs *attributes.Attributes, readStore *readstore.Store, + usageStore *usagestore.Store, coldReader *coldstorage.ColdReader, receiptSigner *receipt.Signer, meter metric.Meter, @@ -138,6 +148,7 @@ func NewDefaultController( store: store, attrs: attrs, readStore: readStore, + usageStore: usageStore, coldReader: coldReader, receiptSigner: receiptSigner, applyDuration: applyDuration, @@ -260,6 +271,7 @@ func (ctrl *DefaultController) WithStores(store *dal.Store, readStore *readstore clone := *ctrl clone.store = store clone.readStore = readStore + clone.historical = true return &clone } @@ -577,7 +589,19 @@ func (ctrl *DefaultController) GetAccount(ctx context.Context, ledgerName string } // GetLedgerStats returns aggregate statistics for a ledger. -// All counters are O(1) reads from the LedgerBoundaries attribute. +// TransactionCount and LogCount come from the LedgerBoundaries attribute — +// they are ID-generator state used by the FSM itself. Every projected +// counter (PostingCount, RevertCount, NumscriptExecutionCount, +// ReferenceCount, EphemeralEvictedCount, TransientUsedCount, VolumeCount) +// is derived from the audit chain by the usagebuilder and read from the +// usagestore side-store through a single Pebble snapshot — expect up to +// one usagebuilder tick interval of lag behind the live FSM. See EN-1420 +// and EN-1422. +// +// MetadataCount is intentionally not returned: the admission preload no +// longer injects old metadata values, so the FSM-side counter could no +// longer distinguish "new key" from "overwrite". It is disabled until it +// comes back on a sound foundation (open question, no ticket yet). func (ctrl *DefaultController) GetLedgerStats(ctx context.Context, ledgerName string) (*commonpb.LedgerStats, error) { handle, err := ctrl.store.NewReadHandle() if err != nil { @@ -605,20 +629,60 @@ func (ctrl *DefaultController) GetLedgerStats(ctx context.Context, ledgerName st stats.TransactionCount = nextTxID - 1 } - stats.VolumeCount = boundaries.GetVolumeCount() - stats.MetadataCount = boundaries.GetMetadataCount() - stats.ReferenceCount = boundaries.GetReferenceCount() - stats.PostingCount = boundaries.GetPostingCount() - stats.EphemeralEvictedCount = boundaries.GetEphemeralEvictedCount() - stats.TransientUsedCount = boundaries.GetTransientUsedCount() - stats.RevertCount = boundaries.GetRevertCount() - stats.NumscriptExecutionCount = boundaries.GetNumscriptExecutionCount() - if nextLogID := boundaries.GetNextLogId(); nextLogID > 0 { stats.LogCount = nextLogID - 1 } } + // Historical (checkpoint-scoped) reads intentionally return zero + // usage counters: the usagestore is a projection of the LIVE audit + // chain and does not participate in query-checkpoint machinery, so + // serving live counters alongside checkpointed boundary values would + // produce a non-deterministic response for the same checkpoint id. + // This is the same trade-off that keeps read-index rebuild scoped to + // live state — future work can add checkpointed usage projections if + // clients need them. The contract is documented on the openapi /stats + // endpoint so a client can read a checkpoint `0` as "not available at + // this checkpoint" rather than a live value; only TransactionCount / + // LogCount are checkpoint-consistent here. + if ctrl.historical { + return &stats, nil + } + + // Projected counters from the usagebuilder side-store. All reads go + // against a single Pebble snapshot so a concurrent usagebuilder commit + // cannot land a partial view between them. Missing keys read as 0. + usageSnap := ctrl.usageStore.NewSnapshot() + defer func() { _ = usageSnap.Close() }() + + if stats.PostingCount, err = usageSnap.GetCounter(ledgerName, usagestore.CounterPosting); err != nil { + return nil, fmt.Errorf("reading posting counter: %w", err) + } + + if stats.RevertCount, err = usageSnap.GetCounter(ledgerName, usagestore.CounterRevert); err != nil { + return nil, fmt.Errorf("reading revert counter: %w", err) + } + + if stats.NumscriptExecutionCount, err = usageSnap.GetCounter(ledgerName, usagestore.CounterNumscriptExecution); err != nil { + return nil, fmt.Errorf("reading numscript execution counter: %w", err) + } + + if stats.ReferenceCount, err = usageSnap.GetCounter(ledgerName, usagestore.CounterReference); err != nil { + return nil, fmt.Errorf("reading reference counter: %w", err) + } + + if stats.EphemeralEvictedCount, err = usageSnap.GetCounter(ledgerName, usagestore.CounterEphemeralEvicted); err != nil { + return nil, fmt.Errorf("reading ephemeral evicted counter: %w", err) + } + + if stats.TransientUsedCount, err = usageSnap.GetCounter(ledgerName, usagestore.CounterTransientUsed); err != nil { + return nil, fmt.Errorf("reading transient used counter: %w", err) + } + + if stats.VolumeCount, err = usageSnap.GetCounter(ledgerName, usagestore.CounterVolume); err != nil { + return nil, fmt.Errorf("reading volume counter: %w", err) + } + return &stats, nil } @@ -1829,6 +1893,37 @@ func (ctrl *DefaultController) GetNumscript(ctx context.Context, ledger, name st return info, nil } +// GetTemplateUsage returns the invocation counter and last-used timestamp +// for a Numscript template. Values are populated by the usagebuilder +// subsystem asynchronously from the audit chain: a template that was just +// invoked may not yet be reflected here for up to one usagebuilder tick +// (100 ms). Returns a zero-valued TemplateUsage (never nil) when the +// template has never been invoked on an existing ledger. +// +// Ledger existence is validated first so an unknown or soft-deleted ledger +// surfaces a NotFound business error rather than a zero-valued 200 — the +// same contract as GetLedgerStats / GetNumscript. +func (ctrl *DefaultController) GetTemplateUsage(ctx context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + if _, err := query.GetLedgerByName(ctx, ctrl.store, ledger); err != nil { + if errors.Is(err, domain.ErrNotFound) { + return nil, commonpb.NewNotFoundError("ledger %s not found", ledger) + } + + return nil, err + } + + usage, err := ctrl.usageStore.GetTemplateUsage(ledger, name) + if err != nil { + return nil, fmt.Errorf("reading template usage %q/%q: %w", ledger, name, err) + } + + if usage == nil { + return &commonpb.TemplateUsage{}, nil + } + + return usage, nil +} + // ListNumscripts returns the latest version of all numscripts for a ledger. func (ctrl *DefaultController) ListNumscripts(ctx context.Context, ledger string) ([]*commonpb.NumscriptInfo, error) { handle, err := ctrl.store.NewReadHandle() diff --git a/internal/application/ctrl/controller_default_receipt_test.go b/internal/application/ctrl/controller_default_receipt_test.go index b73d307043..ceda14d2be 100644 --- a/internal/application/ctrl/controller_default_receipt_test.go +++ b/internal/application/ctrl/controller_default_receipt_test.go @@ -114,7 +114,8 @@ func newReceiptTestController(t *testing.T, store *dal.Store, attrs *attributes. logger := logging.FromContext(logging.TestingContext()) meter := noop.NewMeterProvider().Meter("test") - return NewDefaultController(nil, store, logger, attrs, nil, nil, signer, meter) + // args: admission, store, logger, attrs, readStore, usageStore, coldReader, receiptSigner, meter + return NewDefaultController(nil, store, logger, attrs, nil, nil, nil, signer, meter) } // GetTransaction on the local path must return a NON-EMPTY receipt when a signer diff --git a/internal/application/ctrl/controller_generated_test.go b/internal/application/ctrl/controller_generated_test.go index aebbc69df8..cf45ef096a 100644 --- a/internal/application/ctrl/controller_generated_test.go +++ b/internal/application/ctrl/controller_generated_test.go @@ -314,6 +314,21 @@ func (mr *MockControllerMockRecorder) GetNumscript(ctx, ledger, name, version an return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNumscript", reflect.TypeOf((*MockController)(nil).GetNumscript), ctx, ledger, name, version) } +// GetTemplateUsage mocks base method. +func (m *MockController) GetTemplateUsage(ctx context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateUsage", ctx, ledger, name) + ret0, _ := ret[0].(*commonpb.TemplateUsage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateUsage indicates an expected call of GetTemplateUsage. +func (mr *MockControllerMockRecorder) GetTemplateUsage(ctx, ledger, name any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateUsage", reflect.TypeOf((*MockController)(nil).GetTemplateUsage), ctx, ledger, name) +} + // GetTransaction mocks base method. func (m *MockController) GetTransaction(ctx context.Context, ledgerName string, transactionID uint64) (*commonpb.Transaction, *string, error) { m.ctrl.T.Helper() diff --git a/internal/application/ctrl/ctrlmock/controller_generated.go b/internal/application/ctrl/ctrlmock/controller_generated.go index 33af9a9496..5f84baef77 100644 --- a/internal/application/ctrl/ctrlmock/controller_generated.go +++ b/internal/application/ctrl/ctrlmock/controller_generated.go @@ -315,6 +315,21 @@ func (mr *MockControllerMockRecorder) GetNumscript(ctx, ledger, name, version an return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNumscript", reflect.TypeOf((*MockController)(nil).GetNumscript), ctx, ledger, name, version) } +// GetTemplateUsage mocks base method. +func (m *MockController) GetTemplateUsage(ctx context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateUsage", ctx, ledger, name) + ret0, _ := ret[0].(*commonpb.TemplateUsage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateUsage indicates an expected call of GetTemplateUsage. +func (mr *MockControllerMockRecorder) GetTemplateUsage(ctx, ledger, name any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateUsage", reflect.TypeOf((*MockController)(nil).GetTemplateUsage), ctx, ledger, name) +} + // GetTransaction mocks base method. func (m *MockController) GetTransaction(ctx context.Context, ledgerName string, transactionID uint64) (*commonpb.Transaction, *string, error) { m.ctrl.T.Helper() diff --git a/internal/application/indexbuilder/applied_proposal_sync.go b/internal/application/indexbuilder/applied_proposal_sync.go index 6643e6fa3b..7a47282398 100644 --- a/internal/application/indexbuilder/applied_proposal_sync.go +++ b/internal/application/indexbuilder/applied_proposal_sync.go @@ -238,17 +238,43 @@ func (s *appliedProposalSync) close() error { return nil } -// extractPurgedVolumes returns the set of purged ephemeral (account, asset) -// volumes declared by THIS log. Empty when the order that produced the log -// did not contribute to any ephemeral purge. +// extractPurgedVolumes returns the set of (account, asset, color) volumes +// evicted from Pebble at commit by THIS log — the UNION of draining +// (PurgedVolumes) and pure ephemeral (EphemeralVolumes). The color dimension is +// carried so the key matches the (account, asset, color) tuple isExcluded looks +// up from each posting — dropping it would leave stale index rows for colored +// evictions and wrongly exclude uncolored postings sharing the (account, asset). +// Both categories share the same +// downstream treatment: their acct->tx mappings must be skipped because +// the volume entries no longer exist in the attribute store. +// +// Empty when the order that produced the log evicted nothing. func extractPurgedVolumes(ledgerLog ledgerLogWithPurgedVolumes) map[domain.AccountAssetKey]struct{} { - return domain.TouchedVolumeSet(ledgerLog.GetPurgedVolumes()) + purged := ledgerLog.GetPurgedVolumes() + ephemeral := ledgerLog.GetEphemeralVolumes() + + if len(purged) == 0 && len(ephemeral) == 0 { + return nil + } + + out := make(map[domain.AccountAssetKey]struct{}, len(purged)+len(ephemeral)) + for _, v := range purged { + out[domain.AccountAssetKey{Account: v.GetAccount(), Asset: v.GetAsset(), Color: v.GetColor()}] = struct{}{} + } + for _, v := range ephemeral { + out[domain.AccountAssetKey{Account: v.GetAccount(), Asset: v.GetAsset(), Color: v.GetColor()}] = struct{}{} + } + + return out } // ledgerLogWithPurgedVolumes narrows what we need from commonpb.LedgerLog so -// tests can pass either a real proto or a fake. +// tests can pass either a real proto or a fake. Covers the two on-log +// eviction lists (PurgedVolumes = draining, EphemeralVolumes = pure +// ephemeral). See LedgerLog proto docs for the disjoint-set invariant. type ledgerLogWithPurgedVolumes interface { GetPurgedVolumes() []*commonpb.TouchedVolume + GetEphemeralVolumes() []*commonpb.TouchedVolume } // excludedForLog returns the union of the transient (proposal-level) and diff --git a/internal/application/indexbuilder/protowire_postings.go b/internal/application/indexbuilder/protowire_postings.go index c02c919aa5..03b156c6b7 100644 --- a/internal/application/indexbuilder/protowire_postings.go +++ b/internal/application/indexbuilder/protowire_postings.go @@ -23,21 +23,24 @@ type rawPosting struct { // parsedLog holds the fields extracted by the protowire fast path. type parsedLog struct { - Sequence uint64 - Ledger string - TxID uint64 - Postings []rawPosting // reused across iterations via truncate-to-zero - LogType int32 // LedgerLogPayload oneof tag: 1=created, 2=reverted, 0=skip - PurgedVolumes []*commonpb.TouchedVolume // LedgerLog.purged_volumes (field 4), reused across iterations + Sequence uint64 + Ledger string + TxID uint64 + Postings []rawPosting // reused across iterations via truncate-to-zero + LogType int32 // LedgerLogPayload oneof tag: 1=created, 2=reverted, 0=skip + PurgedVolumes []*commonpb.TouchedVolume // LedgerLog.purged_volumes (field 4) — draining evictions, reused + EphemeralVolumes []*commonpb.TouchedVolume // LedgerLog.ephemeral_volumes (field 6) — pure ephemeral evictions, reused // DeletedLedger is the name carried by a DeleteLedger log (LogPayload // field 2); empty for every other log. It lets the backfill replay wipe // the deleted ledger's readstore rows, mirroring the live processLogs path. DeletedLedger string } -// GetPurgedVolumes satisfies ledgerLogWithPurgedVolumes so extractPurgedVolumes -// can consume the protowire fast path without going through commonpb. -func (p *parsedLog) GetPurgedVolumes() []*commonpb.TouchedVolume { return p.PurgedVolumes } +// GetPurgedVolumes / GetEphemeralVolumes satisfy ledgerLogWithPurgedVolumes +// so extractPurgedVolumes can consume the protowire fast path without going +// through commonpb. +func (p *parsedLog) GetPurgedVolumes() []*commonpb.TouchedVolume { return p.PurgedVolumes } +func (p *parsedLog) GetEphemeralVolumes() []*commonpb.TouchedVolume { return p.EphemeralVolumes } // parsePostingsFromLog extracts only the fields needed for posting indexation // from the raw bytes of a serialized Log message. It skips ~70% of the payload @@ -61,6 +64,7 @@ func parsePostingsFromLog(data []byte, out *parsedLog) error { out.Ledger = "" out.TxID = 0 out.PurgedVolumes = out.PurgedVolumes[:0] + out.EphemeralVolumes = out.EphemeralVolumes[:0] out.DeletedLedger = "" // --- Log level: extract sequence (field 1) and payload (field 2) --- @@ -210,6 +214,18 @@ func parsePostingsFromLog(data []byte, out *parsedLog) error { } out.PurgedVolumes = append(out.PurgedVolumes, vol) ledgerLogBytes = ledgerLogBytes[bn:] + case num == 6 && typ == protowire.BytesType: + b, bn := protowire.ConsumeBytes(ledgerLogBytes) + if bn < 0 { + return errors.New("protowire: invalid bytes for LedgerLog.ephemeral_volumes") + } + + vol, perr := parseTouchedVolume(b) + if perr != nil { + return fmt.Errorf("TouchedVolume: %w", perr) + } + out.EphemeralVolumes = append(out.EphemeralVolumes, vol) + ledgerLogBytes = ledgerLogBytes[bn:] default: n := protowire.ConsumeFieldValue(num, typ, ledgerLogBytes) if n < 0 { diff --git a/internal/application/usagebuilder/builder.go b/internal/application/usagebuilder/builder.go new file mode 100644 index 0000000000..5ded947908 --- /dev/null +++ b/internal/application/usagebuilder/builder.go @@ -0,0 +1,289 @@ +// Package usagebuilder tails the FSM audit chain and materialises the usage +// projections consumed by the housekeeping API: per-Numscript-template +// invocation counters (count + lastUsed) and per-ledger event counters +// (postings, reverts, numscript executions, references). +// +// The projection is not part of the FSM authoritative state — it lives in a +// dedicated secondary Pebble instance (usagestore) and is rebuildable from +// cursor=0 on demand. +// +// The subsystem reads from the audit chain (AuditEntry + AuditItem in +// ZoneCold) rather than the log stream because the audit item carries the +// raw serialized order — the only place where the Numscript reference +// survives past apply (the log's CreatedTransaction payload does not). +// For posting/revert counts, we fetch the specific log referenced by +// AuditItem.LogSequence — a single Get on the hot Pebble cache. +// +// Runs on every node; each replica maintains its own cursor (last consumed +// audit sequence). Eventually consistent with the FSM: reads may lag by up +// to one tick interval plus batch drain time. +package usagebuilder + +import ( + "context" + "fmt" + "sync/atomic" + "time" + + "go.opentelemetry.io/otel/metric" + + logging "github.com/formancehq/go-libs/v5/pkg/observe/log" + + "github.com/formancehq/ledger/v3/internal/pkg/signal" + "github.com/formancehq/ledger/v3/internal/pkg/tailworker" + "github.com/formancehq/ledger/v3/internal/query" + "github.com/formancehq/ledger/v3/internal/storage/dal" + "github.com/formancehq/ledger/v3/internal/storage/usagestore" +) + +// DefaultBatchSize is the default number of audit entries per Pebble batch commit. +const DefaultBatchSize = 200 + +// TickInterval is the steady-state polling interval. Same rationale as the +// audit indexer: the audit sequence advances on every proposal (including +// failures that emit no log), so a ticker is what guarantees pickup. +const TickInterval = 100 * time.Millisecond + +// catchUpBudget bounds how long a single processAuditEntries invocation +// holds a Pebble snapshot during boot-time catch-up. Between slices the +// snapshot is released so compactions can proceed on long-history stores. +const catchUpBudget = 5 * time.Second + +// Builder tails the FSM audit chain and populates the usagestore projections. +// Runs as a background goroutine on all nodes (not leader-only). Progress is +// stored in the usagestore itself under [0xFE][0x01]. +type Builder struct { + pebbleStore *dal.Store + usageStore *usagestore.Store + notifications *signal.Notifications + logger logging.Logger + meter metric.Meter + + batchSize int + + // lastProcessedAuditSeq mirrors usagestore.ReadProgress() and is + // updated on every successful commit — the atomic hint lets external + // readers (metrics, tests) avoid a Pebble Get. + lastProcessedAuditSeq atomic.Uint64 + // pebbleLastAuditSeq is the highest audit sequence in the main store, + // resampled on each tick for the lag gauge. + pebbleLastAuditSeq atomic.Uint64 + + tw *tailworker.TailWorker + reg metric.Registration +} + +// NewBuilder wires the usagebuilder subsystem. Notifications is injected via +// constructor rather than a setter to keep the fx graph explicit — see +// feedback_constructor_injection in the project memory. +func NewBuilder( + pebbleStore *dal.Store, + usageStore *usagestore.Store, + notifications *signal.Notifications, + logger logging.Logger, + meter metric.Meter, + batchSize int, +) *Builder { + if batchSize <= 0 { + batchSize = DefaultBatchSize + } + + return &Builder{ + pebbleStore: pebbleStore, + usageStore: usageStore, + notifications: notifications, + logger: logger.WithFields(map[string]any{"cmp": "usage-builder"}), + meter: meter, + batchSize: batchSize, + } +} + +// Start launches the background tail loop and registers OTEL gauges. +func (b *Builder) Start() { + if reg, err := tailworker.RegisterTailGauges( + b.meter, "usage.builder", "audit", &b.lastProcessedAuditSeq, &b.pebbleLastAuditSeq, + ); err == nil { + b.reg = reg + } + + // Wake on FSM commit signals when available. The guard is defensive: + // steady-state always wires notifications, but a nil value must not + // panic (e.g. a builder constructed in a test without a live FSM). + var wake <-chan struct{} + if b.notifications != nil { + wake = b.notifications.LogCommitted.C() + } + + b.tw = tailworker.New(tailworker.Config{ + Name: "usage-builder", + Logger: b.logger, + Ticker: TickInterval, + Wake: wake, + Boot: b.boot, + Tick: b.tick, + }) + b.tw.Start() +} + +// Stop halts the tail loop and unregisters metrics. +func (b *Builder) Stop() { + if b.tw != nil { + b.tw.Stop() + } + if b.reg != nil { + _ = b.reg.Unregister() + } +} + +// LastProcessedAuditSequence returns the last audit sequence consumed +// (atomic hint — same value as usagestore.ReadProgress but without a +// Pebble Get). Exposed for tests and health checks. +func (b *Builder) LastProcessedAuditSequence() uint64 { + return b.lastProcessedAuditSeq.Load() +} + +// PebbleLastAuditSequence returns the last known main-store audit sequence +// (atomic hint refreshed each tick). +func (b *Builder) PebbleLastAuditSequence() uint64 { + return b.pebbleLastAuditSeq.Load() +} + +// boot runs once before the tail loop: seed both atomics from the persisted +// state and drain the reachable backlog with a bigger batch size so the +// steady-state loop starts already caught up. A cursor-read error aborts the +// loop (returned to tailworker, which logs and stops); a catch-up error is +// logged and swallowed so steady-state indexing still starts. +func (b *Builder) boot(ctx context.Context) error { + cursor, err := b.usageStore.ReadProgress() + if err != nil { + return fmt.Errorf("reading usage progress: %w", err) + } + + b.lastProcessedAuditSeq.Store(cursor) + + pebbleLast, sampleErr := b.sampleAuditHead() + if sampleErr == nil { + b.pebbleLastAuditSeq.Store(pebbleLast) + + // Rollback detection before the catch-up: if the primary store was + // restored beneath the persisted cursor, drop the projection and rewind + // to 0 so the fold below replays into a clean store. + if cursor, err = b.resetIfRolledBack(cursor, pebbleLast); err != nil { + return err + } + } + + b.logger.WithFields(map[string]any{ + "cursor": cursor, + "pebbleLast": pebbleLast, + "gap": int64(pebbleLast) - int64(cursor), + }).Infof("Usage builder started") + + // Initial catch-up — time-bounded slices so the Pebble snapshot is + // released between passes. Larger batch size so bootstrap commits are + // coalesced. + prevCursor := cursor + savedBatchSize := b.batchSize + b.batchSize = max(b.batchSize, 2_000) + defer func() { b.batchSize = savedBatchSize }() + + for { + if err := ctx.Err(); err != nil { + return err + } + + before := cursor + deadline := time.Now().Add(catchUpBudget) + + cursor, err = b.processAuditEntries(ctx, cursor, deadline) + if err != nil { + b.logger.Errorf("initial catch-up: %v", err) + + break + } + + if cursor == before { + break + } + } + + if cursor > prevCursor { + b.logger.WithFields(map[string]any{ + "from": prevCursor, + "to": cursor, + "entries": cursor - prevCursor, + }).Infof("Initial catch-up complete") + } + + return nil +} + +// tick runs one steady-state iteration: refresh the audit-head gauge, detect a +// primary-store rollback, then drain any pending audit entries from the cursor +// forward. +// +// In steady state the persisted cursor sits at or behind the audit head: the +// chain is append-only and RestoreCheckpoint normally only advances a node that +// is behind (IsStoreUpToDate gates sync on LastAppliedIndex >= SnapshotIndex). +// But a restore that rolls the primary store back BENEATH the persisted cursor +// leaves the cursor ahead of the audit head; a forward-only fold would then +// no-op and leave the projection permanently over-counted — and, because the +// usagestore is a peer store outside checker scope (invariant #8), nothing would +// surface the drift. resetIfRolledBack wipes the projection + cursor and rewinds +// to 0 so this tick replays into a clean store (docs: usagebuilder.md rollback). +func (b *Builder) tick(ctx context.Context) error { + cursor := b.lastProcessedAuditSeq.Load() + + if last, err := b.sampleAuditHead(); err == nil { + b.pebbleLastAuditSeq.Store(last) + + if cursor, err = b.resetIfRolledBack(cursor, last); err != nil { + return err + } + } + + _, err := b.processAuditEntries(ctx, cursor, time.Time{}) + + return err +} + +// resetIfRolledBack detects a primary-store rollback beneath the usage cursor — +// the persisted cursor sitting AHEAD of the current audit head — and, when found, +// wipes every counter/template row + the progress cursor (usagestore.Reset) so +// the caller replays the projection from audit sequence 0. It returns the cursor +// to resume from: 0 after a reset, or the unchanged cursor otherwise. A reset +// also rewinds the lastProcessedAuditSeq atomic so external readers observe the +// rewind. This is the online reconvergence path the usagebuilder relies on in +// 3.0 (offline drop-and-rebuild is deferred to 3.1 — see usagebuilder.md). +func (b *Builder) resetIfRolledBack(cursor, auditHead uint64) (uint64, error) { + if cursor <= auditHead { + return cursor, nil + } + + b.logger.WithFields(map[string]any{ + "cursor": cursor, + "auditHead": auditHead, + }).Infof("usage cursor ahead of audit head — primary store rolled back; resetting usage projection and replaying from audit sequence 0") + + if err := b.usageStore.Reset(); err != nil { + return cursor, fmt.Errorf("resetting usage projection after rollback: %w", err) + } + + b.lastProcessedAuditSeq.Store(0) + + return 0, nil +} + +// sampleAuditHead opens a short-lived read handle to read the current audit +// head. The handle is closed immediately so RestoreCheckpoint's write lock +// is not blocked during idle ticks. +func (b *Builder) sampleAuditHead() (uint64, error) { + handle, err := b.pebbleStore.NewDirectReadHandle() + if err != nil { + return 0, err + } + + defer func() { _ = handle.Close() }() + + return query.ReadLastAuditSequence(handle) +} diff --git a/internal/application/usagebuilder/process_audit.go b/internal/application/usagebuilder/process_audit.go new file mode 100644 index 0000000000..694f65c02c --- /dev/null +++ b/internal/application/usagebuilder/process_audit.go @@ -0,0 +1,752 @@ +package usagebuilder + +import ( + "context" + "errors" + "fmt" + "io" + "time" + + "google.golang.org/protobuf/proto" + + "github.com/formancehq/ledger/v3/internal/proto/commonpb" + "github.com/formancehq/ledger/v3/internal/proto/raftcmdpb" + "github.com/formancehq/ledger/v3/internal/query" + "github.com/formancehq/ledger/v3/internal/storage/dal" + "github.com/formancehq/ledger/v3/internal/storage/usagestore" +) + +// templateKey identifies a per-ledger, per-template aggregation slot. +type templateKey struct { + ledger string + template string +} + +// templateDelta accumulates a per-batch increment for one template. +type templateDelta struct { + count uint64 + lastUsed *commonpb.Timestamp // most recent timestamp seen this batch +} + +// counterDelta is a signed delta for a per-ledger event counter. Deltas are +// almost always non-negative (event counters are monotonically increasing) but +// the volume counter can decrement (a draining eviction subtracts 1), so the +// underlying type is signed. Defined as a distinct type — not a type alias, +// which the repository conventions forbid — because the signed-delta semantics +// are load-bearing (see applyDelta's underflow clamp). +type counterDelta int64 + +// batchState holds the in-flight aggregation for one batch: per-ledger +// counter deltas, per-template usage deltas, and the set of ledger names +// dropped by DeleteLedgerOrder entries in this batch. Reset by newBatchState. +type batchState struct { + counters map[string]map[byte]counterDelta + templates map[templateKey]templateDelta + deletedLedgers map[string]struct{} +} + +func newBatchState() *batchState { + return &batchState{ + counters: make(map[string]map[byte]counterDelta), + templates: make(map[templateKey]templateDelta), + deletedLedgers: make(map[string]struct{}), + } +} + +// markLedgerDeleted flags a ledger as dropped by this batch and drops any +// in-batch counter / template deltas already accumulated for it (they are +// for the pre-delete incarnation and must not survive the DeleteLedger). +// +// commitBatch runs the DeleteRange cascade FIRST inside the Pebble batch, +// then stages the counter / template Puts on top — later batch ops shadow +// earlier ones at commit, so if the same audit batch contains a delete +// followed by a same-name recreate + writes, the post-recreate Puts survive +// while every pre-batch row for the old incarnation is wiped. Combined with +// the accumulator reset here, that yields the same net semantics as the +// FSM's own DeleteLedger cascade (which unconditionally purges the ledger's +// Pebble rows regardless of earlier orders in the same proposal). +func (s *batchState) markLedgerDeleted(ledger string) { + s.deletedLedgers[ledger] = struct{}{} + delete(s.counters, ledger) + + for k := range s.templates { + if k.ledger == ledger { + delete(s.templates, k) + } + } +} + +// addCounter accumulates a delta on the (ledger, counterID) slot. +func (s *batchState) addCounter(ledger string, counterID byte, delta counterDelta) { + inner, ok := s.counters[ledger] + if !ok { + inner = make(map[byte]counterDelta, 4) + s.counters[ledger] = inner + } + + inner[counterID] += delta +} + +// addTemplateUsage bumps the template usage aggregation. When multiple +// invocations of the same template land in one batch the max timestamp wins +// (matches the "lastUsed = most recent invocation" semantics). +func (s *batchState) addTemplateUsage(ledger, template string, ts *commonpb.Timestamp) { + k := templateKey{ledger: ledger, template: template} + cur := s.templates[k] + cur.count++ + + if ts != nil && (cur.lastUsed == nil || timestampGreater(ts, cur.lastUsed)) { + cur.lastUsed = ts + } + + s.templates[k] = cur +} + +// timestampGreater reports whether a > b in wall-clock ordering. Both +// operands are non-nil. commonpb.Timestamp encodes microseconds-since-epoch +// as a single uint64 field (data), so ordering is direct integer compare. +func timestampGreater(a, b *commonpb.Timestamp) bool { + return a.GetData() > b.GetData() +} + +// empty reports whether the batch has no writes queued. +func (s *batchState) empty() bool { + return len(s.counters) == 0 && len(s.templates) == 0 && len(s.deletedLedgers) == 0 +} + +// processAuditEntries iterates audit entries after cursor, dispatches each +// item, and commits per-ledger counter deltas + template usage updates +// atomically alongside the cursor advance. Returns the new cursor. +// +// When deadline is non-zero, processing stops once the deadline has passed +// so the caller (initial catch-up loop) can release the Pebble snapshot +// between iterations. +func (b *Builder) processAuditEntries(ctx context.Context, cursor uint64, deadline time.Time) (uint64, error) { + handle, err := b.pebbleStore.NewDirectReadHandle() + if err != nil { + return cursor, fmt.Errorf("creating read handle for audit processing: %w", err) + } + + defer func() { _ = handle.Close() }() + + // afterSequence is passed by pointer to opt into the ">= cursor+1" filter; + // nil would stream from the very first entry. + afterSeq := cursor + + entriesCursor, err := query.ReadAuditEntries(ctx, handle, &afterSeq) + if err != nil { + return cursor, fmt.Errorf("opening audit cursor: %w", err) + } + + defer func() { _ = entriesCursor.Close() }() + + startCursor := cursor + lastProgressLog := time.Now() + + for { + select { + case <-ctx.Done(): + return cursor, ctx.Err() + default: + } + + state := newBatchState() + + var ( + batchCount int + lastAuditSeq uint64 + eof bool + ) + + for batchCount < b.batchSize { + entry, err := entriesCursor.Next() + if err != nil { + if errors.Is(err, io.EOF) { + eof = true + + break + } + + return cursor, fmt.Errorf("reading audit entry: %w", err) + } + + lastAuditSeq = entry.GetSequence() + batchCount++ + + // Failed proposals: no state change, nothing to project. The + // hash chain still binds them (compareIdempotencyOutcomes) + // but the usagebuilder is only interested in state deltas. + if entry.GetSuccess() == nil { + continue + } + + // TransientVolumes live on the AppliedProposal projection (keyed by + // audit sequence — 1:1 with AuditEntry). Batch-scoped, not per-log: + // transientness depends on the WriteSet's final aggregate state, + // so it cannot be split per item. + proposal, err := query.ReadAppliedProposal(ctx, handle, entry.GetSequence()) + if err != nil { + return cursor, fmt.Errorf("reading applied proposal for seq %d: %w", entry.GetSequence(), err) + } + + if proposal != nil { + for ledger, tvList := range proposal.GetTransientVolumes() { + if n := len(tvList.GetVolumes()); n > 0 { + state.addCounter(ledger, usagestore.CounterTransientUsed, counterDelta(n)) + } + } + } + + items, err := query.ReadAuditItems(ctx, handle, entry.GetSequence()) + if err != nil { + return cursor, fmt.Errorf("reading audit items for seq %d: %w", entry.GetSequence(), err) + } + + // Fresh dedup sets per audit entry — the entry is the natural + // boundary at which a (ledger, account, asset) key can change + // persistence class at most once. See applyVolumeAnnotations. + entryState := newEntryVolumeState() + + for _, item := range items { + // LogSequence == 0 → idempotent replay or non-log-producing + // order (metadata schema changes, etc.). Skip: no work. + if item.GetLogSequence() == 0 { + continue + } + + order := &raftcmdpb.Order{} + if err := proto.Unmarshal(item.GetSerializedOrder(), order); err != nil { + return cursor, fmt.Errorf("unmarshaling audit item order (audit_seq=%d, idx=%d): %w", + entry.GetSequence(), item.GetOrderIndex(), err) + } + + if err := b.dispatchOrder(ctx, handle, order, item.GetLogSequence(), state, entryState); err != nil { + return cursor, err + } + } + } + + if batchCount == 0 { + break + } + + if err := b.commitBatch(state, lastAuditSeq); err != nil { + return cursor, err + } + + cursor = lastAuditSeq + b.lastProcessedAuditSeq.Store(cursor) + + // Periodic progress logging for long catch-up runs. + if now := time.Now(); now.Sub(lastProgressLog) >= 10*time.Second { + b.logger.WithFields(map[string]any{ + "cursor": cursor, + "from": startCursor, + "processed": cursor - startCursor, + }).Infof("processAuditEntries progress") + + lastProgressLog = now + } + + if eof { + break + } + + if !deadline.IsZero() && time.Now().After(deadline) { + break + } + } + + return cursor, nil +} + +// dispatchOrder inspects a raw Order and accumulates counter / template +// deltas into the batch state. Fetches the produced log when the resolved +// posting count is required (revert txs, script-backed create txs, mirror +// ingests). entry carries the per-audit-entry dedup scratchpad — see +// applyVolumeAnnotations. +func (b *Builder) dispatchOrder( + ctx context.Context, + handle dal.PebbleGetter, + order *raftcmdpb.Order, + logSeq uint64, + state *batchState, + entry *entryVolumeState, +) error { + scoped := order.GetLedgerScoped() + if scoped == nil { + // System-scoped orders (cluster config, chapter close, …) do not + // contribute to per-ledger usage counters. Skip. + return nil + } + + ledger := scoped.GetLedger() + if ledger == "" { + return nil + } + + // DeleteLedger orders MUST be projected — otherwise the usagestore + // keeps stale rows for the dropped ledger indefinitely. Same story as + // the readstore's DeleteLedgerIndexes. + if scoped.GetDeleteLedger() != nil { + state.markLedgerDeleted(ledger) + + return nil + } + + // Mirror ingests produce Created/Reverted transaction logs the same + // shape as the direct write path, so posting / revert / volume / + // ephemeral counters all apply. References ARE carried across the + // mirror wire (MirrorCreatedTransaction.reference) and counted the + // same as native creates. Numscript templates are not — v2 sources + // do not carry per-template invocation metadata, so we skip + // CounterNumscriptExecution and template usage for mirrored logs. + if mirror := scoped.GetMirrorIngest(); mirror != nil { + return b.dispatchMirrorIngest(ctx, handle, ledger, mirror.GetEntry(), logSeq, state, entry) + } + + apply := scoped.GetApply() + if apply == nil { + // CreateLedger / PromoteLedger — no state deltas that concern + // usage counters. + return nil + } + + switch data := apply.GetData().(type) { + case *raftcmdpb.LedgerApplyOrder_CreateTransaction: + return b.dispatchCreateTransaction(ctx, handle, ledger, data.CreateTransaction, logSeq, state, entry) + case *raftcmdpb.LedgerApplyOrder_RevertTransaction: + return b.dispatchRevertTransaction(ctx, handle, ledger, logSeq, state, entry) + } + + return nil +} + +// dispatchMirrorIngest projects a single MirrorLogEntry — the mirror worker +// replays these on the destination ledger, producing the same CreatedTx / +// RevertedTx logs the direct write path emits. We contribute the +// downstream-observable counters (postings, reverts, volumes, ephemeral) but +// skip client-driven metadata (reference / numscript) since it doesn't +// travel across the mirror wire. +func (b *Builder) dispatchMirrorIngest( + ctx context.Context, + handle dal.PebbleGetter, + ledger string, + mle *raftcmdpb.MirrorLogEntry, + logSeq uint64, + state *batchState, + entry *entryVolumeState, +) error { + if mle == nil { + return nil + } + + switch data := mle.GetData().(type) { + case *raftcmdpb.MirrorLogEntry_CreatedTransaction: + ann, err := b.readLog(ctx, handle, logSeq) + if err != nil { + return err + } + if ann.postings > 0 { + state.addCounter(ledger, usagestore.CounterPosting, counterDelta(ann.postings)) + } + if data.CreatedTransaction.GetReference() != "" { + state.addCounter(ledger, usagestore.CounterReference, 1) + } + applyVolumeAnnotations(ledger, ann, state, entry) + case *raftcmdpb.MirrorLogEntry_RevertedTransaction: + state.addCounter(ledger, usagestore.CounterRevert, 1) + ann, err := b.readLog(ctx, handle, logSeq) + if err != nil { + return err + } + if ann.postings > 0 { + state.addCounter(ledger, usagestore.CounterPosting, counterDelta(ann.postings)) + } + applyVolumeAnnotations(ledger, ann, state, entry) + } + + return nil +} + +// entryVolumeState is the per-audit-entry deduplication scratchpad. Each set +// records the (account, asset, color) tuples already applied to their +// respective counter for the current audit entry. VolumeCount, CounterEphemeralEvicted +// and CounterTransientUsed are per-batch cardinality deltas: a tuple that +// appears in multiple orders of the same batch (e.g. a shared "bank:main" +// account touched by three transactions) must contribute at most once to +// each counter. Postings / references / reverts / numscript executions are +// per-event and don't need this dedup. +type entryVolumeState struct { + seenNewKept map[volumeSetKey]struct{} + seenPurged map[volumeSetKey]struct{} + seenEphemeral map[volumeSetKey]struct{} +} + +// volumeSetKey mirrors state.volumeSetKey — kept local to avoid crossing +// package boundaries just for a tuple of strings. Color is part of the volume +// identity (volumes are keyed by (account, asset, color) in both the FSM and the +// proto model), so it MUST be in the dedup key: two color buckets of the same +// (account, asset) within one audit entry are distinct volumes and each must +// count once, else VolumeCount / EphemeralEvictedCount undercount colored rows. +type volumeSetKey struct { + ledger string + account string + asset string + color string +} + +func newEntryVolumeState() *entryVolumeState { + return &entryVolumeState{ + seenNewKept: make(map[volumeSetKey]struct{}), + seenPurged: make(map[volumeSetKey]struct{}), + seenEphemeral: make(map[volumeSetKey]struct{}), + } +} + +// applyVolumeAnnotations folds the three disjoint per-log volume lists into +// the batch counter state, deduplicating each tuple within the current audit +// entry. The audit entry maps 1:1 to an FSM apply batch, so a tuple can only +// change persistence class (new → kept, draining → evicted, ephemeral in-out) +// at most once inside it. Without this dedup, an account touched by N orders +// of the same batch would be counted N times. +func applyVolumeAnnotations(ledger string, ann logVolumeAnnotations, state *batchState, entry *entryVolumeState) { + for _, v := range ann.newKept { + k := volumeSetKey{ledger: ledger, account: v.GetAccount(), asset: v.GetAsset(), color: v.GetColor()} + if _, ok := entry.seenNewKept[k]; ok { + continue + } + entry.seenNewKept[k] = struct{}{} + state.addCounter(ledger, usagestore.CounterVolume, 1) + } + + // Draining evictions: a volume that persisted with a non-zero balance + // and now goes back to zero. Both the volume counter (–1, it was + // counted before) and the eviction counter (+1, this is an eviction + // event) contribute. The pre-EN-1420 EphemeralEvictedCount tallied + // every log-level eviction, not just pure ephemeral tuples. + for _, v := range ann.purged { + k := volumeSetKey{ledger: ledger, account: v.GetAccount(), asset: v.GetAsset(), color: v.GetColor()} + if _, ok := entry.seenPurged[k]; ok { + continue + } + entry.seenPurged[k] = struct{}{} + state.addCounter(ledger, usagestore.CounterVolume, -1) + state.addCounter(ledger, usagestore.CounterEphemeralEvicted, 1) + } + + for _, v := range ann.ephemeral { + k := volumeSetKey{ledger: ledger, account: v.GetAccount(), asset: v.GetAsset(), color: v.GetColor()} + if _, ok := entry.seenEphemeral[k]; ok { + continue + } + entry.seenEphemeral[k] = struct{}{} + state.addCounter(ledger, usagestore.CounterEphemeralEvicted, 1) + } +} + +// dispatchCreateTransaction increments posting, reference, numscript-exec, +// ephemeral-evicted, volume and template usage counters for a create-tx +// order. +func (b *Builder) dispatchCreateTransaction( + ctx context.Context, + handle dal.PebbleGetter, + ledger string, + order *raftcmdpb.CreateTransactionOrder, + logSeq uint64, + state *batchState, + entry *entryVolumeState, +) error { + // Resolved posting count and volume annotations live on the log — the + // order carries raw postings only for the non-scripted path, and never + // carries purge info. + ann, err := b.readLog(ctx, handle, logSeq) + if err != nil { + return err + } + + if ann.postings > 0 { + state.addCounter(ledger, usagestore.CounterPosting, counterDelta(ann.postings)) + } + + applyVolumeAnnotations(ledger, ann, state, entry) + + // A skipped CreateTransaction produces an OrderSkipped log, not a + // CreatedTransaction, so readLog reports no real transaction. Such an order + // committed nothing: it must contribute no reference / numscript-execution / + // template-usage counters (all derived from the raw order below). Posting and + // volume counters above come from the produced log and are already naturally + // zero for a skip. + if !ann.isCreatedTx { + return nil + } + + if order.GetReference() != "" { + state.addCounter(ledger, usagestore.CounterReference, 1) + } + + isScripted := order.GetNumscriptReference() != nil || + (order.GetScript() != nil && order.GetScript().GetPlain() != "") + + if isScripted { + state.addCounter(ledger, usagestore.CounterNumscriptExecution, 1) + } + + if ref := order.GetNumscriptReference(); ref != nil { + // Prefer the order's client-supplied timestamp so template usage + // tracks the wall clock the client cares about; when omitted, fall + // back to the effective timestamp the FSM stamped on the produced + // log (either the client value or the proposal date resolved by + // processor_transaction.go). Either way we end up with a + // deterministic non-nil timestamp on every replay. + ts := order.GetTimestamp() + if ts == nil { + ts = ann.txTimestamp + } + state.addTemplateUsage(ledger, ref.GetName(), ts) + } + + return nil +} + +// dispatchRevertTransaction increments revert, posting, ephemeral-evicted +// and volume counters for a revert-tx order. The resolved reverse-postings, +// purged volumes and newly-created volumes live on the produced log. +func (b *Builder) dispatchRevertTransaction( + ctx context.Context, + handle dal.PebbleGetter, + ledger string, + logSeq uint64, + state *batchState, + entry *entryVolumeState, +) error { + ann, err := b.readLog(ctx, handle, logSeq) + if err != nil { + return err + } + + // A skipped RevertTransaction produces an OrderSkipped log; only a produced + // RevertedTransaction is a successful revert. Gate the revert counter on it so + // a skipped revert does not inflate the count. (Posting/volume counters below + // come from the produced log and are already zero for a skip.) + if ann.isRevertedTx { + state.addCounter(ledger, usagestore.CounterRevert, 1) + } + + if ann.postings > 0 { + state.addCounter(ledger, usagestore.CounterPosting, counterDelta(ann.postings)) + } + + applyVolumeAnnotations(ledger, ann, state, entry) + + return nil +} + +// logVolumeAnnotations bundles the three disjoint TouchedVolume lists that +// LedgerLog carries plus the resolved posting count and the transaction +// timestamp. The lists are kept as slices (not lengths) because the counter +// dispatch needs per-tuple identity for batch-scoped deduplication — see +// applyVolumeAnnotations. txTimestamp is the effective timestamp the FSM +// stamped on the transaction (client-provided or falling back to the +// proposal date). Nil for non-transaction logs. +type logVolumeAnnotations struct { + postings int + purged []*commonpb.TouchedVolume // len — draining only + newKept []*commonpb.TouchedVolume // new + kept + ephemeral []*commonpb.TouchedVolume // new + purged (pure ephemeral) + txTimestamp *commonpb.Timestamp // Transaction.Timestamp on Created/Reverted logs + + // Kind of the produced log. Both false when the order was skipped + // (OrderSkipped) or produced no transaction — the order committed nothing, + // so it must not contribute success-scoped usage counters. + isCreatedTx bool + isRevertedTx bool +} + +// readLog fetches the log at logSeq and returns its posting count plus the +// three disjoint volume-annotation lists. Empty when the log does not exist +// or carries no transaction / annotation. +func (b *Builder) readLog(ctx context.Context, handle dal.PebbleGetter, logSeq uint64) (logVolumeAnnotations, error) { + log, err := query.ReadLogBySequence(ctx, handle, logSeq) + if err != nil { + return logVolumeAnnotations{}, fmt.Errorf("reading log at seq %d: %w", logSeq, err) + } + + if log == nil { + return logVolumeAnnotations{}, nil + } + + apply, ok := log.GetPayload().GetType().(*commonpb.LogPayload_Apply) + if !ok || apply.Apply == nil { + return logVolumeAnnotations{}, nil + } + + ledgerLog := apply.Apply.GetLog() + if ledgerLog == nil { + return logVolumeAnnotations{}, nil + } + + // PurgedVolumes / NewKeptVolumes / EphemeralVolumes live on LedgerLog + // directly (not on the payload variant). The three lists are DISJOINT + // at the FSM emission site, but a single (account, asset) key can + // still appear in multiple orders' lists within the SAME batch because + // each order tracks the volumes IT touched. The counter side of the + // pipeline deduplicates per audit entry — see applyVolumeDelta. + result := logVolumeAnnotations{ + purged: ledgerLog.GetPurgedVolumes(), + newKept: ledgerLog.GetNewKeptVolumes(), + ephemeral: ledgerLog.GetEphemeralVolumes(), + } + + if ledgerLog.GetData() == nil { + return result, nil + } + + switch p := ledgerLog.GetData().GetPayload().(type) { + case *commonpb.LedgerLogPayload_CreatedTransaction: + tx := p.CreatedTransaction.GetTransaction() + result.postings = len(tx.GetPostings()) + result.txTimestamp = tx.GetTimestamp() + result.isCreatedTx = true + case *commonpb.LedgerLogPayload_RevertedTransaction: + tx := p.RevertedTransaction.GetRevertTransaction() + result.postings = len(tx.GetPostings()) + result.txTimestamp = tx.GetTimestamp() + result.isRevertedTx = true + } + + return result, nil +} + +// commitBatch applies the accumulated counter / template deltas to the +// usagestore and advances the cursor — all in a single Pebble batch commit. +// +// Ordering inside the batch: DeleteRange cascade FIRST, then counter / +// template Puts. Pebble batches apply operations in enqueue order at commit, +// so any Put on a key inside a DeleteRange range enqueued earlier still lands +// (later ops shadow earlier ones). Combined with markLedgerDeleted clearing +// in-batch counters for the deleted ledger, this yields the correct semantic +// for a delete+recreate sequence within the same audit batch: every +// pre-batch row for the old incarnation is wiped, while any post-recreate +// Puts on the recycled name survive. +func (b *Builder) commitBatch(state *batchState, cursor uint64) error { + batch := b.usageStore.NewBatch() + + // Ledger deletions first — see the function comment. + for ledger := range state.deletedLedgers { + if err := usagestore.DeleteLedger(batch, ledger); err != nil { + _ = batch.Cancel() + + return fmt.Errorf("dropping usage rows for deleted ledger %q: %w", ledger, err) + } + } + + // Counter deltas: read-modify-write against the usagestore. Not the + // FSM's Pebble — invariant #3 does not apply here. + for ledger, counters := range state.counters { + // If this batch also deleted the ledger, the DeleteRange enqueued + // above logically zeroes every counter for the recycled name. But + // GetCounter reads the committed DB, not the pending batch, so it + // would return the OLD incarnation's value and we'd write + // old+delta on top of the DeleteRange — resurrecting stale counts + // for a same-batch delete+recreate. Treat the baseline as 0 for a + // deleted ledger so only the post-recreate deltas survive. + _, deleted := state.deletedLedgers[ledger] + + for counterID, delta := range counters { + var current uint64 + if !deleted { + var err error + current, err = b.usageStore.GetCounter(ledger, counterID) + if err != nil { + _ = batch.Cancel() + + return fmt.Errorf("reading counter %#x for ledger %q: %w", counterID, ledger, err) + } + } + + next := applyDelta(current, delta) + + if err := b.usageStore.PutCounter(batch, ledger, counterID, next); err != nil { + _ = batch.Cancel() + + return fmt.Errorf("writing counter %#x for ledger %q: %w", counterID, ledger, err) + } + } + } + + // Template deltas: same read-modify-write pattern on the TemplateUsage + // proto. count is additive; last_used is max(previous, batch max). + for k, delta := range state.templates { + // Same same-batch delete+recreate hazard as counters above: for a + // ledger this batch deleted, the DeleteRange zeroes the recycled + // name, so ignore the persisted (old incarnation) value and start + // from a nil baseline. + var current *commonpb.TemplateUsage + if _, deleted := state.deletedLedgers[k.ledger]; !deleted { + var err error + current, err = b.usageStore.GetTemplateUsage(k.ledger, k.template) + if err != nil { + _ = batch.Cancel() + + return fmt.Errorf("reading template usage %q/%q: %w", k.ledger, k.template, err) + } + } + + next := mergeTemplateUsage(current, delta) + + if err := b.usageStore.PutTemplateUsage(batch, k.ledger, k.template, next); err != nil { + _ = batch.Cancel() + + return fmt.Errorf("writing template usage %q/%q: %w", k.ledger, k.template, err) + } + } + + if err := b.usageStore.WriteProgress(batch, cursor); err != nil { + _ = batch.Cancel() + + return fmt.Errorf("writing usage progress: %w", err) + } + + if err := batch.Commit(); err != nil { + _ = batch.Cancel() + + return fmt.Errorf("committing usage batch: %w", err) + } + + return nil +} + +// applyDelta safely adds a signed delta to a uint64 counter, clamping at +// zero on underflow. Same helper as write_set_counters.applyDelta but kept +// local so the usagebuilder doesn't pull in state. +func applyDelta(current uint64, delta counterDelta) uint64 { + if delta >= 0 { + return current + uint64(delta) + } + + sub := uint64(-delta) + if sub > current { + return 0 + } + + return current - sub +} + +// mergeTemplateUsage folds a per-batch delta into the persisted TemplateUsage. +// A nil `current` (no persisted entry yet) is treated as {count: 0, lastUsed: nil}. +func mergeTemplateUsage(current *commonpb.TemplateUsage, delta templateDelta) *commonpb.TemplateUsage { + next := &commonpb.TemplateUsage{} + if current != nil { + next.Count = current.GetCount() + delta.count + next.LastUsed = current.GetLastUsed() + } else { + next.Count = delta.count + } + + if delta.lastUsed != nil && (next.GetLastUsed() == nil || timestampGreater(delta.lastUsed, next.GetLastUsed())) { + next.LastUsed = delta.lastUsed + } + + return next +} diff --git a/internal/application/usagebuilder/process_audit_integration_test.go b/internal/application/usagebuilder/process_audit_integration_test.go new file mode 100644 index 0000000000..ffe5ba0fc5 --- /dev/null +++ b/internal/application/usagebuilder/process_audit_integration_test.go @@ -0,0 +1,860 @@ +package usagebuilder + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/metric/noop" + + logging "github.com/formancehq/go-libs/v5/pkg/observe/log" + + "github.com/formancehq/ledger/v3/internal/proto/auditpb" + "github.com/formancehq/ledger/v3/internal/proto/commonpb" + "github.com/formancehq/ledger/v3/internal/proto/proposalpb" + "github.com/formancehq/ledger/v3/internal/proto/raftcmdpb" + "github.com/formancehq/ledger/v3/internal/storage/dal" + "github.com/formancehq/ledger/v3/internal/storage/usagestore" +) + +// --------------------------------------------------------------------------- +// Fixture-seeding harness +// +// processAuditEntries reads, per audit sequence, from the PRIMARY pebble store: +// - the auditpb.AuditEntry ([ZoneCold][SubColdAudit][seq BE8]) +// - its auditpb.AuditItem(s) ([ZoneCold][SubColdAuditItem][seq BE8][idx BE4]) +// - the proposalpb.AppliedProposal ([ZoneCold][SubColdAppliedProposal][seq BE8]) +// - the commonpb.LedgerLog per item ([ZoneCold][SubColdLog][logSeq BE8]) via readLog +// +// The FSM write helpers that produce these rows (state.batch.go) are +// unexported, so we mirror their key layouts here with the DAL key builder — +// the same layouts query/audit.go, query/applied_proposal.go and query/log.go +// read back. Only structurally-sufficient fields are set: processAuditEntries +// does not verify the hash chain (only the checker does), so a minimal but +// valid (Sequence / Success / items referencing valid log sequences) fixture +// drives every path. +// +// NOTE: query.ReadAppliedProposal returns domain.ErrNotFound when the row is +// absent, which processAuditEntries treats as fatal — so every SUCCESS audit +// entry must have a matching AppliedProposal row (possibly empty). +// --------------------------------------------------------------------------- + +func newUsageTestStores(t *testing.T) (*dal.Store, *usagestore.Store) { + t.Helper() + + ctx := logging.TestingContext() + logger := logging.FromContext(ctx) + meter := noop.NewMeterProvider().Meter("test") + + primary, err := dal.NewStore(t.TempDir(), logger, meter, dal.DefaultConfig()) + require.NoError(t, err) + t.Cleanup(func() { _ = primary.Close() }) + + usage, err := usagestore.New(t.TempDir(), logging.NopZap(), usagestore.DefaultConfig()) + require.NoError(t, err) + t.Cleanup(func() { _ = usage.Close() }) + + return primary, usage +} + +func usageColdAuditKey(seq uint64) []byte { + return dal.NewKeyBuilder(). + PutZonePrefix(dal.ZoneCold, dal.SubColdAudit). + PutUint64(seq). + Build() +} + +func usageColdAuditItemKey(seq uint64, idx uint32) []byte { + return dal.NewKeyBuilder(). + PutZonePrefix(dal.ZoneCold, dal.SubColdAuditItem). + PutUint64(seq). + PutUint32(idx). + Build() +} + +func usageColdAppliedProposalKey(seq uint64) []byte { + return dal.NewKeyBuilder(). + PutZonePrefix(dal.ZoneCold, dal.SubColdAppliedProposal). + PutUint64(seq). + Build() +} + +func usageColdLogKey(seq uint64) []byte { + return dal.NewKeyBuilder(). + PutZonePrefix(dal.ZoneCold, dal.SubColdLog). + PutUint64(seq). + Build() +} + +// touchedVolume builds a (account, asset, color) volume identity tuple. +func touchedVolume(account, asset, color string) *commonpb.TouchedVolume { + return &commonpb.TouchedVolume{Account: account, Asset: asset, Color: color} +} + +// usagePosting builds a posting for the transaction payload — the posting +// count is derived from len(Transaction.Postings) on the produced log. +func usagePosting(source, destination, asset string, amount uint64) *commonpb.Posting { + return &commonpb.Posting{ + Source: source, + Destination: destination, + Asset: asset, + Amount: commonpb.NewUint256FromUint64(amount), + } +} + +// createdTxLog builds an Apply log carrying a CreatedTransaction plus the three +// disjoint volume-annotation lists that live on LedgerLog directly (what +// readLog / applyVolumeAnnotations consume). +func createdTxLog( + seq uint64, + ledger string, + ts *commonpb.Timestamp, + postings []*commonpb.Posting, + newKept, purged, ephemeral []*commonpb.TouchedVolume, +) *commonpb.Log { + return &commonpb.Log{ + Sequence: seq, + Payload: &commonpb.LogPayload{ + Type: &commonpb.LogPayload_Apply{ + Apply: &commonpb.ApplyLedgerLog{ + LedgerName: ledger, + Log: &commonpb.LedgerLog{ + Id: seq, + NewKeptVolumes: newKept, + PurgedVolumes: purged, + EphemeralVolumes: ephemeral, + Data: &commonpb.LedgerLogPayload{ + Payload: &commonpb.LedgerLogPayload_CreatedTransaction{ + CreatedTransaction: &commonpb.CreatedTransaction{ + Transaction: &commonpb.Transaction{ + Id: seq, + Postings: postings, + Timestamp: ts, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +// revertedTxLog builds an Apply log carrying a RevertedTransaction plus the +// volume-annotation lists. +func revertedTxLog( + seq uint64, + ledger string, + ts *commonpb.Timestamp, + postings []*commonpb.Posting, + newKept, purged, ephemeral []*commonpb.TouchedVolume, +) *commonpb.Log { + return &commonpb.Log{ + Sequence: seq, + Payload: &commonpb.LogPayload{ + Type: &commonpb.LogPayload_Apply{ + Apply: &commonpb.ApplyLedgerLog{ + LedgerName: ledger, + Log: &commonpb.LedgerLog{ + Id: seq, + NewKeptVolumes: newKept, + PurgedVolumes: purged, + EphemeralVolumes: ephemeral, + Data: &commonpb.LedgerLogPayload{ + Payload: &commonpb.LedgerLogPayload_RevertedTransaction{ + RevertedTransaction: &commonpb.RevertedTransaction{ + RevertTransaction: &commonpb.Transaction{ + Id: seq, + Postings: postings, + Timestamp: ts, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +// createTxOrder wraps a CreateTransactionOrder in an Order the way the FSM +// serializes it into an AuditItem (raftcmdpb.Order → SerializedOrder). +func createTxOrder(ledger string, order *raftcmdpb.CreateTransactionOrder) *raftcmdpb.Order { + return &raftcmdpb.Order{ + Type: &raftcmdpb.Order_LedgerScoped{ + LedgerScoped: &raftcmdpb.LedgerScopedOrder{ + Ledger: ledger, + Payload: &raftcmdpb.LedgerScopedOrder_Apply{ + Apply: &raftcmdpb.LedgerApplyOrder{ + Data: &raftcmdpb.LedgerApplyOrder_CreateTransaction{CreateTransaction: order}, + }, + }, + }, + }, + } +} + +// revertTxOrder wraps a RevertTransactionOrder in an Order. +func revertTxOrder(ledger string, order *raftcmdpb.RevertTransactionOrder) *raftcmdpb.Order { + return &raftcmdpb.Order{ + Type: &raftcmdpb.Order_LedgerScoped{ + LedgerScoped: &raftcmdpb.LedgerScopedOrder{ + Ledger: ledger, + Payload: &raftcmdpb.LedgerScopedOrder_Apply{ + Apply: &raftcmdpb.LedgerApplyOrder{ + Data: &raftcmdpb.LedgerApplyOrder_RevertTransaction{RevertTransaction: order}, + }, + }, + }, + }, + } +} + +// mirrorCreatedOrder wraps a MirrorIngest carrying a created-transaction entry. +func mirrorCreatedOrder(ledger, reference string) *raftcmdpb.Order { + return &raftcmdpb.Order{ + Type: &raftcmdpb.Order_LedgerScoped{ + LedgerScoped: &raftcmdpb.LedgerScopedOrder{ + Ledger: ledger, + Payload: &raftcmdpb.LedgerScopedOrder_MirrorIngest{ + MirrorIngest: &raftcmdpb.MirrorIngestOrder{ + Entry: &raftcmdpb.MirrorLogEntry{ + Data: &raftcmdpb.MirrorLogEntry_CreatedTransaction{ + CreatedTransaction: &raftcmdpb.MirrorCreatedTransaction{Reference: reference}, + }, + }, + }, + }, + }, + }, + } +} + +// seedAuditItem is a single order in a synthetic audit entry: the order to +// serialize, the log sequence it produced (0 → skipped/non-log-producing), and +// the log to persist at that sequence (nil → no log row). +type seedAuditItem struct { + order *raftcmdpb.Order + logSeq uint64 + log *commonpb.Log +} + +// seedAuditEntry describes one synthetic audit entry to write into the primary +// store. success=false stages a failed proposal (GetSuccess() == nil, no +// AppliedProposal). transientVolumes stages an AppliedProposal.TransientVolumes +// map keyed by ledger. +type seedAuditEntry struct { + seq uint64 + success bool + items []seedAuditItem + transientVolumes map[string][]*commonpb.TouchedVolume +} + +// seedAuditData writes the full fixture (audit entries, items, applied +// proposals and logs) into the primary store in a single committed batch. +func seedAuditData(t *testing.T, store *dal.Store, entries []seedAuditEntry) { + t.Helper() + + batch := store.OpenWriteSession() + + for _, e := range entries { + auditEntry := &auditpb.AuditEntry{Sequence: e.seq} + if e.success { + auditEntry.Outcome = &auditpb.AuditEntry_Success{Success: &auditpb.AuditSuccess{}} + } else { + auditEntry.Outcome = &auditpb.AuditEntry_Failure{Failure: &auditpb.AuditFailure{}} + } + + require.NoError(t, batch.SetProto(usageColdAuditKey(e.seq), auditEntry)) + + // Only success entries carry an AppliedProposal — a failed proposal + // leaves a gap (ReadAppliedProposal → ErrNotFound), which is exactly + // the branch processAuditEntries skips via GetSuccess() == nil. + if e.success { + proposal := &proposalpb.AppliedProposal{Sequence: e.seq} + if len(e.transientVolumes) > 0 { + proposal.TransientVolumes = make(map[string]*proposalpb.TouchedVolumeList, len(e.transientVolumes)) + for ledger, vols := range e.transientVolumes { + proposal.TransientVolumes[ledger] = &proposalpb.TouchedVolumeList{Volumes: vols} + } + } + + require.NoError(t, batch.SetProto(usageColdAppliedProposalKey(e.seq), proposal)) + } + + for idx, item := range e.items { + raw, err := item.order.MarshalVT() + require.NoError(t, err) + + auditItem := &auditpb.AuditItem{ + OrderIndex: uint32(idx), + SerializedOrder: raw, + LogSequence: item.logSeq, + } + require.NoError(t, batch.SetProto(usageColdAuditItemKey(e.seq, uint32(idx)), auditItem)) + + if item.log != nil { + require.NoError(t, batch.SetProto(usageColdLogKey(item.logSeq), item.log)) + } + } + } + + require.NoError(t, batch.Commit()) +} + +// newTestBuilder constructs a Builder wired to the two stores with the given +// batch size (uses a no-op logger). +func newTestBuilder(primary *dal.Store, usage *usagestore.Store, batchSize int) *Builder { + return &Builder{ + pebbleStore: primary, + usageStore: usage, + logger: logging.NopZap(), + batchSize: batchSize, + } +} + +// TestResetIfRolledBack covers the rollback self-heal wired into boot()/tick(): +// when the persisted usage cursor sits ahead of the audit head (the primary +// store was restored beneath it), the projection + cursor are wiped so the fold +// replays from 0. There is no checker backstop for the usagestore, so this is +// the only reconvergence path — worth pinning. +func TestResetIfRolledBack(t *testing.T) { + t.Parallel() + + t.Run("cursor ahead of audit head wipes the projection and rewinds to 0", func(t *testing.T) { + t.Parallel() + + _, usage := newUsageTestStores(t) + b := &Builder{usageStore: usage, logger: logging.NopZap()} + + // Seed a projection + a non-zero progress cursor (commitBatch writes both). + seed := newBatchState() + seed.addCounter("l1", usagestore.CounterPosting, 42) + require.NoError(t, b.commitBatch(seed, 7)) + b.lastProcessedAuditSeq.Store(7) + + got, err := usage.GetCounter("l1", usagestore.CounterPosting) + require.NoError(t, err) + require.Equal(t, uint64(42), got) + + // Audit head (3) sits BELOW the persisted cursor (7) — rollback. + cursor, err := b.resetIfRolledBack(7, 3) + require.NoError(t, err) + assert.Equal(t, uint64(0), cursor, "must rewind to replay from 0") + + got, err = usage.GetCounter("l1", usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(0), got, "projection must be wiped") + + progress, err := usage.ReadProgress() + require.NoError(t, err) + assert.Equal(t, uint64(0), progress, "cursor must be cleared") + + assert.Equal(t, uint64(0), b.lastProcessedAuditSeq.Load(), "atomic hint must be rewound") + }) + + t.Run("cursor at or behind audit head is a no-op", func(t *testing.T) { + t.Parallel() + + _, usage := newUsageTestStores(t) + b := &Builder{usageStore: usage, logger: logging.NopZap()} + + seed := newBatchState() + seed.addCounter("l1", usagestore.CounterPosting, 5) + require.NoError(t, b.commitBatch(seed, 2)) + + cursor, err := b.resetIfRolledBack(2, 9) + require.NoError(t, err) + assert.Equal(t, uint64(2), cursor, "cursor unchanged when at/behind the head") + + got, err := usage.GetCounter("l1", usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(5), got, "projection must be intact") + }) +} + +// --------------------------------------------------------------------------- +// Table-driven end-to-end tests for the ingestion pipeline. +// --------------------------------------------------------------------------- + +func TestProcessAuditEntries_Dispatch(t *testing.T) { + t.Parallel() + + const ledger = "l1" + + ts := &commonpb.Timestamp{Data: 1234} + + type wantCounter struct { + id byte + value uint64 + } + + type wantTemplate struct { + name string + count uint64 + lastUsed uint64 + } + + tests := []struct { + name string + entries []seedAuditEntry + wantCursor uint64 + wantCounters []wantCounter + zeroCounters []byte // counters expected to be absent/zero + wantTemplates []wantTemplate + }{ + { + // Case 1: single scripted CreateTransaction with a reference and one + // new-kept volume — posting/reference/numscript/volume/template all fire. + name: "single_create_transaction_scripted_with_reference", + entries: []seedAuditEntry{{ + seq: 1, + success: true, + items: []seedAuditItem{{ + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Reference: "ref-1", + Timestamp: ts, + NumscriptReference: &raftcmdpb.NumscriptReference{Name: "payout"}, + }), + logSeq: 10, + log: createdTxLog(10, ledger, ts, + []*commonpb.Posting{usagePosting("world", "alice", "USD", 100)}, + []*commonpb.TouchedVolume{touchedVolume("alice", "USD", "")}, + nil, nil), + }}, + }}, + wantCursor: 1, + wantCounters: []wantCounter{ + {usagestore.CounterPosting, 1}, + {usagestore.CounterReference, 1}, + {usagestore.CounterNumscriptExecution, 1}, + {usagestore.CounterVolume, 1}, + }, + zeroCounters: []byte{usagestore.CounterRevert, usagestore.CounterEphemeralEvicted}, + wantTemplates: []wantTemplate{{"payout", 1, 1234}}, + }, + { + // Case 1b: a non-scripted create with no reference contributes only + // posting + volume; no reference / numscript / template. + name: "single_create_transaction_plain_no_reference", + entries: []seedAuditEntry{{ + seq: 1, + success: true, + items: []seedAuditItem{{ + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "bob", "USD", 5)}, + }), + logSeq: 10, + log: createdTxLog(10, ledger, nil, + []*commonpb.Posting{usagePosting("world", "bob", "USD", 5)}, + []*commonpb.TouchedVolume{touchedVolume("bob", "USD", "")}, + nil, nil), + }}, + }}, + wantCursor: 1, + wantCounters: []wantCounter{ + {usagestore.CounterPosting, 1}, + {usagestore.CounterVolume, 1}, + }, + zeroCounters: []byte{usagestore.CounterReference, usagestore.CounterNumscriptExecution, usagestore.CounterRevert}, + }, + { + // Case 2: RevertTransaction — revert counter + posting + the + // reversal's purged volume (volume -1, ephemeral-evicted +1). + name: "revert_transaction", + entries: []seedAuditEntry{{ + seq: 1, + success: true, + items: []seedAuditItem{{ + order: revertTxOrder(ledger, &raftcmdpb.RevertTransactionOrder{TransactionId: 7}), + logSeq: 10, + log: revertedTxLog(10, ledger, ts, + []*commonpb.Posting{usagePosting("alice", "world", "USD", 100)}, + nil, + []*commonpb.TouchedVolume{touchedVolume("alice", "USD", "")}, + nil), + }}, + }}, + wantCursor: 1, + wantCounters: []wantCounter{ + {usagestore.CounterRevert, 1}, + {usagestore.CounterPosting, 1}, + {usagestore.CounterEphemeralEvicted, 1}, + }, + // One purged volume: CounterVolume was decremented from 0 → clamped to 0. + zeroCounters: []byte{usagestore.CounterVolume, usagestore.CounterReference}, + }, + { + // Case 3: MirrorIngest created-transaction — posting + reference + + // volume, but NO numscript/template (client metadata doesn't cross + // the mirror wire). + name: "mirror_ingest_created_transaction", + entries: []seedAuditEntry{{ + seq: 1, + success: true, + items: []seedAuditItem{{ + order: mirrorCreatedOrder(ledger, "mirror-ref"), + logSeq: 10, + log: createdTxLog(10, ledger, ts, + []*commonpb.Posting{usagePosting("world", "carol", "USD", 3)}, + []*commonpb.TouchedVolume{touchedVolume("carol", "USD", "")}, + nil, nil), + }}, + }}, + wantCursor: 1, + wantCounters: []wantCounter{ + {usagestore.CounterPosting, 1}, + {usagestore.CounterReference, 1}, + {usagestore.CounterVolume, 1}, + }, + zeroCounters: []byte{usagestore.CounterNumscriptExecution, usagestore.CounterRevert}, + }, + { + // Case 4: multi-order dedup within one audit entry — a shared + // (account, asset) touched by three orders contributes to + // CounterVolume exactly once (entryVolumeState dedup). + name: "multi_order_shared_volume_dedup_within_entry", + entries: []seedAuditEntry{{ + seq: 1, + success: true, + items: []seedAuditItem{ + { + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "bank:main", "USD", 1)}, + }), + logSeq: 10, + log: createdTxLog(10, ledger, nil, + []*commonpb.Posting{usagePosting("world", "bank:main", "USD", 1)}, + []*commonpb.TouchedVolume{touchedVolume("bank:main", "USD", "")}, + nil, nil), + }, + { + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "bank:main", "USD", 2)}, + }), + logSeq: 11, + log: createdTxLog(11, ledger, nil, + []*commonpb.Posting{usagePosting("world", "bank:main", "USD", 2)}, + []*commonpb.TouchedVolume{touchedVolume("bank:main", "USD", "")}, + nil, nil), + }, + { + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "bank:main", "USD", 3)}, + }), + logSeq: 12, + log: createdTxLog(12, ledger, nil, + []*commonpb.Posting{usagePosting("world", "bank:main", "USD", 3)}, + []*commonpb.TouchedVolume{touchedVolume("bank:main", "USD", "")}, + nil, nil), + }, + }, + }}, + wantCursor: 1, + wantCounters: []wantCounter{ + // Postings are per-event: 3 orders → 3. + {usagestore.CounterPosting, 3}, + // Volume is per-entry cardinality: shared tuple counts once. + {usagestore.CounterVolume, 1}, + }, + }, + { + // Case 5: color dedup within one audit entry (regression guard) — + // two DISTINCT colors of the same (account, asset) each count + // independently. Two new-kept color buckets → CounterVolume == 2; + // two purged color buckets → CounterEphemeralEvicted == 2. + name: "distinct_colors_same_account_count_independently", + entries: []seedAuditEntry{{ + seq: 1, + success: true, + items: []seedAuditItem{{ + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "vault", "USD", 1)}, + }), + logSeq: 10, + log: createdTxLog(10, ledger, nil, + []*commonpb.Posting{usagePosting("world", "vault", "USD", 1)}, + []*commonpb.TouchedVolume{ + touchedVolume("vault", "USD", "red"), + touchedVolume("vault", "USD", "blue"), + }, + []*commonpb.TouchedVolume{ + touchedVolume("vault", "EUR", "red"), + touchedVolume("vault", "EUR", "blue"), + }, + nil), + }}, + }}, + wantCursor: 1, + wantCounters: []wantCounter{ + {usagestore.CounterPosting, 1}, + // 2 new-kept color buckets (+2), 2 purged color buckets (-2) → 0. + {usagestore.CounterVolume, 0}, + // Both purged color buckets are evictions → 2. + {usagestore.CounterEphemeralEvicted, 2}, + }, + }, + { + // Case 6: failed proposal contributes nothing. A success entry + // alongside it proves processing continues and the cursor still + // advances past the failure. + name: "failed_proposal_skipped", + entries: []seedAuditEntry{ + {seq: 1, success: false}, + { + seq: 2, + success: true, + items: []seedAuditItem{{ + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "dave", "USD", 9)}, + }), + logSeq: 10, + log: createdTxLog(10, ledger, nil, + []*commonpb.Posting{usagePosting("world", "dave", "USD", 9)}, + nil, nil, nil), + }}, + }, + }, + wantCursor: 2, + wantCounters: []wantCounter{{usagestore.CounterPosting, 1}}, + }, + { + // Case 8: LogSequence == 0 item is skipped (no log-producing order). + // The entry still advances the cursor but contributes no counters. + name: "log_sequence_zero_item_skipped", + entries: []seedAuditEntry{{ + seq: 1, + success: true, + items: []seedAuditItem{{ + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "eve", "USD", 1)}, + }), + logSeq: 0, // idempotent replay / non-log-producing → skip + log: nil, + }}, + }}, + wantCursor: 1, + zeroCounters: []byte{usagestore.CounterPosting, usagestore.CounterVolume}, + }, + { + // TransientVolumes on the AppliedProposal → CounterTransientUsed. + name: "transient_volumes_from_applied_proposal", + entries: []seedAuditEntry{{ + seq: 1, + success: true, + transientVolumes: map[string][]*commonpb.TouchedVolume{ + ledger: { + touchedVolume("tmp:1", "USD", ""), + touchedVolume("tmp:2", "USD", ""), + }, + }, + }}, + wantCursor: 1, + wantCounters: []wantCounter{{usagestore.CounterTransientUsed, 2}}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + primary, usage := newUsageTestStores(t) + seedAuditData(t, primary, tc.entries) + + b := newTestBuilder(primary, usage, 200) + + cursor, err := b.processAuditEntries(context.Background(), 0, time.Time{}) + require.NoError(t, err) + assert.Equal(t, tc.wantCursor, cursor, "cursor must advance to the last audit sequence") + assert.Equal(t, tc.wantCursor, b.LastProcessedAuditSequence(), "atomic hint must mirror the cursor") + + for _, wc := range tc.wantCounters { + got, err := usage.GetCounter(ledger, wc.id) + require.NoError(t, err) + assert.Equalf(t, wc.value, got, "counter %#x", wc.id) + } + + for _, id := range tc.zeroCounters { + got, err := usage.GetCounter(ledger, id) + require.NoError(t, err) + assert.Equalf(t, uint64(0), got, "counter %#x must be zero", id) + } + + for _, wt := range tc.wantTemplates { + got, err := usage.GetTemplateUsage(ledger, wt.name) + require.NoError(t, err) + require.NotNilf(t, got, "template %q must exist", wt.name) + assert.Equalf(t, wt.count, got.GetCount(), "template %q count", wt.name) + assert.Equalf(t, wt.lastUsed, got.GetLastUsed().GetData(), "template %q lastUsed", wt.name) + } + + // The persisted progress cursor must match the returned cursor. + progress, err := usage.ReadProgress() + require.NoError(t, err) + assert.Equal(t, tc.wantCursor, progress, "persisted progress must equal the cursor") + }) + } +} + +// TestProcessAuditEntries_SkippedCreateDoesNotCount guards the isCreatedTx gate: +// a CreateTransaction that produced an OrderSkipped log (no CreatedTransaction / +// RevertedTransaction payload) must contribute no reference / numscript / +// template counters even though the order carried them. +func TestProcessAuditEntries_SkippedCreateDoesNotCount(t *testing.T) { + t.Parallel() + + const ledger = "l1" + + primary, usage := newUsageTestStores(t) + + // A log with no CreatedTransaction/RevertedTransaction payload models a + // skipped order: readLog reports isCreatedTx == false. + skippedLog := &commonpb.Log{ + Sequence: 10, + Payload: &commonpb.LogPayload{ + Type: &commonpb.LogPayload_Apply{ + Apply: &commonpb.ApplyLedgerLog{ + LedgerName: ledger, + Log: &commonpb.LedgerLog{Id: 10}, + }, + }, + }, + } + + seedAuditData(t, primary, []seedAuditEntry{{ + seq: 1, + success: true, + items: []seedAuditItem{{ + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Reference: "ref-1", + NumscriptReference: &raftcmdpb.NumscriptReference{Name: "payout"}, + }), + logSeq: 10, + log: skippedLog, + }}, + }}) + + b := newTestBuilder(primary, usage, 200) + + cursor, err := b.processAuditEntries(context.Background(), 0, time.Time{}) + require.NoError(t, err) + require.Equal(t, uint64(1), cursor) + + for _, id := range []byte{ + usagestore.CounterReference, + usagestore.CounterNumscriptExecution, + usagestore.CounterPosting, + usagestore.CounterVolume, + } { + got, err := usage.GetCounter(ledger, id) + require.NoError(t, err) + assert.Equalf(t, uint64(0), got, "skipped create must not bump counter %#x", id) + } + + tpl, err := usage.GetTemplateUsage(ledger, "payout") + require.NoError(t, err) + assert.Nil(t, tpl, "skipped create must not record template usage") +} + +// TestProcessAuditEntries_BatchBoundaryAndCursorAdvance covers case 7: with +// batchSize=2 and three entries, all are processed across batches, the returned +// cursor equals the last sequence, and a second call from that cursor is a +// no-op (EOF). +func TestProcessAuditEntries_BatchBoundaryAndCursorAdvance(t *testing.T) { + t.Parallel() + + const ledger = "l1" + + primary, usage := newUsageTestStores(t) + + var entries []seedAuditEntry + for seq := uint64(1); seq <= 3; seq++ { + logSeq := 10 + seq + entries = append(entries, seedAuditEntry{ + seq: seq, + success: true, + items: []seedAuditItem{{ + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "acc", "USD", seq)}, + }), + logSeq: logSeq, + log: createdTxLog(logSeq, ledger, nil, + []*commonpb.Posting{usagePosting("world", "acc", "USD", seq)}, + nil, nil, nil), + }}, + }) + } + + seedAuditData(t, primary, entries) + + b := newTestBuilder(primary, usage, 2) // batchSize=2 → two commits (2 then 1) + + cursor, err := b.processAuditEntries(context.Background(), 0, time.Time{}) + require.NoError(t, err) + require.Equal(t, uint64(3), cursor, "all three entries processed across batch boundaries") + + got, err := usage.GetCounter(ledger, usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(3), got, "one posting per entry across both batches") + + // Persisted progress reflects the full drain. + progress, err := usage.ReadProgress() + require.NoError(t, err) + assert.Equal(t, uint64(3), progress) + + // A second call from the advanced cursor is a no-op: nothing new to read, + // clean EOF, cursor unchanged. + cursor2, err := b.processAuditEntries(context.Background(), cursor, time.Time{}) + require.NoError(t, err) + assert.Equal(t, uint64(3), cursor2, "re-running from the head is an idempotent no-op") + + got, err = usage.GetCounter(ledger, usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(3), got, "no-op pass must not double-count") +} + +// TestProcessAuditEntries_ResumeFromCursorSkipsProcessed verifies the cursor +// filter: starting from a non-zero cursor skips already-consumed entries and +// only folds the tail. +func TestProcessAuditEntries_ResumeFromCursorSkipsProcessed(t *testing.T) { + t.Parallel() + + const ledger = "l1" + + primary, usage := newUsageTestStores(t) + + var entries []seedAuditEntry + for seq := uint64(1); seq <= 3; seq++ { + logSeq := 100 + seq + entries = append(entries, seedAuditEntry{ + seq: seq, + success: true, + items: []seedAuditItem{{ + order: createTxOrder(ledger, &raftcmdpb.CreateTransactionOrder{ + Postings: []*commonpb.Posting{usagePosting("world", "acc", "USD", seq)}, + }), + logSeq: logSeq, + log: createdTxLog(logSeq, ledger, nil, + []*commonpb.Posting{usagePosting("world", "acc", "USD", seq)}, + nil, nil, nil), + }}, + }) + } + + seedAuditData(t, primary, entries) + + b := newTestBuilder(primary, usage, 200) + + // Resume from cursor=2: only entry seq 3 should be folded. + cursor, err := b.processAuditEntries(context.Background(), 2, time.Time{}) + require.NoError(t, err) + assert.Equal(t, uint64(3), cursor) + + got, err := usage.GetCounter(ledger, usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(1), got, "only the single post-cursor entry must be folded") +} diff --git a/internal/application/usagebuilder/process_audit_test.go b/internal/application/usagebuilder/process_audit_test.go new file mode 100644 index 0000000000..7f467a0862 --- /dev/null +++ b/internal/application/usagebuilder/process_audit_test.go @@ -0,0 +1,172 @@ +package usagebuilder + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + logging "github.com/formancehq/go-libs/v5/pkg/observe/log" + + "github.com/formancehq/ledger/v3/internal/proto/commonpb" + "github.com/formancehq/ledger/v3/internal/storage/usagestore" +) + +func TestBatchState_AddCounterAggregates(t *testing.T) { + t.Parallel() + + s := newBatchState() + + s.addCounter("l1", usagestore.CounterPosting, 3) + s.addCounter("l1", usagestore.CounterPosting, 5) + s.addCounter("l1", usagestore.CounterRevert, 2) + s.addCounter("l2", usagestore.CounterPosting, 7) + + assert.Equal(t, counterDelta(8), s.counters["l1"][usagestore.CounterPosting]) + assert.Equal(t, counterDelta(2), s.counters["l1"][usagestore.CounterRevert]) + assert.Equal(t, counterDelta(7), s.counters["l2"][usagestore.CounterPosting]) +} + +func TestBatchState_AddTemplateUsageMaxLastUsed(t *testing.T) { + t.Parallel() + + s := newBatchState() + + early := &commonpb.Timestamp{Data: 100} + mid := &commonpb.Timestamp{Data: 500} + late := &commonpb.Timestamp{Data: 900} + + // Ordering shouldn't matter — the max of the three timestamps wins. + s.addTemplateUsage("l1", "payout", mid) + s.addTemplateUsage("l1", "payout", late) + s.addTemplateUsage("l1", "payout", early) + + got := s.templates[templateKey{ledger: "l1", template: "payout"}] + assert.Equal(t, uint64(3), got.count) + assert.Equal(t, late, got.lastUsed) +} + +func TestBatchState_AddTemplateUsageNilTimestamp(t *testing.T) { + t.Parallel() + + s := newBatchState() + + // A nil timestamp bumps the counter but must not overwrite an already-seen + // non-nil lastUsed. + s.addTemplateUsage("l1", "payout", &commonpb.Timestamp{Data: 500}) + s.addTemplateUsage("l1", "payout", nil) + + got := s.templates[templateKey{ledger: "l1", template: "payout"}] + assert.Equal(t, uint64(2), got.count) + assert.Equal(t, uint64(500), got.lastUsed.GetData()) +} + +func TestBatchState_EmptyOnFreshState(t *testing.T) { + t.Parallel() + + assert.True(t, newBatchState().empty()) +} + +func TestApplyDelta(t *testing.T) { + t.Parallel() + + assert.Equal(t, uint64(15), applyDelta(10, 5)) + assert.Equal(t, uint64(5), applyDelta(10, -5)) + assert.Equal(t, uint64(0), applyDelta(10, -10)) + assert.Equal(t, uint64(0), applyDelta(3, -10), "underflow must clamp at zero") + assert.Equal(t, uint64(7), applyDelta(7, 0)) +} + +func TestTimestampGreater(t *testing.T) { + t.Parallel() + + a := &commonpb.Timestamp{Data: 100} + b := &commonpb.Timestamp{Data: 200} + + assert.True(t, timestampGreater(b, a)) + assert.False(t, timestampGreater(a, b)) + assert.False(t, timestampGreater(a, a), "equal timestamps are not greater") +} + +func TestMergeTemplateUsage_NilCurrent(t *testing.T) { + t.Parallel() + + ts := &commonpb.Timestamp{Data: 500} + + got := mergeTemplateUsage(nil, templateDelta{count: 3, lastUsed: ts}) + assert.Equal(t, uint64(3), got.GetCount()) + assert.Equal(t, ts, got.GetLastUsed()) +} + +func TestMergeTemplateUsage_WithCurrent(t *testing.T) { + t.Parallel() + + current := &commonpb.TemplateUsage{ + Count: 10, + LastUsed: &commonpb.Timestamp{Data: 500}, + } + + // Newer batch timestamp wins. + got := mergeTemplateUsage(current, templateDelta{count: 5, lastUsed: &commonpb.Timestamp{Data: 900}}) + assert.Equal(t, uint64(15), got.GetCount()) + assert.Equal(t, uint64(900), got.GetLastUsed().GetData()) + + // Older batch timestamp is ignored. + got = mergeTemplateUsage(current, templateDelta{count: 2, lastUsed: &commonpb.Timestamp{Data: 200}}) + assert.Equal(t, uint64(12), got.GetCount()) + assert.Equal(t, uint64(500), got.GetLastUsed().GetData(), "current lastUsed is later — keep it") + + // Nil batch timestamp: current lastUsed preserved. + got = mergeTemplateUsage(current, templateDelta{count: 1, lastUsed: nil}) + assert.Equal(t, uint64(11), got.GetCount()) + assert.Equal(t, uint64(500), got.GetLastUsed().GetData()) +} + +// TestCommitBatch_SameBatchDeleteRecreateDoesNotResurrect guards the +// same-batch delete+recreate hazard: GetCounter / GetTemplateUsage read the +// committed DB, not the pending batch's DeleteRange, so without a zero +// baseline for deleted ledgers commitBatch would write old+delta on top of +// the DeleteRange and resurrect the old incarnation's counts. +func TestCommitBatch_SameBatchDeleteRecreateDoesNotResurrect(t *testing.T) { + t.Parallel() + + us, err := usagestore.New(t.TempDir(), logging.NopZap(), usagestore.DefaultConfig()) + require.NoError(t, err) + t.Cleanup(func() { _ = us.Close() }) + + b := &Builder{usageStore: us} + + // Seed the OLD incarnation: 100 postings and a template with count 7. + seed := newBatchState() + seed.addCounter("foo", usagestore.CounterPosting, 100) + seed.addTemplateUsage("foo", "tpl", &commonpb.Timestamp{Data: 111}) + for range 6 { + seed.addTemplateUsage("foo", "tpl", &commonpb.Timestamp{Data: 111}) + } + require.NoError(t, b.commitBatch(seed, 1)) + + // Sanity: the old incarnation is persisted. + c, err := us.GetCounter("foo", usagestore.CounterPosting) + require.NoError(t, err) + require.Equal(t, uint64(100), c) + + // A single batch deletes "foo" and then recreates it with 5 new + // postings + a single template invocation. + batch := newBatchState() + batch.markLedgerDeleted("foo") + batch.addCounter("foo", usagestore.CounterPosting, 5) + batch.addTemplateUsage("foo", "tpl", &commonpb.Timestamp{Data: 999}) + require.NoError(t, b.commitBatch(batch, 2)) + + // The recycled ledger must reflect ONLY the post-recreate deltas, not + // old+delta. + c, err = us.GetCounter("foo", usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(5), c, "counter must not resurrect the deleted incarnation's value") + + tpl, err := us.GetTemplateUsage("foo", "tpl") + require.NoError(t, err) + require.NotNil(t, tpl) + assert.Equal(t, uint64(1), tpl.GetCount(), "template count must not resurrect the deleted incarnation") + assert.Equal(t, uint64(999), tpl.GetLastUsed().GetData()) +} diff --git a/internal/bootstrap/controller_routed.go b/internal/bootstrap/controller_routed.go index bb8cf8454f..904fa31b69 100644 --- a/internal/bootstrap/controller_routed.go +++ b/internal/bootstrap/controller_routed.go @@ -361,6 +361,15 @@ func (b *RoutedController) ListNumscripts(ctx context.Context, ledger string) ([ return c.ListNumscripts(ctx, ledger) } +func (b *RoutedController) GetTemplateUsage(ctx context.Context, ledger, name string) (*commonpb.TemplateUsage, error) { + c, _, err := b.readCtrl(ctx) + if err != nil { + return nil, err + } + + return c.GetTemplateUsage(ctx, ledger, name) +} + func (b *RoutedController) GetChapterSchedule(ctx context.Context) (string, error) { c, _, err := b.readCtrl(ctx) if err != nil { diff --git a/internal/bootstrap/module.go b/internal/bootstrap/module.go index cc95e486de..507796ef80 100644 --- a/internal/bootstrap/module.go +++ b/internal/bootstrap/module.go @@ -40,6 +40,7 @@ import ( "github.com/formancehq/ledger/v3/internal/application/indexbuilder" "github.com/formancehq/ledger/v3/internal/application/membership" "github.com/formancehq/ledger/v3/internal/application/mirror" + "github.com/formancehq/ledger/v3/internal/application/usagebuilder" "github.com/formancehq/ledger/v3/internal/domain/crypto/keystore" "github.com/formancehq/ledger/v3/internal/domain/crypto/signing" "github.com/formancehq/ledger/v3/internal/domain/processing/numscript" @@ -71,6 +72,7 @@ import ( "github.com/formancehq/ledger/v3/internal/storage/dal" "github.com/formancehq/ledger/v3/internal/storage/readstore" "github.com/formancehq/ledger/v3/internal/storage/spool" + "github.com/formancehq/ledger/v3/internal/storage/usagestore" "github.com/formancehq/ledger/v3/internal/storage/wal" ) @@ -398,6 +400,7 @@ func Module() fx.Option { eventNotifications *signal.Notifications, mirrorNotifications *signal.Notifications, indexNotifications *signal.Notifications, + usageNotifications *signal.Notifications, bloomFilters *bloom.FilterSet, membership *raftmembership.Membership, ) (*state.Machine, error) { @@ -406,8 +409,8 @@ func Module() fx.Option { idempotencyTTLMicros := uint64(cfg.IdempotencyTTL.Microseconds()) // Fan-out: Machine emits to a single Notifier; FanOut dispatches - // to the per-consumer Notifications (events, mirror, index). - fanOut := signal.NewFanOut(eventNotifications, mirrorNotifications, indexNotifications) + // to the per-consumer Notifications (events, mirror, index, usage). + fanOut := signal.NewFanOut(eventNotifications, mirrorNotifications, indexNotifications, usageNotifications) // Sub-objects built in-line so NewMachine receives them pre-built. registry := state.NewStateRegistry(c, attrs, idempotencyTTLMicros) @@ -437,7 +440,7 @@ func Module() fx.Option { }).Infof("FSM Machine created") return m, nil - }, fx.ParamTags(``, ``, ``, ``, ``, ``, ``, ``, `name:"events"`, `name:"mirror"`, `name:"index"`, ``, ``)), + }, fx.ParamTags(``, ``, ``, ``, ``, ``, ``, ``, `name:"events"`, `name:"mirror"`, `name:"index"`, `name:"usage"`, ``, ``)), func( params struct { fx.In @@ -636,6 +639,7 @@ func Module() fx.Option { fx.Annotate(events.NewManager, fx.ParamTags(``, ``, ``, ``, ``, `name:"events"`)), fx.Annotate(signal.NewNotifications, fx.ResultTags(`name:"mirror"`)), fx.Annotate(signal.NewNotifications, fx.ResultTags(`name:"index"`)), + fx.Annotate(signal.NewNotifications, fx.ResultTags(`name:"usage"`)), fx.Annotate(func(store *dal.Store, proposer mirror.Proposer, builder *plan.Builder, logger logging.Logger, notifications *signal.Notifications, meterProvider metric.MeterProvider, cfg Config) *mirror.Manager { return mirror.NewManager(store, proposer, builder, logger, notifications, meterProvider, cfg.MirrorMaxBatchSize) }, fx.ParamTags(``, ``, ``, ``, `name:"mirror"`, ``, ``)), @@ -666,6 +670,26 @@ func Module() fx.Option { store, rs, logger, meterProvider.Meter("audit.index"), ) }, + // Usage store (Pebble) — dedicated secondary store for the + // usagebuilder projections. Kept physically separate from the + // readstore so an operational reset is just a directory drop and + // the builder re-derives every counter from the audit chain. + func(cfg Config, logger logging.Logger) (*usagestore.Store, error) { + dir := filepath.Join(cfg.DataDir, "usage") + + return usagestore.New(dir, logger, usagestore.DefaultConfig()) + }, + // Usage builder — tails the FSM audit chain to populate the usage + // store (template usage + per-ledger event counters). Notifications + // arrive via the dedicated `name:"usage"` FanOut target. + fx.Annotate(func(store *dal.Store, us *usagestore.Store, notifications *signal.Notifications, logger logging.Logger, meterProvider metric.MeterProvider, cfg Config) *usagebuilder.Builder { + // Final arg is batchSize; 0 selects usagebuilder.DefaultBatchSize. + // No rollback/catch-up guard is needed: audit entries are written + // only for committed Raft entries, so the audit chain is + // append-only and the persisted cursor can never sit ahead of the + // head — the builder only ever moves forward. + return usagebuilder.NewBuilder(store, us, notifications, logger, meterProvider.Meter("usage.builder"), 0) + }, fx.ParamTags(``, ``, `name:"usage"`, ``, ``, ``)), httpcompat.NewServer, func(cfg Config, logger logging.Logger, backend httpcompat.Backend, authCfg internalauth.AuthConfig, info version.Info) http.Handler { return httpcompat.NewHandler(logger, backend, authCfg, info) @@ -793,18 +817,19 @@ func Module() fx.Option { logger logging.Logger, attrs *attributes.Attributes, rs *readstore.Store, + us *usagestore.Store, coldReader *coldstorage.ColdReader, receiptSigner *receipt.Signer, meterProvider metric.MeterProvider, ) (ctrl.Controller, *ctrl.DefaultController) { - defaultCtrl := ctrl.NewDefaultController(admission, store, logger, attrs, rs, coldReader, receiptSigner, meterProvider.Meter("ctrl")) + defaultCtrl := ctrl.NewDefaultController(admission, store, logger, attrs, rs, us, coldReader, receiptSigner, meterProvider.Meter("ctrl")) return NewRoutedController( defaultCtrl, raftNode, servicePool, ), defaultCtrl - }, fx.ParamTags(``, `name:"service"`, ``, ``, ``, ``, ``, `optional:"true"`, ``, ``)), + }, fx.ParamTags(``, `name:"service"`, ``, ``, ``, ``, ``, ``, `optional:"true"`, ``, ``)), func(serviceServer *grpcadp.ServiceServer, n *node.Node) *clusterhealth.GRPCHealthUpdater { hs := health.NewServer() healthpb.RegisterHealthServer(serviceServer.GetServer(), hs) @@ -841,6 +866,7 @@ func Module() fx.Option { runtime *dal.Store, wal *wal.DefaultWAL, rs *readstore.Store, + us *usagestore.Store, sp *spool.Default, cfg Config, logger logging.Logger, @@ -860,6 +886,11 @@ func Module() fx.Option { return rs.Close() }, }) + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + return us.Close() + }, + }) }, // Bloom-rebuild dispatcher: the Machine signals on its // BloomRebuildCh when a cluster-config change requires a rebuild; @@ -1340,6 +1371,21 @@ func Module() fx.Option { return nil }, + // Register Pebble usage store metrics and unregister on stop. + func(lc fx.Lifecycle, us *usagestore.Store, meterProvider metric.MeterProvider) error { + reg, err := us.RegisterMetrics(meterProvider.Meter("usagestore")) + if err != nil { + return fmt.Errorf("registering usagestore metrics: %w", err) + } + + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + return reg.Unregister() + }, + }) + + return nil + }, // Start and stop the index builder. // The builder has its own dedicated Notifications signal to receive // log-committed events from the FSM without competing with other consumers. @@ -1351,6 +1397,12 @@ func Module() fx.Option { func(lc fx.Lifecycle, auditIndexer *auditindexer.Indexer) { lc.Append(worker.FxHook(auditIndexer)) }, + // Start and stop the usage builder. Notifications are already + // wired at construction time (constructor injection), so this + // hook only needs the lifecycle wiring. + func(lc fx.Lifecycle, usageBuilder *usagebuilder.Builder) { + lc.Append(worker.FxHook(usageBuilder)) + }, ), ) } diff --git a/internal/domain/processing/processor_mirror.go b/internal/domain/processing/processor_mirror.go index 2f817548c6..220caa86fd 100644 --- a/internal/domain/processing/processor_mirror.go +++ b/internal/domain/processing/processor_mirror.go @@ -214,7 +214,9 @@ func processMirrorCreatedTransaction(ledger string, ct *raftcmdpb.MirrorCreatedT if boundaries.GetNextTransactionId() <= txID { boundaries.NextTransactionId = txID + 1 } - boundaries.PostingCount += uint64(len(ct.GetPostings())) + + // posting_count is no longer maintained on LedgerBoundaries — the + // usagebuilder derives it from the audit chain. See EN-1420. timestamp := ct.GetTimestamp() if timestamp == nil { @@ -396,8 +398,10 @@ func processMirrorRevertedTransaction(ledger string, rt *raftcmdpb.MirrorReverte if boundaries.GetNextTransactionId() <= revertTxID { boundaries.NextTransactionId = revertTxID + 1 } - boundaries.PostingCount += uint64(len(rt.GetReversePostings())) - boundaries.RevertCount++ + + // posting_count and revert_count are no longer maintained on + // LedgerBoundaries — the usagebuilder derives them from the audit + // chain. See EN-1420. timestamp := rt.GetTimestamp() if timestamp == nil { diff --git a/internal/domain/processing/processor_revert_transaction.go b/internal/domain/processing/processor_revert_transaction.go index f69757de44..32adc05185 100644 --- a/internal/domain/processing/processor_revert_transaction.go +++ b/internal/domain/processing/processor_revert_transaction.go @@ -95,8 +95,10 @@ func processRevertTransaction(ledger string, order *raftcmdpb.RevertTransactionO // Get new transaction ID for the revert transaction revertTxID := boundaries.GetNextTransactionId() boundaries.NextTransactionId = revertTxID + 1 - boundaries.PostingCount += uint64(len(revertPostings)) - boundaries.RevertCount++ + + // posting_count and revert_count are no longer maintained on + // LedgerBoundaries — the usagebuilder derives them from the audit + // chain. See EN-1420. // Resolve the revert timestamp. When at_effective_date is set, the compensating // transaction inherits the original's effective timestamp (parity with diff --git a/internal/domain/processing/processor_transaction.go b/internal/domain/processing/processor_transaction.go index 28ba82f1c4..f84f853002 100644 --- a/internal/domain/processing/processor_transaction.go +++ b/internal/domain/processing/processor_transaction.go @@ -88,11 +88,12 @@ func processCreateTransaction(ledger string, order *raftcmdpb.CreateTransactionO nextTransactionID := boundaries.GetNextTransactionId() boundaries.NextTransactionId = nextTransactionID + 1 - boundaries.PostingCount += uint64(len(result.Postings)) - if isNumscript { - boundaries.NumscriptExecutionCount++ - } + // posting_count, numscript_execution_count, revert_count, reference_count + // are no longer maintained on LedgerBoundaries — they are derived from the + // audit chain by internal/application/usagebuilder and served by the + // LedgerStats handler out of usagestore. See EN-1420. + _ = isNumscript // Use the user-provided timestamp, or fall back to the command date. // The effective timestamp is recorded on TransactionState so reverts can diff --git a/internal/infra/backup/rebuild.go b/internal/infra/backup/rebuild.go index 733682a7d6..d8ba20f1bf 100644 --- a/internal/infra/backup/rebuild.go +++ b/internal/infra/backup/rebuild.go @@ -10,7 +10,6 @@ import ( "github.com/cockroachdb/pebble/v2" "github.com/holiman/uint256" - "google.golang.org/protobuf/proto" logging "github.com/formancehq/go-libs/v5/pkg/observe/log" @@ -431,19 +430,10 @@ func RebuildDelta( return fmt.Errorf("applying audit order effects to boundaries: %w", err) } - // Net attribute counts (VolumeCount, MetadataCount, ReferenceCount) are - // read from the committed 0xF1 state, so this runs after the attribute - // commit. The boundaries themselves are then written in their own batch. - countHandle, err := store.NewDirectReadHandle() - if err != nil { - return fmt.Errorf("opening read handle for boundary counts: %w", err) - } - defer func() { _ = countHandle.Close() }() - - if err := writer.countNetAttributes(countHandle); err != nil { - return fmt.Errorf("counting net attributes for boundaries: %w", err) - } - + // The rebuilt boundaries (NextTransactionId / NextLogId / mirror + // high-water) are written in their own batch after the attribute commit. + // The per-ledger usage counters live in the usagestore peer secondary + // store and are rebuilt there, so they are not derived or written here. writer.batch = store.OpenWriteSession() if err := writer.flushBoundaries(); err != nil { @@ -718,10 +708,10 @@ type attributeReplayWriter struct { // LedgerBoundaries per touched ledger. The apply path preloads boundaries // from the SubAttrBoundary attribute, which the log replay does not write - // per-entry: NextTransactionId / NextLogId and the per-transaction counters - // accumulate here, seeded from the checkpoint on first touch via - // readHandle, and are flushed in their own batch after the attribute - // commit (net counts are derived from the committed 0xF1 state). + // per-entry: NextTransactionId / NextLogId accumulate here, seeded from the + // checkpoint on first touch via readHandle, and are flushed in their own + // batch after the attribute commit. The per-ledger usage counters live in + // the usagestore peer secondary store, not here. boundaries map[string]*raftcmdpb.LedgerBoundaries readHandle dal.PebbleReader @@ -738,14 +728,13 @@ type attributeReplayWriter struct { // applyAuditOrderEffects folds order-level boundary effects that the ledger-log // stream does not carry: MirrorFillGap's skipped transaction ids (FilledGapLog -// keeps only the original v2 id) and NumscriptExecutionCount (CreatedTransaction -// logs record the resulting postings, not the content source). Both live on the -// order itself, which AuditItem.serialized_order preserves — bound into the -// audit hash chain and shipped by the incremental export's auditItem segments. +// keeps only the original v2 id). These live on the order itself, which +// AuditItem.serialized_order preserves — bound into the audit hash chain and +// shipped by the incremental export's auditItem segments. // // Items with log_sequence == 0 (failed proposals, idempotent replays) and items // at or below fromLogSeq (already folded into the checkpoint) contribute -// nothing. See replay.OrderEffects for why script detection is exact. +// nothing. func (w *attributeReplayWriter) applyAuditOrderEffects(reader dal.PebbleReader, fromLogSeq, fromAuditSeq uint64) error { lower := dal.NewKeyBuilder(). PutZonePrefix(dal.ZoneCold, dal.SubColdAuditItem). @@ -806,10 +795,6 @@ func (w *attributeReplayWriter) applyAuditOrderEffects(reader dal.PebbleReader, b.NextTransactionId = next } } - - if effects.IsNumscript { - b.NumscriptExecutionCount++ - } } return iter.Error() @@ -924,11 +909,12 @@ func (w *attributeReplayWriter) advanceLogID(ledgerName string, logID uint64) er return nil } -// recordTransactionBoundary advances a ledger's boundaries for one created -// transaction: NextTransactionId past its id, PostingCount by its postings, and -// RevertCount when it reverts another (revert reversals carry revertsTransaction -// and flow through CreateTransaction like any other tx). -func (w *attributeReplayWriter) recordTransactionBoundary(canonicalKey []byte, postingCount int, revertsTransaction uint64) error { +// recordTransactionBoundary advances a ledger's NextTransactionId past a created +// transaction's id (revert reversals carry revertsTransaction and flow through +// CreateTransaction like any other tx). The per-ledger usage counters +// (PostingCount, RevertCount) live in the usagestore peer secondary store and +// are rebuilt there, so they are not advanced here. +func (w *attributeReplayWriter) recordTransactionBoundary(canonicalKey []byte) error { var tk domain.TransactionKey if err := tk.Unmarshal(canonicalKey); err != nil { return fmt.Errorf("parsing transaction key for boundaries: %w", err) @@ -943,70 +929,9 @@ func (w *attributeReplayWriter) recordTransactionBoundary(canonicalKey []byte, p b.NextTransactionId = next } - b.PostingCount += uint64(postingCount) - - if revertsTransaction != 0 { - b.RevertCount++ - } - return nil } -// countNetAttributes sets VolumeCount, MetadataCount and ReferenceCount for -// every touched ledger to the number of persisted keys in the committed 0xF1 -// state. These are net (last-value) counts, so counting the final keys is -// exact: ephemeral and transient volumes have already been purged, matching the -// live counters. -// -// NextTransactionId, NextLogId, PostingCount, RevertCount accumulate during -// the log replay; NumscriptExecutionCount and the mirror fill-gap advances come -// from applyAuditOrderEffects. EphemeralEvictedCount / TransientUsedCount are -// carried from the checkpoint unchanged. -func (w *attributeReplayWriter) countNetAttributes(reader dal.PebbleReader) error { - for name, b := range w.boundaries { - prefix := domain.LedgerScopedPrefix(name) - - volumeCount, err := countAttributeKeys(w.volume, reader, prefix) - if err != nil { - return fmt.Errorf("counting volumes for ledger %q: %w", name, err) - } - - metadataCount, err := countAttributeKeys(w.metadata, reader, prefix) - if err != nil { - return fmt.Errorf("counting metadata for ledger %q: %w", name, err) - } - - referenceCount, err := countAttributeKeys(w.references, reader, prefix) - if err != nil { - return fmt.Errorf("counting references for ledger %q: %w", name, err) - } - - b.VolumeCount = volumeCount - b.MetadataCount = metadataCount - b.ReferenceCount = referenceCount - } - - return nil -} - -// countAttributeKeys counts the persisted keys under a canonical prefix (the -// fixed-width ledger name) in the 0xF1 attribute zone. -func countAttributeKeys[V proto.Message](attr *attributes.Attribute[V], reader dal.PebbleReader, prefix []byte) (uint64, error) { - si, err := attr.NewStreamingIter(reader, prefix) - if err != nil { - return 0, err - } - - defer func() { _ = si.Close() }() - - var count uint64 - for si.Next() { - count++ - } - - return count, si.Err() -} - // flushReversions writes the reversion bitset words of every ledger the // replay reverted in, in the same [zone][sub][ledger][wordIndex] layout the // FSM persists (SaveReversionWord). Untouched ledgers keep their @@ -1160,7 +1085,7 @@ func (w *attributeReplayWriter) getTx(canonicalKey []byte) (*commonpb.Transactio } func (w *attributeReplayWriter) CreateTransaction(canonicalKey []byte, seq uint64, timestamp *commonpb.Timestamp, metadata map[string]*commonpb.MetadataValue, postings []*commonpb.Posting, revertsTransaction uint64) error { - if err := w.recordTransactionBoundary(canonicalKey, len(postings), revertsTransaction); err != nil { + if err := w.recordTransactionBoundary(canonicalKey); err != nil { return err } diff --git a/internal/infra/backup/rebuild_test.go b/internal/infra/backup/rebuild_test.go index b08b86b31a..e177130fb7 100644 --- a/internal/infra/backup/rebuild_test.go +++ b/internal/infra/backup/rebuild_test.go @@ -147,21 +147,6 @@ func fillGapOrder(ledger string, v2LogID uint64, skippedIDs ...uint64) *raftcmdp } } -func createTransactionOrder(ledger string, ct *raftcmdpb.CreateTransactionOrder) *raftcmdpb.Order { - return &raftcmdpb.Order{ - Type: &raftcmdpb.Order_LedgerScoped{ - LedgerScoped: &raftcmdpb.LedgerScopedOrder{ - Ledger: ledger, - Payload: &raftcmdpb.LedgerScopedOrder_Apply{ - Apply: &raftcmdpb.LedgerApplyOrder{ - Data: &raftcmdpb.LedgerApplyOrder_CreateTransaction{CreateTransaction: ct}, - }, - }, - }, - }, - } -} - func auditSuccess(seq, minLogSeq, maxLogSeq uint64) *auditpb.AuditEntry { return &auditpb.AuditEntry{ Sequence: seq, @@ -267,18 +252,15 @@ func TestRebuildDelta_ReplaysEphemeralPurgeAtProposalBoundary(t *testing.T) { require.Equal(t, "8", pair.GetInput().ToBigInt().String()) require.Equal(t, "5", pair.GetOutput().ToBigInt().String()) - // Boundaries are rebuilt into the attribute zone with reconstructed - // counters. Log ids here equal the log sequence (test fixture), so - // NextLogId is max(seq)+1 over the four apply logs (seqs 2-5). + // Boundaries are rebuilt into the attribute zone with the id fields. Log + // ids here equal the log sequence (test fixture), so NextLogId is + // max(seq)+1 over the four apply logs (seqs 2-5). The per-ledger usage + // counters live in the usagestore peer secondary store, not here. boundary, err := attrs.Boundary.Get(handle, domain.LedgerKey{Name: "ledger"}.Bytes()) require.NoError(t, err) require.NotNil(t, boundary, "boundaries must be reconstructed into the attribute zone") require.Equal(t, uint64(4), boundary.GetNextTransactionId(), "3 transactions created") require.Equal(t, uint64(6), boundary.GetNextLogId()) - require.Equal(t, uint64(3), boundary.GetPostingCount(), "one posting per transaction") - require.Equal(t, uint64(0), boundary.GetRevertCount()) - require.Equal(t, uint64(2), boundary.GetVolumeCount(), "orders:1 + world; ephemeral orders:1 kept because input != output") - require.Equal(t, uint64(0), boundary.GetMetadataCount()) } func TestRebuildDelta_ReconstructsTransactionReference(t *testing.T) { @@ -306,10 +288,6 @@ func TestRebuildDelta_ReconstructsTransactionReference(t *testing.T) { require.NoError(t, err) require.NotNil(t, ref, "reference index must be reconstructed") require.Equal(t, uint64(1), ref.GetTransactionId()) - - boundary, err := attrs.Boundary.Get(handle, domain.LedgerKey{Name: "ledger"}.Bytes()) - require.NoError(t, err) - require.Equal(t, uint64(1), boundary.GetReferenceCount()) } func TestRebuildDelta_AdvancesBoundariesForMirrorFillGap(t *testing.T) { @@ -341,51 +319,6 @@ func TestRebuildDelta_AdvancesBoundariesForMirrorFillGap(t *testing.T) { require.Equal(t, uint64(3), boundary.GetNextLogId()) } -func TestRebuildDelta_CountsNumscriptExecutionsFromAuditOrders(t *testing.T) { - t.Parallel() - - store := newRebuildTestStore(t) - - batch := store.OpenWriteSession() - require.NoError(t, batch.SetProto(coldLogKey(1), createLedgerLog(1, "ledger", 1))) - for seq := uint64(2); seq <= 4; seq++ { - require.NoError(t, batch.SetProto(coldLogKey(seq), applyLedgerLog(seq, "ledger", - createdTransactionPayload(seq-1, rebuildTestPosting("world", "alice", "USD", 10)), - ))) - } - - // Inline script and library reference both count; a postings order and a - // failed script order (log_sequence 0) do not. - scriptOrder := createTransactionOrder("ledger", &raftcmdpb.CreateTransactionOrder{ - Script: &commonpb.Script{Plain: "send [USD 10] (source = @world destination = @alice)"}, - }) - refOrder := createTransactionOrder("ledger", &raftcmdpb.CreateTransactionOrder{ - NumscriptReference: &raftcmdpb.NumscriptReference{Name: "payout", Version: "1"}, - }) - postingsOrder := createTransactionOrder("ledger", &raftcmdpb.CreateTransactionOrder{ - Postings: []*commonpb.Posting{rebuildTestPosting("world", "alice", "USD", 10)}, - }) - require.NoError(t, batch.SetProto(coldAuditItemKey(1, 0), auditItem(t, 2, scriptOrder))) - require.NoError(t, batch.SetProto(coldAuditItemKey(2, 0), auditItem(t, 3, refOrder))) - require.NoError(t, batch.SetProto(coldAuditItemKey(3, 0), auditItem(t, 4, postingsOrder))) - require.NoError(t, batch.SetProto(coldAuditItemKey(4, 0), auditItem(t, 0, scriptOrder))) - require.NoError(t, batch.Commit()) - - require.NoError(t, RebuildDelta(context.Background(), testLogger(), store, 0, 0)) - - handle, err := store.NewDirectReadHandle() - require.NoError(t, err) - defer func() { _ = handle.Close() }() - - attrs := attributes.New() - - boundary, err := attrs.Boundary.Get(handle, domain.LedgerKey{Name: "ledger"}.Bytes()) - require.NoError(t, err) - require.NotNil(t, boundary) - require.Equal(t, uint64(2), boundary.GetNumscriptExecutionCount(), - "inline script + library reference count; postings and failed orders do not") -} - func TestRebuildDelta_ReplaysLedgerMetadata(t *testing.T) { t.Parallel() @@ -899,40 +832,6 @@ func TestAttributeReplayWriter_RemoveFieldTypeNoSchemaIsNoOp(t *testing.T) { require.NoError(t, writer.RemoveMetadataFieldType("ledger", commonpb.TargetType_TARGET_TYPE_ACCOUNT, "k")) } -// TestRebuildDelta_CountsDoNotBleedAcrossPrefixLedgers: net counts must scan -// with the padded ledger prefix — an unpadded prefix also matches every -// ledger whose name extends it. -func TestRebuildDelta_CountsDoNotBleedAcrossPrefixLedgers(t *testing.T) { - t.Parallel() - - store := newRebuildTestStore(t) - - batch := store.OpenWriteSession() - require.NoError(t, batch.SetProto(coldLogKey(1), createLedgerLog(1, "pay", 1))) - require.NoError(t, batch.SetProto(coldLogKey(2), createLedgerLog(2, "payments", 2))) - require.NoError(t, batch.SetProto(coldLogKey(3), applyLedgerLog(3, "pay", - createdTransactionPayload(1, rebuildTestPosting("world", "alice", "USD", 10)), - ))) - require.NoError(t, batch.SetProto(coldLogKey(4), applyLedgerLog(4, "payments", - createdTransactionPayload(1, rebuildTestPosting("world", "bob", "USD", 10)), - ))) - require.NoError(t, batch.Commit()) - - require.NoError(t, RebuildDelta(context.Background(), testLogger(), store, 0, 0)) - - handle, err := store.NewDirectReadHandle() - require.NoError(t, err) - defer func() { _ = handle.Close() }() - - attrs := attributes.New() - - boundary, err := attrs.Boundary.Get(handle, domain.LedgerKey{Name: "pay"}.Bytes()) - require.NoError(t, err) - require.NotNil(t, boundary) - require.Equal(t, uint64(2), boundary.GetVolumeCount(), - `"pay" must count only its own rows (world + alice), not "payments" rows too`) -} - // TestAttributeReplayWriter_DeleteLedgerRemovesReversionRows: DeleteLedger // replay must delete the ledger's persisted reversion words — the live path // does so at apply time (not at the covering purge), so leaving them would diff --git a/internal/infra/state/write_set.go b/internal/infra/state/write_set.go index e7183e1ff2..261d7d5b5e 100644 --- a/internal/infra/state/write_set.go +++ b/internal/infra/state/write_set.go @@ -96,12 +96,27 @@ type WriteSet struct { transientVolumes map[string][]*commonpb.TouchedVolume // purgedByLog[i] is the deduplicated list of (account, asset) volumes - // that the log produced by order i touched and that the proposal-level - // partitionVolumes classified as purged. Computed during Merge from - // volumes.Slots() ∩ partResult.purged. Injected into each + // drained to zero (had a prior non-zero balance, now zero and evicted + // from Pebble) by the log produced by order i. DISJOINT from + // newKeptByLog and ephemeralByLog. Injected into each // LedgerLog.purged_volumes before AppendLogs. purgedByLog [][]*commonpb.TouchedVolume + // newKeptByLog[i] is the deduplicated list of (account, asset) volumes + // whose persistent entry was newly created by order i AND survived + // past commit. DISJOINT from purgedByLog and ephemeralByLog. Injected + // into each LedgerLog.new_kept_volumes before AppendLogs. Feeds the + // usagebuilder's VolumeCount projection. + newKeptByLog [][]*commonpb.TouchedVolume + + // ephemeralByLog[i] is the deduplicated list of (account, asset) + // volumes that were both newly created AND purged by order i — pure + // ephemeral. DISJOINT from purgedByLog and newKeptByLog. Injected + // into each LedgerLog.ephemeral_volumes before AppendLogs. Consumed + // by the index builder (skip acct->tx mappings) alongside + // purgedByLog; contributes 0 to VolumeCount. + ephemeralByLog [][]*commonpb.TouchedVolume + // bloomUpdates collects canonical keys per attribute type during Merge // for bloom filter updates before batch.Commit(). bloomUpdates bloom.BloomUpdates @@ -257,8 +272,13 @@ func (b *WriteSet) Merge(batch *dal.WriteSession, logsOrRefs []*raftcmdpb.Create return fmt.Errorf("failed to merge references: %w", err) } - // Update per-ledger attribute counters in boundaries before merging them. - b.updateBoundaryCounters(volumeUpdates, partResult.purged, partResult.transient, metadataUpdates, metadataDeletions, referenceUpdates) + // No boundary-counter mutation here anymore: every per-ledger counter + // moved to the usagebuilder subsystem (EN-1420 / EN-1422). LedgerBoundaries + // carries only the two ID generators now, and they are mutated by the + // posting producers directly on the boundaries reader. + // + // The `new_volumes` list is computed post-merge alongside `purged_volumes` + // — see the log-injection block below. boundaryUpdates, boundaryDeletions, err := b.Derived.Boundaries.Merge() if err != nil { @@ -398,11 +418,23 @@ func (b *WriteSet) Merge(batch *dal.WriteSession, logsOrRefs []*raftcmdpb.Create } // Build createdLogs (skipping idempotency replays) and inject the - // per-log purged_volumes subset before persisting. purgedByLog is - // indexed by ORDER index — same as logsOrRefs — so the mapping uses - // the loop's i, not the createdLogs append index. - purgedSet := makePurgedKeySet(partResult.purged) - b.purgedByLog = buildPurgedByLog(b.volumes.Slots(), purgedSet) + // per-log volume annotation lists before persisting. Three disjoint + // sets — draining-purged, new-kept, and pure-ephemeral — are + // intersected with each order's touched volume slots to produce the + // per-log subsets. Order-indexed so the mapping uses the loop's i, + // not the createdLogs append index. + // + // The three-way split (vs. the earlier two-list encoding that + // duplicated ephemeral tuples across new_volumes and purged_volumes) + // keeps ephemeral-heavy workloads from paying 2× bytes on the log + // payload — see EN-1422. + ephemeralSet, drainingSet := splitPurged(partResult.purged) + newKeptSet := makeNewKeptKeySet(partResult.kept) + + slots := b.volumes.Slots() + b.purgedByLog = buildTouchedByLog(slots, drainingSet) + b.newKeptByLog = buildTouchedByLog(slots, newKeptSet) + b.ephemeralByLog = buildTouchedByLog(slots, ephemeralSet) createdLogs := make([]*commonpb.Log, 0, len(logsOrRefs)) for i, lr := range logsOrRefs { @@ -414,17 +446,29 @@ func (b *WriteSet) Merge(batch *dal.WriteSession, logsOrRefs []*raftcmdpb.Create continue } - if i < len(b.purgedByLog) && len(b.purgedByLog[i]) > 0 { + hasPurged := i < len(b.purgedByLog) && len(b.purgedByLog[i]) > 0 + hasNewKept := i < len(b.newKeptByLog) && len(b.newKeptByLog[i]) > 0 + hasEphemeral := i < len(b.ephemeralByLog) && len(b.ephemeralByLog[i]) > 0 + + if hasPurged || hasNewKept || hasEphemeral { apply := log.GetPayload().GetApply() if apply == nil { - return fmt.Errorf("invariant: order %d produced purged volumes %v but its log payload is not an ApplyLedgerLog (payload=%T)", - i, b.purgedByLog[i], log.GetPayload()) + return fmt.Errorf("invariant: order %d produced volume annotations but its log payload is not an ApplyLedgerLog (payload=%T)", + i, log.GetPayload()) } ledgerLog := apply.GetLog() if ledgerLog == nil { - return fmt.Errorf("invariant: order %d produced purged volumes %v but its ApplyLedgerLog carries no LedgerLog", i, b.purgedByLog[i]) + return fmt.Errorf("invariant: order %d produced volume annotations but its ApplyLedgerLog carries no LedgerLog", i) + } + if hasPurged { + ledgerLog.PurgedVolumes = b.purgedByLog[i] + } + if hasNewKept { + ledgerLog.NewKeptVolumes = b.newKeptByLog[i] + } + if hasEphemeral { + ledgerLog.EphemeralVolumes = b.ephemeralByLog[i] } - ledgerLog.PurgedVolumes = b.purgedByLog[i] } createdLogs = append(createdLogs, log) diff --git a/internal/infra/state/write_set_counters.go b/internal/infra/state/write_set_counters.go deleted file mode 100644 index 65553156d4..0000000000 --- a/internal/infra/state/write_set_counters.go +++ /dev/null @@ -1,141 +0,0 @@ -package state - -import ( - "github.com/formancehq/ledger/v3/internal/domain" - "github.com/formancehq/ledger/v3/internal/infra/attributes" - "github.com/formancehq/ledger/v3/internal/proto/commonpb" - "github.com/formancehq/ledger/v3/internal/proto/raftcmdpb" -) - -// countKeyDeltas counts per-ledger new keys (+1) and deletions (-1) from merge results. -// A new key is identified by Old not being defined (first time in the parent KeyStore). -func countKeyDeltas[K attributes.Key, T any]( - updates []attributes.Update[K, T], - deletions []attributes.Deletion[K], - getLedgerName func(K) string, -) map[string]int64 { - deltas := make(map[string]int64) - - for i := range updates { - if !updates[i].Old.IsDefined() { - deltas[getLedgerName(updates[i].Key)]++ - } - } - - for i := range deletions { - deltas[getLedgerName(deletions[i].Key)]-- - } - - return deltas -} - -// applyDelta safely adds a signed delta to a uint64 counter, clamping at zero on underflow. -func applyDelta(current uint64, delta int64) uint64 { - if delta >= 0 { - return current + uint64(delta) - } - - sub := uint64(-delta) - if sub > current { - return 0 - } - - return current - sub -} - -// isVolumePreloadZero returns true if the volume pair is the zero placeholder -// injected by the preloader for keys that don't exist in Pebble. -// Unlike isVolumeZeroBalance (input == output), this checks input == 0 AND output == 0. -func isVolumePreloadZero(v *raftcmdpb.VolumePair) bool { - if v == nil { - return true - } - - in := v.GetInput() - out := v.GetOutput() - - return (in == nil || (in.GetV0() == 0 && in.GetV1() == 0 && in.GetV2() == 0 && in.GetV3() == 0)) && - (out == nil || (out.GetV0() == 0 && out.GetV1() == 0 && out.GetV2() == 0 && out.GetV3() == 0)) -} - -// countVolumeDeltas counts per-ledger new volume keys. -// A volume is "new" if Old is either undefined or a zero preload placeholder -// (the preloader always seeds missing volumes with {0,0} in the cache). -func countVolumeDeltas(updates []attributes.Update[domain.VolumeKey, *raftcmdpb.VolumePair]) map[string]int64 { - deltas := make(map[string]int64) - - for i := range updates { - old := updates[i].Old - if !old.IsDefined() || isVolumePreloadZero(old.Value()) { - deltas[updates[i].Key.LedgerName]++ - } - } - - return deltas -} - -// updateBoundaryCounters computes attribute key deltas and updates LedgerBoundaries -// for each affected ledger. Must be called before Derived.Boundaries.Merge(). -func (b *WriteSet) updateBoundaryCounters( - volumeUpdates []attributes.Update[domain.VolumeKey, *raftcmdpb.VolumePair], - purgedVolumes []attributes.Update[domain.VolumeKey, *raftcmdpb.VolumePair], - transientVolumes []attributes.Update[domain.VolumeKey, *raftcmdpb.VolumePair], - metadataUpdates []attributes.Update[domain.MetadataKey, *commonpb.MetadataValue], - metadataDeletions []attributes.Deletion[domain.MetadataKey], - referenceUpdates []attributes.Update[domain.TransactionReferenceKey, *commonpb.TransactionReferenceValue], -) { - volumeDeltas := countVolumeDeltas(volumeUpdates) - - // Per-ledger ephemeral/transient counters (monotonic). - ephemeralEvicted := make(map[string]uint64) - transientUsed := make(map[string]uint64) - - // Ephemeral volumes are purged after commit — subtract from volume count. - for i := range purgedVolumes { - ledger := purgedVolumes[i].Key.LedgerName - volumeDeltas[ledger]-- - ephemeralEvicted[ledger]++ - } - // Transient volumes are never persisted — subtract from volume count. - for i := range transientVolumes { - ledger := transientVolumes[i].Key.LedgerName - volumeDeltas[ledger]-- - transientUsed[ledger]++ - } - - metadataDeltas := countKeyDeltas(metadataUpdates, metadataDeletions, func(k domain.MetadataKey) string { return k.LedgerName }) - referenceDeltas := countKeyDeltas(referenceUpdates, nil, func(k domain.TransactionReferenceKey) string { return k.LedgerName }) - - // Collect all affected ledgers. - affected := make(map[string]struct{}) - for ledger := range volumeDeltas { - affected[ledger] = struct{}{} - } - for ledger := range metadataDeltas { - affected[ledger] = struct{}{} - } - for ledger := range referenceDeltas { - affected[ledger] = struct{}{} - } - for ledger := range ephemeralEvicted { - affected[ledger] = struct{}{} - } - for ledger := range transientUsed { - affected[ledger] = struct{}{} - } - - for ledgerName := range affected { - boundariesReader, err := b.Boundaries().Get(domain.LedgerKey{Name: ledgerName}) - if err != nil { - continue - } - - boundaries := boundariesReader.Mutate() - boundaries.VolumeCount = applyDelta(boundaries.GetVolumeCount(), volumeDeltas[ledgerName]) - boundaries.MetadataCount = applyDelta(boundaries.GetMetadataCount(), metadataDeltas[ledgerName]) - boundaries.ReferenceCount = applyDelta(boundaries.GetReferenceCount(), referenceDeltas[ledgerName]) - boundaries.EphemeralEvictedCount += ephemeralEvicted[ledgerName] - boundaries.TransientUsedCount += transientUsed[ledgerName] - b.Boundaries().Put(domain.LedgerKey{Name: ledgerName}, boundaries) - } -} diff --git a/internal/infra/state/write_set_ephemeral_purge.go b/internal/infra/state/write_set_ephemeral_purge.go index 59e14ffe5a..6aad43741b 100644 --- a/internal/infra/state/write_set_ephemeral_purge.go +++ b/internal/infra/state/write_set_ephemeral_purge.go @@ -1,8 +1,6 @@ package state import ( - "sort" - "github.com/formancehq/ledger/v3/internal/domain" "github.com/formancehq/ledger/v3/internal/domain/accounttype" "github.com/formancehq/ledger/v3/internal/infra/attributes" @@ -117,90 +115,6 @@ func (b *WriteSet) partitionVolumes( return result } -// makePurgedKeySet builds a lookup set over the (ledger, account, asset, color) -// of every purged volume entry. Keeping both asset and color dimensions -// matters: a multi-bucket account may have one (asset, color) purged while -// another stays kept — dropping either would over-attribute purged state to -// orders touching the still-kept bucket. -func makePurgedKeySet(purged []attributes.Update[domain.VolumeKey, *raftcmdpb.VolumePair]) map[purgedVolumeKey]struct{} { - if len(purged) == 0 { - return nil - } - set := make(map[purgedVolumeKey]struct{}, len(purged)) - for _, u := range purged { - set[purgedVolumeKey{Ledger: u.Key.LedgerName, Account: u.Key.Account, Asset: u.Key.Asset, Color: u.Key.Color}] = struct{}{} - } - - return set -} - -// purgedVolumeKey is the (ledger, account, asset, color) tuple used by -// makePurgedKeySet and buildPurgedByLog. Both dimensions are kept to avoid -// over-attribution in multi-bucket accounts: two color buckets of the same -// (account, asset) can have different purge fates. -type purgedVolumeKey struct { - Ledger string - Account string - Asset string - Color string -} - -// buildPurgedByLog produces, for each order index, the deduplicated list of -// (account, asset, color) tuples that the order touched and that the proposal -// classified as purged. Indexed by order_index; entries for orders that -// touched nothing purged (or didn't touch volumes at all) are nil. Tuples -// within an entry are sorted (by account, asset, color) to keep the log -// payload deterministic across runs. -func buildPurgedByLog(perOrderVolumeKeys [][]domain.VolumeKey, purged map[purgedVolumeKey]struct{}) [][]*commonpb.TouchedVolume { - if len(perOrderVolumeKeys) == 0 || len(purged) == 0 { - return nil - } - - type accAssetColor struct{ Account, Asset, Color string } - - out := make([][]*commonpb.TouchedVolume, len(perOrderVolumeKeys)) - for i, keys := range perOrderVolumeKeys { - if len(keys) == 0 { - continue - } - - seen := make(map[accAssetColor]struct{}, len(keys)) - for _, k := range keys { - if _, ok := purged[purgedVolumeKey{Ledger: k.LedgerName, Account: k.Account, Asset: k.Asset, Color: k.Color}]; !ok { - continue - } - seen[accAssetColor{Account: k.Account, Asset: k.Asset, Color: k.Color}] = struct{}{} - } - - if len(seen) == 0 { - continue - } - - ordered := make([]accAssetColor, 0, len(seen)) - for k := range seen { - ordered = append(ordered, k) - } - sort.Slice(ordered, func(a, b int) bool { - if ordered[a].Account != ordered[b].Account { - return ordered[a].Account < ordered[b].Account - } - if ordered[a].Asset != ordered[b].Asset { - return ordered[a].Asset < ordered[b].Asset - } - - return ordered[a].Color < ordered[b].Color - }) - - vols := make([]*commonpb.TouchedVolume, len(ordered)) - for j, k := range ordered { - vols[j] = &commonpb.TouchedVolume{Account: k.Account, Asset: k.Asset, Color: k.Color} - } - out[i] = vols - } - - return out -} - // applyEphemeralPurge deletes purged volumes from 0xF1 then zeroes the cache. // Deleting saves storage; the cache is zeroed (rather than deleted) so any // co-batched proposal admitted with CacheHit still sees a populated diff --git a/internal/infra/state/write_set_ephemeral_purge_test.go b/internal/infra/state/write_set_ephemeral_purge_test.go index cab4f1f301..f703ffd6b7 100644 --- a/internal/infra/state/write_set_ephemeral_purge_test.go +++ b/internal/infra/state/write_set_ephemeral_purge_test.go @@ -443,20 +443,20 @@ func TestBuildPurgedByLog_KeepsAssetDimension(t *testing.T) { account := "ephemeral:multi" // purged set contains only (account, USD) — the EUR cell is kept. - purged := map[purgedVolumeKey]struct{}{ + purged := map[volumeSetKey]struct{}{ {Ledger: ledger, Account: account, Asset: "USD"}: {}, } - // Order 0 touches (account, EUR) — must NOT appear in purgedByLog. - // Order 1 touches (account, USD) — must appear in purgedByLog[1]. + // Order 0 touches (account, EUR) — must NOT appear in the output. + // Order 1 touches (account, USD) — must appear in out[1]. perOrderVolumeKeys := [][]domain.VolumeKey{ {{AccountKey: domain.AccountKey{LedgerName: ledger, Account: account}, Asset: "EUR"}}, {{AccountKey: domain.AccountKey{LedgerName: ledger, Account: account}, Asset: "USD"}}, } - out := buildPurgedByLog(perOrderVolumeKeys, purged) + out := buildTouchedByLog(perOrderVolumeKeys, purged) require.Len(t, out, 2) - require.Empty(t, out[0], "order touching only kept assets must not be flagged purged") + require.Empty(t, out[0], "order touching only kept assets must not appear in the touched set") require.Len(t, out[1], 1) require.Equal(t, account, out[1][0].GetAccount()) require.Equal(t, "USD", out[1][0].GetAsset()) diff --git a/internal/infra/state/write_set_new_volumes.go b/internal/infra/state/write_set_new_volumes.go new file mode 100644 index 0000000000..e898fc9cba --- /dev/null +++ b/internal/infra/state/write_set_new_volumes.go @@ -0,0 +1,160 @@ +package state + +import ( + "sort" + + "github.com/formancehq/ledger/v3/internal/domain" + "github.com/formancehq/ledger/v3/internal/infra/attributes" + "github.com/formancehq/ledger/v3/internal/proto/commonpb" + "github.com/formancehq/ledger/v3/internal/proto/raftcmdpb" +) + +// isVolumePreloadZero returns true if the volume pair is the zero placeholder +// injected by the preloader for keys that don't exist in Pebble. Unlike +// isVolumeZeroBalance (input == output), this checks input == 0 AND output == 0 +// — the exact seed the preloader emits so admission's `Needs` can be planned +// deterministically. +func isVolumePreloadZero(v *raftcmdpb.VolumePair) bool { + if v == nil { + return true + } + + in := v.GetInput() + out := v.GetOutput() + + return (in == nil || (in.GetV0() == 0 && in.GetV1() == 0 && in.GetV2() == 0 && in.GetV3() == 0)) && + (out == nil || (out.GetV0() == 0 && out.GetV1() == 0 && out.GetV2() == 0 && out.GetV3() == 0)) +} + +// isNewVolumeUpdate reports whether a volume update represents a +// first-time write to that (account, asset) key. "New" is defined by the +// preloaded prior value: absent or the zero placeholder → new; a defined +// non-zero prior value → pre-existing. +func isNewVolumeUpdate(u attributes.Update[domain.VolumeKey, *raftcmdpb.VolumePair]) bool { + if !u.Old.IsDefined() { + return true + } + + return isVolumePreloadZero(u.Old.Value()) +} + +// volumeSetKey is the (ledger, account, asset, color) tuple used by the per-log +// intersection helpers below. Both asset and color dimensions are kept: a +// multi-bucket account may split across categories per (asset, color) — one +// (asset, color) bucket may be purged/new while another stays kept, so dropping +// either dimension would over-attribute a category to orders touching a +// still-kept bucket. +type volumeSetKey struct { + Ledger string + Account string + Asset string + Color string +} + +// makeNewKeptKeySet builds the set of (ledger, account, asset) tuples that +// were newly created AND survived past commit — i.e. persistent-new volumes +// that are NOT ephemeral. Consumed by buildNewKeptByLog. +func makeNewKeptKeySet(kept []attributes.Update[domain.VolumeKey, *raftcmdpb.VolumePair]) map[volumeSetKey]struct{} { + set := make(map[volumeSetKey]struct{}) + + for i := range kept { + if !isNewVolumeUpdate(kept[i]) { + continue + } + + set[volumeSetKey{ + Ledger: kept[i].Key.LedgerName, + Account: kept[i].Key.Account, + Asset: kept[i].Key.Asset, + Color: kept[i].Key.Color, + }] = struct{}{} + } + + return set +} + +// splitPurged partitions partResult.purged into pure-ephemeral (was zero, +// briefly touched, is zero at commit) and draining (was non-zero, back to +// zero). The two sets are disjoint by definition — a purged update either +// had a prior balance or did not. +func splitPurged(purged []attributes.Update[domain.VolumeKey, *raftcmdpb.VolumePair]) (ephemeral, draining map[volumeSetKey]struct{}) { + ephemeral = make(map[volumeSetKey]struct{}) + draining = make(map[volumeSetKey]struct{}) + + for i := range purged { + key := volumeSetKey{ + Ledger: purged[i].Key.LedgerName, + Account: purged[i].Key.Account, + Asset: purged[i].Key.Asset, + Color: purged[i].Key.Color, + } + + if isNewVolumeUpdate(purged[i]) { + ephemeral[key] = struct{}{} + } else { + draining[key] = struct{}{} + } + } + + return ephemeral, draining +} + +// buildTouchedByLog produces, for each order index, the deduplicated list of +// (account, asset, color) tuples the order touched that fall in the given set. +// Indexed by order_index; entries for orders with no matching keys are nil. +// Tuples within an entry are sorted (by account, asset, then color) so the log +// payload is deterministic across nodes and runs. +// +// This is the generalisation of buildPurgedByLog / buildNewByLog into one +// helper — the caller supplies the intersection set (draining, ephemeral, +// or new-kept). The color dimension is preserved so multi-bucket accounts are +// attributed per (asset, color) bucket rather than collapsed onto the asset. +func buildTouchedByLog(perOrderVolumeKeys [][]domain.VolumeKey, set map[volumeSetKey]struct{}) [][]*commonpb.TouchedVolume { + if len(perOrderVolumeKeys) == 0 || len(set) == 0 { + return nil + } + + type accAssetColor struct{ Account, Asset, Color string } + + out := make([][]*commonpb.TouchedVolume, len(perOrderVolumeKeys)) + for i, keys := range perOrderVolumeKeys { + if len(keys) == 0 { + continue + } + + seen := make(map[accAssetColor]struct{}, len(keys)) + for _, k := range keys { + if _, ok := set[volumeSetKey{Ledger: k.LedgerName, Account: k.Account, Asset: k.Asset, Color: k.Color}]; !ok { + continue + } + seen[accAssetColor{Account: k.Account, Asset: k.Asset, Color: k.Color}] = struct{}{} + } + + if len(seen) == 0 { + continue + } + + ordered := make([]accAssetColor, 0, len(seen)) + for k := range seen { + ordered = append(ordered, k) + } + sort.Slice(ordered, func(a, b int) bool { + if ordered[a].Account != ordered[b].Account { + return ordered[a].Account < ordered[b].Account + } + if ordered[a].Asset != ordered[b].Asset { + return ordered[a].Asset < ordered[b].Asset + } + + return ordered[a].Color < ordered[b].Color + }) + + vols := make([]*commonpb.TouchedVolume, len(ordered)) + for j, k := range ordered { + vols[j] = &commonpb.TouchedVolume{Account: k.Account, Asset: k.Asset, Color: k.Color} + } + out[i] = vols + } + + return out +} diff --git a/internal/proto/commonpb/common.pb.go b/internal/proto/commonpb/common.pb.go index 69dd478fef..a97bde0776 100644 --- a/internal/proto/commonpb/common.pb.go +++ b/internal/proto/commonpb/common.pb.go @@ -4774,6 +4774,61 @@ func (x *DeletedNumscriptLog) GetLedger() string { return "" } +// TemplateUsage tracks per-template invocation usage. Persisted as a +// projection of the audit log by the usagebuilder subsystem — NOT part of +// the FSM authoritative state. Rebuildable from cursor=0 on demand. +type TemplateUsage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Count uint64 `protobuf:"fixed64,1,opt,name=count,proto3" json:"count,omitempty"` + LastUsed *Timestamp `protobuf:"bytes,2,opt,name=last_used,json=lastUsed,proto3" json:"last_used,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TemplateUsage) Reset() { + *x = TemplateUsage{} + mi := &file_common_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TemplateUsage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TemplateUsage) ProtoMessage() {} + +func (x *TemplateUsage) ProtoReflect() protoreflect.Message { + mi := &file_common_proto_msgTypes[49] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TemplateUsage.ProtoReflect.Descriptor instead. +func (*TemplateUsage) Descriptor() ([]byte, []int) { + return file_common_proto_rawDescGZIP(), []int{49} +} + +func (x *TemplateUsage) GetCount() uint64 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *TemplateUsage) GetLastUsed() *Timestamp { + if x != nil { + return x.LastUsed + } + return nil +} + // SetQueryCheckpointScheduleLog records a query checkpoint schedule change. type SetQueryCheckpointScheduleLog struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -4784,7 +4839,7 @@ type SetQueryCheckpointScheduleLog struct { func (x *SetQueryCheckpointScheduleLog) Reset() { *x = SetQueryCheckpointScheduleLog{} - mi := &file_common_proto_msgTypes[49] + mi := &file_common_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4796,7 +4851,7 @@ func (x *SetQueryCheckpointScheduleLog) String() string { func (*SetQueryCheckpointScheduleLog) ProtoMessage() {} func (x *SetQueryCheckpointScheduleLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[49] + mi := &file_common_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4809,7 +4864,7 @@ func (x *SetQueryCheckpointScheduleLog) ProtoReflect() protoreflect.Message { // Deprecated: Use SetQueryCheckpointScheduleLog.ProtoReflect.Descriptor instead. func (*SetQueryCheckpointScheduleLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{49} + return file_common_proto_rawDescGZIP(), []int{50} } func (x *SetQueryCheckpointScheduleLog) GetCron() string { @@ -4828,7 +4883,7 @@ type DeletedQueryCheckpointScheduleLog struct { func (x *DeletedQueryCheckpointScheduleLog) Reset() { *x = DeletedQueryCheckpointScheduleLog{} - mi := &file_common_proto_msgTypes[50] + mi := &file_common_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4840,7 +4895,7 @@ func (x *DeletedQueryCheckpointScheduleLog) String() string { func (*DeletedQueryCheckpointScheduleLog) ProtoMessage() {} func (x *DeletedQueryCheckpointScheduleLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[50] + mi := &file_common_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4853,7 +4908,7 @@ func (x *DeletedQueryCheckpointScheduleLog) ProtoReflect() protoreflect.Message // Deprecated: Use DeletedQueryCheckpointScheduleLog.ProtoReflect.Descriptor instead. func (*DeletedQueryCheckpointScheduleLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{50} + return file_common_proto_rawDescGZIP(), []int{51} } // CreatedQueryCheckpointLog records a query checkpoint being created. @@ -4867,7 +4922,7 @@ type CreatedQueryCheckpointLog struct { func (x *CreatedQueryCheckpointLog) Reset() { *x = CreatedQueryCheckpointLog{} - mi := &file_common_proto_msgTypes[51] + mi := &file_common_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4879,7 +4934,7 @@ func (x *CreatedQueryCheckpointLog) String() string { func (*CreatedQueryCheckpointLog) ProtoMessage() {} func (x *CreatedQueryCheckpointLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[51] + mi := &file_common_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4892,7 +4947,7 @@ func (x *CreatedQueryCheckpointLog) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatedQueryCheckpointLog.ProtoReflect.Descriptor instead. func (*CreatedQueryCheckpointLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{51} + return file_common_proto_rawDescGZIP(), []int{52} } func (x *CreatedQueryCheckpointLog) GetCheckpointId() uint64 { @@ -4919,7 +4974,7 @@ type DeletedQueryCheckpointLog struct { func (x *DeletedQueryCheckpointLog) Reset() { *x = DeletedQueryCheckpointLog{} - mi := &file_common_proto_msgTypes[52] + mi := &file_common_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4931,7 +4986,7 @@ func (x *DeletedQueryCheckpointLog) String() string { func (*DeletedQueryCheckpointLog) ProtoMessage() {} func (x *DeletedQueryCheckpointLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[52] + mi := &file_common_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4944,7 +4999,7 @@ func (x *DeletedQueryCheckpointLog) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletedQueryCheckpointLog.ProtoReflect.Descriptor instead. func (*DeletedQueryCheckpointLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{52} + return file_common_proto_rawDescGZIP(), []int{53} } func (x *DeletedQueryCheckpointLog) GetCheckpointId() uint64 { @@ -4976,7 +5031,7 @@ type SinkConfig struct { func (x *SinkConfig) Reset() { *x = SinkConfig{} - mi := &file_common_proto_msgTypes[53] + mi := &file_common_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4988,7 +5043,7 @@ func (x *SinkConfig) String() string { func (*SinkConfig) ProtoMessage() {} func (x *SinkConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[53] + mi := &file_common_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5001,7 +5056,7 @@ func (x *SinkConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use SinkConfig.ProtoReflect.Descriptor instead. func (*SinkConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{53} + return file_common_proto_rawDescGZIP(), []int{54} } func (x *SinkConfig) GetName() string { @@ -5137,7 +5192,7 @@ type SinkStatus struct { func (x *SinkStatus) Reset() { *x = SinkStatus{} - mi := &file_common_proto_msgTypes[54] + mi := &file_common_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5149,7 +5204,7 @@ func (x *SinkStatus) String() string { func (*SinkStatus) ProtoMessage() {} func (x *SinkStatus) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[54] + mi := &file_common_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5162,7 +5217,7 @@ func (x *SinkStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use SinkStatus.ProtoReflect.Descriptor instead. func (*SinkStatus) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{54} + return file_common_proto_rawDescGZIP(), []int{55} } func (x *SinkStatus) GetSinkName() string { @@ -5197,7 +5252,7 @@ type SinkError struct { func (x *SinkError) Reset() { *x = SinkError{} - mi := &file_common_proto_msgTypes[55] + mi := &file_common_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5209,7 +5264,7 @@ func (x *SinkError) String() string { func (*SinkError) ProtoMessage() {} func (x *SinkError) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[55] + mi := &file_common_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5222,7 +5277,7 @@ func (x *SinkError) ProtoReflect() protoreflect.Message { // Deprecated: Use SinkError.ProtoReflect.Descriptor instead. func (*SinkError) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{55} + return file_common_proto_rawDescGZIP(), []int{56} } func (x *SinkError) GetMessage() string { @@ -5250,7 +5305,7 @@ type NatsSinkConfig struct { func (x *NatsSinkConfig) Reset() { *x = NatsSinkConfig{} - mi := &file_common_proto_msgTypes[56] + mi := &file_common_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5262,7 +5317,7 @@ func (x *NatsSinkConfig) String() string { func (*NatsSinkConfig) ProtoMessage() {} func (x *NatsSinkConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[56] + mi := &file_common_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5275,7 +5330,7 @@ func (x *NatsSinkConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use NatsSinkConfig.ProtoReflect.Descriptor instead. func (*NatsSinkConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{56} + return file_common_proto_rawDescGZIP(), []int{57} } func (x *NatsSinkConfig) GetUrl() string { @@ -5303,7 +5358,7 @@ type ClickHouseSinkConfig struct { func (x *ClickHouseSinkConfig) Reset() { *x = ClickHouseSinkConfig{} - mi := &file_common_proto_msgTypes[57] + mi := &file_common_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5315,7 +5370,7 @@ func (x *ClickHouseSinkConfig) String() string { func (*ClickHouseSinkConfig) ProtoMessage() {} func (x *ClickHouseSinkConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[57] + mi := &file_common_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5328,7 +5383,7 @@ func (x *ClickHouseSinkConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use ClickHouseSinkConfig.ProtoReflect.Descriptor instead. func (*ClickHouseSinkConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{57} + return file_common_proto_rawDescGZIP(), []int{58} } func (x *ClickHouseSinkConfig) GetDsn() string { @@ -5360,7 +5415,7 @@ type KafkaSinkConfig struct { func (x *KafkaSinkConfig) Reset() { *x = KafkaSinkConfig{} - mi := &file_common_proto_msgTypes[58] + mi := &file_common_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5372,7 +5427,7 @@ func (x *KafkaSinkConfig) String() string { func (*KafkaSinkConfig) ProtoMessage() {} func (x *KafkaSinkConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[58] + mi := &file_common_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5385,7 +5440,7 @@ func (x *KafkaSinkConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use KafkaSinkConfig.ProtoReflect.Descriptor instead. func (*KafkaSinkConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{58} + return file_common_proto_rawDescGZIP(), []int{59} } func (x *KafkaSinkConfig) GetBrokers() []string { @@ -5441,7 +5496,7 @@ type HttpSinkConfig struct { func (x *HttpSinkConfig) Reset() { *x = HttpSinkConfig{} - mi := &file_common_proto_msgTypes[59] + mi := &file_common_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5453,7 +5508,7 @@ func (x *HttpSinkConfig) String() string { func (*HttpSinkConfig) ProtoMessage() {} func (x *HttpSinkConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[59] + mi := &file_common_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5466,7 +5521,7 @@ func (x *HttpSinkConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use HttpSinkConfig.ProtoReflect.Descriptor instead. func (*HttpSinkConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{59} + return file_common_proto_rawDescGZIP(), []int{60} } func (x *HttpSinkConfig) GetEndpoint() string { @@ -5504,7 +5559,7 @@ type DatabricksSinkConfig struct { func (x *DatabricksSinkConfig) Reset() { *x = DatabricksSinkConfig{} - mi := &file_common_proto_msgTypes[60] + mi := &file_common_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5516,7 +5571,7 @@ func (x *DatabricksSinkConfig) String() string { func (*DatabricksSinkConfig) ProtoMessage() {} func (x *DatabricksSinkConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[60] + mi := &file_common_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5529,7 +5584,7 @@ func (x *DatabricksSinkConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use DatabricksSinkConfig.ProtoReflect.Descriptor instead. func (*DatabricksSinkConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{60} + return file_common_proto_rawDescGZIP(), []int{61} } func (x *DatabricksSinkConfig) GetServerHostname() string { @@ -5626,7 +5681,7 @@ type DatabricksOAuthM2M struct { func (x *DatabricksOAuthM2M) Reset() { *x = DatabricksOAuthM2M{} - mi := &file_common_proto_msgTypes[61] + mi := &file_common_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5638,7 +5693,7 @@ func (x *DatabricksOAuthM2M) String() string { func (*DatabricksOAuthM2M) ProtoMessage() {} func (x *DatabricksOAuthM2M) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[61] + mi := &file_common_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5651,7 +5706,7 @@ func (x *DatabricksOAuthM2M) ProtoReflect() protoreflect.Message { // Deprecated: Use DatabricksOAuthM2M.ProtoReflect.Descriptor instead. func (*DatabricksOAuthM2M) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{61} + return file_common_proto_rawDescGZIP(), []int{62} } func (x *DatabricksOAuthM2M) GetClientId() string { @@ -5687,7 +5742,7 @@ type CreatedLedgerLog struct { func (x *CreatedLedgerLog) Reset() { *x = CreatedLedgerLog{} - mi := &file_common_proto_msgTypes[62] + mi := &file_common_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5699,7 +5754,7 @@ func (x *CreatedLedgerLog) String() string { func (*CreatedLedgerLog) ProtoMessage() {} func (x *CreatedLedgerLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[62] + mi := &file_common_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5712,7 +5767,7 @@ func (x *CreatedLedgerLog) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatedLedgerLog.ProtoReflect.Descriptor instead. func (*CreatedLedgerLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{62} + return file_common_proto_rawDescGZIP(), []int{63} } func (x *CreatedLedgerLog) GetName() string { @@ -5781,7 +5836,7 @@ type DeletedLedgerLog struct { func (x *DeletedLedgerLog) Reset() { *x = DeletedLedgerLog{} - mi := &file_common_proto_msgTypes[63] + mi := &file_common_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5793,7 +5848,7 @@ func (x *DeletedLedgerLog) String() string { func (*DeletedLedgerLog) ProtoMessage() {} func (x *DeletedLedgerLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[63] + mi := &file_common_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5806,7 +5861,7 @@ func (x *DeletedLedgerLog) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletedLedgerLog.ProtoReflect.Descriptor instead. func (*DeletedLedgerLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{63} + return file_common_proto_rawDescGZIP(), []int{64} } func (x *DeletedLedgerLog) GetName() string { @@ -5833,7 +5888,7 @@ type ApplyLedgerLog struct { func (x *ApplyLedgerLog) Reset() { *x = ApplyLedgerLog{} - mi := &file_common_proto_msgTypes[64] + mi := &file_common_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5845,7 +5900,7 @@ func (x *ApplyLedgerLog) String() string { func (*ApplyLedgerLog) ProtoMessage() {} func (x *ApplyLedgerLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[64] + mi := &file_common_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5858,7 +5913,7 @@ func (x *ApplyLedgerLog) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyLedgerLog.ProtoReflect.Descriptor instead. func (*ApplyLedgerLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{64} + return file_common_proto_rawDescGZIP(), []int{65} } func (x *ApplyLedgerLog) GetLedgerName() string { @@ -5880,23 +5935,38 @@ type LedgerLog struct { Data *LedgerLogPayload `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` Date *Timestamp `protobuf:"bytes,2,opt,name=date,proto3" json:"date,omitempty"` Id uint64 `protobuf:"fixed64,3,opt,name=id,proto3" json:"id,omitempty"` - // Volumes (account+asset) whose ephemeral state was purged (zero balance) - // by THIS log specifically. Subset of the proposal's purged universe — - // only volumes touched by the order that produced this log. Empty when - // the order did not contribute to any ephemeral purge. The index builder - // uses this to skip account->transaction mappings for the corresponding - // (account, asset) tuples without reading the audit zone. Carrying the - // asset dimension matters: a multi-asset account may have one asset - // purged while another stays kept; tagging the account as a whole would - // over-skip mappings for transactions that touched the kept asset. + // Volumes (account+asset) DRAINED to zero by THIS log — the entry had a + // pre-existing non-zero balance in Pebble and this log brought it back to + // zero, causing the volume to be evicted from the attribute store at + // commit. Purged is DISJOINT from ephemeral_volumes and new_kept_volumes. + // The index builder skips account->transaction mappings for + // purged ∪ ephemeral (both are evicted from Pebble). The usagebuilder + // subtracts len(purged_volumes) from VolumeCount — a draining eviction + // decreases the live cardinality by one. PurgedVolumes []*TouchedVolume `protobuf:"bytes,4,rep,name=purged_volumes,json=purgedVolumes,proto3" json:"purged_volumes,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Volumes (account+asset) whose PERSISTENT entry was newly created by + // THIS log AND SURVIVED past commit. New + kept — disjoint from + // purged_volumes and ephemeral_volumes. The usagebuilder increments + // VolumeCount by len(new_kept_volumes) — a newly-persisted key raises + // the live cardinality by one. + NewKeptVolumes []*TouchedVolume `protobuf:"bytes,5,rep,name=new_kept_volumes,json=newKeptVolumes,proto3" json:"new_kept_volumes,omitempty"` + // Volumes (account+asset) that were both newly created AND purged by + // THIS log — pure ephemeral. Written to Pebble briefly then evicted at + // commit. Contributes +0 to VolumeCount (was zero, is zero after commit) + // and is tracked separately so: + // - the index builder can skip acct->tx mappings for them (via + // purged_volumes ∪ ephemeral_volumes); + // - the log payload does not duplicate ephemeral tuples in two lists + // (previous encoding carried them in both purged_volumes AND + // new_volumes, doubling bytes on ephemeral-heavy workloads). + EphemeralVolumes []*TouchedVolume `protobuf:"bytes,6,rep,name=ephemeral_volumes,json=ephemeralVolumes,proto3" json:"ephemeral_volumes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LedgerLog) Reset() { *x = LedgerLog{} - mi := &file_common_proto_msgTypes[65] + mi := &file_common_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5908,7 +5978,7 @@ func (x *LedgerLog) String() string { func (*LedgerLog) ProtoMessage() {} func (x *LedgerLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[65] + mi := &file_common_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5921,7 +5991,7 @@ func (x *LedgerLog) ProtoReflect() protoreflect.Message { // Deprecated: Use LedgerLog.ProtoReflect.Descriptor instead. func (*LedgerLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{65} + return file_common_proto_rawDescGZIP(), []int{66} } func (x *LedgerLog) GetData() *LedgerLogPayload { @@ -5952,6 +6022,20 @@ func (x *LedgerLog) GetPurgedVolumes() []*TouchedVolume { return nil } +func (x *LedgerLog) GetNewKeptVolumes() []*TouchedVolume { + if x != nil { + return x.NewKeptVolumes + } + return nil +} + +func (x *LedgerLog) GetEphemeralVolumes() []*TouchedVolume { + if x != nil { + return x.EphemeralVolumes + } + return nil +} + // TouchedVolume identifies a (ledger-local) volume cell — an account paired // with an asset and a color. Used in transient/purged volume exclusion sets // where the indexer must distinguish per-(asset, color) state inside a @@ -5968,7 +6052,7 @@ type TouchedVolume struct { func (x *TouchedVolume) Reset() { *x = TouchedVolume{} - mi := &file_common_proto_msgTypes[66] + mi := &file_common_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5980,7 +6064,7 @@ func (x *TouchedVolume) String() string { func (*TouchedVolume) ProtoMessage() {} func (x *TouchedVolume) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[66] + mi := &file_common_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5993,7 +6077,7 @@ func (x *TouchedVolume) ProtoReflect() protoreflect.Message { // Deprecated: Use TouchedVolume.ProtoReflect.Descriptor instead. func (*TouchedVolume) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{66} + return file_common_proto_rawDescGZIP(), []int{67} } func (x *TouchedVolume) GetAccount() string { @@ -6041,7 +6125,7 @@ type LedgerLogPayload struct { func (x *LedgerLogPayload) Reset() { *x = LedgerLogPayload{} - mi := &file_common_proto_msgTypes[67] + mi := &file_common_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6053,7 +6137,7 @@ func (x *LedgerLogPayload) String() string { func (*LedgerLogPayload) ProtoMessage() {} func (x *LedgerLogPayload) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[67] + mi := &file_common_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6066,7 +6150,7 @@ func (x *LedgerLogPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use LedgerLogPayload.ProtoReflect.Descriptor instead. func (*LedgerLogPayload) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{67} + return file_common_proto_rawDescGZIP(), []int{68} } func (x *LedgerLogPayload) GetPayload() isLedgerLogPayload_Payload { @@ -6299,7 +6383,7 @@ type OrderSkippedLog struct { func (x *OrderSkippedLog) Reset() { *x = OrderSkippedLog{} - mi := &file_common_proto_msgTypes[68] + mi := &file_common_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6311,7 +6395,7 @@ func (x *OrderSkippedLog) String() string { func (*OrderSkippedLog) ProtoMessage() {} func (x *OrderSkippedLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[68] + mi := &file_common_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6324,7 +6408,7 @@ func (x *OrderSkippedLog) ProtoReflect() protoreflect.Message { // Deprecated: Use OrderSkippedLog.ProtoReflect.Descriptor instead. func (*OrderSkippedLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{68} + return file_common_proto_rawDescGZIP(), []int{69} } func (x *OrderSkippedLog) GetReason() ErrorReason { @@ -6351,7 +6435,7 @@ type CreatedIndexLog struct { func (x *CreatedIndexLog) Reset() { *x = CreatedIndexLog{} - mi := &file_common_proto_msgTypes[69] + mi := &file_common_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6363,7 +6447,7 @@ func (x *CreatedIndexLog) String() string { func (*CreatedIndexLog) ProtoMessage() {} func (x *CreatedIndexLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[69] + mi := &file_common_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6376,7 +6460,7 @@ func (x *CreatedIndexLog) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatedIndexLog.ProtoReflect.Descriptor instead. func (*CreatedIndexLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{69} + return file_common_proto_rawDescGZIP(), []int{70} } func (x *CreatedIndexLog) GetId() *IndexID { @@ -6396,7 +6480,7 @@ type DroppedIndexLog struct { func (x *DroppedIndexLog) Reset() { *x = DroppedIndexLog{} - mi := &file_common_proto_msgTypes[70] + mi := &file_common_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6408,7 +6492,7 @@ func (x *DroppedIndexLog) String() string { func (*DroppedIndexLog) ProtoMessage() {} func (x *DroppedIndexLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[70] + mi := &file_common_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6421,7 +6505,7 @@ func (x *DroppedIndexLog) ProtoReflect() protoreflect.Message { // Deprecated: Use DroppedIndexLog.ProtoReflect.Descriptor instead. func (*DroppedIndexLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{70} + return file_common_proto_rawDescGZIP(), []int{71} } func (x *DroppedIndexLog) GetId() *IndexID { @@ -6440,7 +6524,7 @@ type FilledGapLog struct { func (x *FilledGapLog) Reset() { *x = FilledGapLog{} - mi := &file_common_proto_msgTypes[71] + mi := &file_common_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6452,7 +6536,7 @@ func (x *FilledGapLog) String() string { func (*FilledGapLog) ProtoMessage() {} func (x *FilledGapLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[71] + mi := &file_common_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6465,7 +6549,7 @@ func (x *FilledGapLog) ProtoReflect() protoreflect.Message { // Deprecated: Use FilledGapLog.ProtoReflect.Descriptor instead. func (*FilledGapLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{71} + return file_common_proto_rawDescGZIP(), []int{72} } func (x *FilledGapLog) GetOriginalId() uint64 { @@ -6487,7 +6571,7 @@ type CreatedTransaction struct { func (x *CreatedTransaction) Reset() { *x = CreatedTransaction{} - mi := &file_common_proto_msgTypes[72] + mi := &file_common_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6499,7 +6583,7 @@ func (x *CreatedTransaction) String() string { func (*CreatedTransaction) ProtoMessage() {} func (x *CreatedTransaction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[72] + mi := &file_common_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6512,7 +6596,7 @@ func (x *CreatedTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatedTransaction.ProtoReflect.Descriptor instead. func (*CreatedTransaction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{72} + return file_common_proto_rawDescGZIP(), []int{73} } func (x *CreatedTransaction) GetTransaction() *Transaction { @@ -6554,7 +6638,7 @@ type RevertedTransaction struct { func (x *RevertedTransaction) Reset() { *x = RevertedTransaction{} - mi := &file_common_proto_msgTypes[73] + mi := &file_common_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6566,7 +6650,7 @@ func (x *RevertedTransaction) String() string { func (*RevertedTransaction) ProtoMessage() {} func (x *RevertedTransaction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[73] + mi := &file_common_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6579,7 +6663,7 @@ func (x *RevertedTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertedTransaction.ProtoReflect.Descriptor instead. func (*RevertedTransaction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{73} + return file_common_proto_rawDescGZIP(), []int{74} } func (x *RevertedTransaction) GetRevertedTransactionId() uint64 { @@ -6613,7 +6697,7 @@ type SavedMetadata struct { func (x *SavedMetadata) Reset() { *x = SavedMetadata{} - mi := &file_common_proto_msgTypes[74] + mi := &file_common_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6625,7 +6709,7 @@ func (x *SavedMetadata) String() string { func (*SavedMetadata) ProtoMessage() {} func (x *SavedMetadata) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[74] + mi := &file_common_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6638,7 +6722,7 @@ func (x *SavedMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use SavedMetadata.ProtoReflect.Descriptor instead. func (*SavedMetadata) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{74} + return file_common_proto_rawDescGZIP(), []int{75} } func (x *SavedMetadata) GetTarget() *Target { @@ -6665,7 +6749,7 @@ type DeletedMetadata struct { func (x *DeletedMetadata) Reset() { *x = DeletedMetadata{} - mi := &file_common_proto_msgTypes[75] + mi := &file_common_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6677,7 +6761,7 @@ func (x *DeletedMetadata) String() string { func (*DeletedMetadata) ProtoMessage() {} func (x *DeletedMetadata) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[75] + mi := &file_common_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6690,7 +6774,7 @@ func (x *DeletedMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletedMetadata.ProtoReflect.Descriptor instead. func (*DeletedMetadata) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{75} + return file_common_proto_rawDescGZIP(), []int{76} } func (x *DeletedMetadata) GetTarget() *Target { @@ -6719,7 +6803,7 @@ type SetMetadataFieldTypeLog struct { func (x *SetMetadataFieldTypeLog) Reset() { *x = SetMetadataFieldTypeLog{} - mi := &file_common_proto_msgTypes[76] + mi := &file_common_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6731,7 +6815,7 @@ func (x *SetMetadataFieldTypeLog) String() string { func (*SetMetadataFieldTypeLog) ProtoMessage() {} func (x *SetMetadataFieldTypeLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[76] + mi := &file_common_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6744,7 +6828,7 @@ func (x *SetMetadataFieldTypeLog) ProtoReflect() protoreflect.Message { // Deprecated: Use SetMetadataFieldTypeLog.ProtoReflect.Descriptor instead. func (*SetMetadataFieldTypeLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{76} + return file_common_proto_rawDescGZIP(), []int{77} } func (x *SetMetadataFieldTypeLog) GetTargetType() TargetType { @@ -6782,7 +6866,7 @@ type RemovedMetadataFieldTypeLog struct { func (x *RemovedMetadataFieldTypeLog) Reset() { *x = RemovedMetadataFieldTypeLog{} - mi := &file_common_proto_msgTypes[77] + mi := &file_common_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6794,7 +6878,7 @@ func (x *RemovedMetadataFieldTypeLog) String() string { func (*RemovedMetadataFieldTypeLog) ProtoMessage() {} func (x *RemovedMetadataFieldTypeLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[77] + mi := &file_common_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6807,7 +6891,7 @@ func (x *RemovedMetadataFieldTypeLog) ProtoReflect() protoreflect.Message { // Deprecated: Use RemovedMetadataFieldTypeLog.ProtoReflect.Descriptor instead. func (*RemovedMetadataFieldTypeLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{77} + return file_common_proto_rawDescGZIP(), []int{78} } func (x *RemovedMetadataFieldTypeLog) GetTargetType() TargetType { @@ -6850,7 +6934,7 @@ type Chapter struct { func (x *Chapter) Reset() { *x = Chapter{} - mi := &file_common_proto_msgTypes[78] + mi := &file_common_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6862,7 +6946,7 @@ func (x *Chapter) String() string { func (*Chapter) ProtoMessage() {} func (x *Chapter) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[78] + mi := &file_common_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6875,7 +6959,7 @@ func (x *Chapter) ProtoReflect() protoreflect.Message { // Deprecated: Use Chapter.ProtoReflect.Descriptor instead. func (*Chapter) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{78} + return file_common_proto_rawDescGZIP(), []int{79} } func (x *Chapter) GetId() uint64 { @@ -6965,7 +7049,7 @@ type ClosedChapterLog struct { func (x *ClosedChapterLog) Reset() { *x = ClosedChapterLog{} - mi := &file_common_proto_msgTypes[79] + mi := &file_common_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6977,7 +7061,7 @@ func (x *ClosedChapterLog) String() string { func (*ClosedChapterLog) ProtoMessage() {} func (x *ClosedChapterLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[79] + mi := &file_common_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6990,7 +7074,7 @@ func (x *ClosedChapterLog) ProtoReflect() protoreflect.Message { // Deprecated: Use ClosedChapterLog.ProtoReflect.Descriptor instead. func (*ClosedChapterLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{79} + return file_common_proto_rawDescGZIP(), []int{80} } func (x *ClosedChapterLog) GetClosedChapter() *Chapter { @@ -7016,7 +7100,7 @@ type SealedChapterLog struct { func (x *SealedChapterLog) Reset() { *x = SealedChapterLog{} - mi := &file_common_proto_msgTypes[80] + mi := &file_common_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7028,7 +7112,7 @@ func (x *SealedChapterLog) String() string { func (*SealedChapterLog) ProtoMessage() {} func (x *SealedChapterLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[80] + mi := &file_common_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7041,7 +7125,7 @@ func (x *SealedChapterLog) ProtoReflect() protoreflect.Message { // Deprecated: Use SealedChapterLog.ProtoReflect.Descriptor instead. func (*SealedChapterLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{80} + return file_common_proto_rawDescGZIP(), []int{81} } func (x *SealedChapterLog) GetChapter() *Chapter { @@ -7060,7 +7144,7 @@ type ArchivedChapterLog struct { func (x *ArchivedChapterLog) Reset() { *x = ArchivedChapterLog{} - mi := &file_common_proto_msgTypes[81] + mi := &file_common_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7072,7 +7156,7 @@ func (x *ArchivedChapterLog) String() string { func (*ArchivedChapterLog) ProtoMessage() {} func (x *ArchivedChapterLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[81] + mi := &file_common_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7085,7 +7169,7 @@ func (x *ArchivedChapterLog) ProtoReflect() protoreflect.Message { // Deprecated: Use ArchivedChapterLog.ProtoReflect.Descriptor instead. func (*ArchivedChapterLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{81} + return file_common_proto_rawDescGZIP(), []int{82} } func (x *ArchivedChapterLog) GetChapter() *Chapter { @@ -7104,7 +7188,7 @@ type ConfirmedArchiveChapterLog struct { func (x *ConfirmedArchiveChapterLog) Reset() { *x = ConfirmedArchiveChapterLog{} - mi := &file_common_proto_msgTypes[82] + mi := &file_common_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7116,7 +7200,7 @@ func (x *ConfirmedArchiveChapterLog) String() string { func (*ConfirmedArchiveChapterLog) ProtoMessage() {} func (x *ConfirmedArchiveChapterLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[82] + mi := &file_common_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7129,7 +7213,7 @@ func (x *ConfirmedArchiveChapterLog) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfirmedArchiveChapterLog.ProtoReflect.Descriptor instead. func (*ConfirmedArchiveChapterLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{82} + return file_common_proto_rawDescGZIP(), []int{83} } func (x *ConfirmedArchiveChapterLog) GetChapter() *Chapter { @@ -7158,7 +7242,7 @@ type MirrorSourceConfig struct { func (x *MirrorSourceConfig) Reset() { *x = MirrorSourceConfig{} - mi := &file_common_proto_msgTypes[83] + mi := &file_common_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7170,7 +7254,7 @@ func (x *MirrorSourceConfig) String() string { func (*MirrorSourceConfig) ProtoMessage() {} func (x *MirrorSourceConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[83] + mi := &file_common_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7183,7 +7267,7 @@ func (x *MirrorSourceConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use MirrorSourceConfig.ProtoReflect.Descriptor instead. func (*MirrorSourceConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{83} + return file_common_proto_rawDescGZIP(), []int{84} } func (x *MirrorSourceConfig) GetLedgerName() string { @@ -7281,7 +7365,7 @@ type MirrorRewriteRule struct { func (x *MirrorRewriteRule) Reset() { *x = MirrorRewriteRule{} - mi := &file_common_proto_msgTypes[84] + mi := &file_common_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7293,7 +7377,7 @@ func (x *MirrorRewriteRule) String() string { func (*MirrorRewriteRule) ProtoMessage() {} func (x *MirrorRewriteRule) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[84] + mi := &file_common_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7306,7 +7390,7 @@ func (x *MirrorRewriteRule) ProtoReflect() protoreflect.Message { // Deprecated: Use MirrorRewriteRule.ProtoReflect.Descriptor instead. func (*MirrorRewriteRule) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{84} + return file_common_proto_rawDescGZIP(), []int{85} } func (x *MirrorRewriteRule) GetScope() isMirrorRewriteRule_Scope { @@ -7412,7 +7496,7 @@ type CreatedTransactionRule struct { func (x *CreatedTransactionRule) Reset() { *x = CreatedTransactionRule{} - mi := &file_common_proto_msgTypes[85] + mi := &file_common_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7424,7 +7508,7 @@ func (x *CreatedTransactionRule) String() string { func (*CreatedTransactionRule) ProtoMessage() {} func (x *CreatedTransactionRule) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[85] + mi := &file_common_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7437,7 +7521,7 @@ func (x *CreatedTransactionRule) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatedTransactionRule.ProtoReflect.Descriptor instead. func (*CreatedTransactionRule) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{85} + return file_common_proto_rawDescGZIP(), []int{86} } func (x *CreatedTransactionRule) GetMatch() string { @@ -7464,7 +7548,7 @@ type RevertedTransactionRule struct { func (x *RevertedTransactionRule) Reset() { *x = RevertedTransactionRule{} - mi := &file_common_proto_msgTypes[86] + mi := &file_common_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7476,7 +7560,7 @@ func (x *RevertedTransactionRule) String() string { func (*RevertedTransactionRule) ProtoMessage() {} func (x *RevertedTransactionRule) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[86] + mi := &file_common_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7489,7 +7573,7 @@ func (x *RevertedTransactionRule) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertedTransactionRule.ProtoReflect.Descriptor instead. func (*RevertedTransactionRule) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{86} + return file_common_proto_rawDescGZIP(), []int{87} } func (x *RevertedTransactionRule) GetMatch() string { @@ -7516,7 +7600,7 @@ type SavedMetadataRule struct { func (x *SavedMetadataRule) Reset() { *x = SavedMetadataRule{} - mi := &file_common_proto_msgTypes[87] + mi := &file_common_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7528,7 +7612,7 @@ func (x *SavedMetadataRule) String() string { func (*SavedMetadataRule) ProtoMessage() {} func (x *SavedMetadataRule) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[87] + mi := &file_common_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7541,7 +7625,7 @@ func (x *SavedMetadataRule) ProtoReflect() protoreflect.Message { // Deprecated: Use SavedMetadataRule.ProtoReflect.Descriptor instead. func (*SavedMetadataRule) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{87} + return file_common_proto_rawDescGZIP(), []int{88} } func (x *SavedMetadataRule) GetMatch() string { @@ -7568,7 +7652,7 @@ type DeletedMetadataRule struct { func (x *DeletedMetadataRule) Reset() { *x = DeletedMetadataRule{} - mi := &file_common_proto_msgTypes[88] + mi := &file_common_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7580,7 +7664,7 @@ func (x *DeletedMetadataRule) String() string { func (*DeletedMetadataRule) ProtoMessage() {} func (x *DeletedMetadataRule) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[88] + mi := &file_common_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7593,7 +7677,7 @@ func (x *DeletedMetadataRule) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletedMetadataRule.ProtoReflect.Descriptor instead. func (*DeletedMetadataRule) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{88} + return file_common_proto_rawDescGZIP(), []int{89} } func (x *DeletedMetadataRule) GetMatch() string { @@ -7624,7 +7708,7 @@ type AnyVariantRule struct { func (x *AnyVariantRule) Reset() { *x = AnyVariantRule{} - mi := &file_common_proto_msgTypes[89] + mi := &file_common_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7636,7 +7720,7 @@ func (x *AnyVariantRule) String() string { func (*AnyVariantRule) ProtoMessage() {} func (x *AnyVariantRule) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[89] + mi := &file_common_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7649,7 +7733,7 @@ func (x *AnyVariantRule) ProtoReflect() protoreflect.Message { // Deprecated: Use AnyVariantRule.ProtoReflect.Descriptor instead. func (*AnyVariantRule) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{89} + return file_common_proto_rawDescGZIP(), []int{90} } func (x *AnyVariantRule) GetMatch() string { @@ -7684,7 +7768,7 @@ type CreatedTransactionAction struct { func (x *CreatedTransactionAction) Reset() { *x = CreatedTransactionAction{} - mi := &file_common_proto_msgTypes[90] + mi := &file_common_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7696,7 +7780,7 @@ func (x *CreatedTransactionAction) String() string { func (*CreatedTransactionAction) ProtoMessage() {} func (x *CreatedTransactionAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[90] + mi := &file_common_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7709,7 +7793,7 @@ func (x *CreatedTransactionAction) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatedTransactionAction.ProtoReflect.Descriptor instead. func (*CreatedTransactionAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{90} + return file_common_proto_rawDescGZIP(), []int{91} } func (x *CreatedTransactionAction) GetAction() isCreatedTransactionAction_Action { @@ -7843,7 +7927,7 @@ type RevertedTransactionAction struct { func (x *RevertedTransactionAction) Reset() { *x = RevertedTransactionAction{} - mi := &file_common_proto_msgTypes[91] + mi := &file_common_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7855,7 +7939,7 @@ func (x *RevertedTransactionAction) String() string { func (*RevertedTransactionAction) ProtoMessage() {} func (x *RevertedTransactionAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[91] + mi := &file_common_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7868,7 +7952,7 @@ func (x *RevertedTransactionAction) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertedTransactionAction.ProtoReflect.Descriptor instead. func (*RevertedTransactionAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{91} + return file_common_proto_rawDescGZIP(), []int{92} } func (x *RevertedTransactionAction) GetAction() isRevertedTransactionAction_Action { @@ -7957,7 +8041,7 @@ type SavedMetadataAction struct { func (x *SavedMetadataAction) Reset() { *x = SavedMetadataAction{} - mi := &file_common_proto_msgTypes[92] + mi := &file_common_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7969,7 +8053,7 @@ func (x *SavedMetadataAction) String() string { func (*SavedMetadataAction) ProtoMessage() {} func (x *SavedMetadataAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[92] + mi := &file_common_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7982,7 +8066,7 @@ func (x *SavedMetadataAction) ProtoReflect() protoreflect.Message { // Deprecated: Use SavedMetadataAction.ProtoReflect.Descriptor instead. func (*SavedMetadataAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{92} + return file_common_proto_rawDescGZIP(), []int{93} } func (x *SavedMetadataAction) GetAction() isSavedMetadataAction_Action { @@ -8069,7 +8153,7 @@ type DeletedMetadataAction struct { func (x *DeletedMetadataAction) Reset() { *x = DeletedMetadataAction{} - mi := &file_common_proto_msgTypes[93] + mi := &file_common_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8081,7 +8165,7 @@ func (x *DeletedMetadataAction) String() string { func (*DeletedMetadataAction) ProtoMessage() {} func (x *DeletedMetadataAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[93] + mi := &file_common_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8094,7 +8178,7 @@ func (x *DeletedMetadataAction) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletedMetadataAction.ProtoReflect.Descriptor instead. func (*DeletedMetadataAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{93} + return file_common_proto_rawDescGZIP(), []int{94} } func (x *DeletedMetadataAction) GetAction() isDeletedMetadataAction_Action { @@ -8151,7 +8235,7 @@ type AnyVariantAction struct { func (x *AnyVariantAction) Reset() { *x = AnyVariantAction{} - mi := &file_common_proto_msgTypes[94] + mi := &file_common_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8163,7 +8247,7 @@ func (x *AnyVariantAction) String() string { func (*AnyVariantAction) ProtoMessage() {} func (x *AnyVariantAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[94] + mi := &file_common_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8176,7 +8260,7 @@ func (x *AnyVariantAction) ProtoReflect() protoreflect.Message { // Deprecated: Use AnyVariantAction.ProtoReflect.Descriptor instead. func (*AnyVariantAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{94} + return file_common_proto_rawDescGZIP(), []int{95} } func (x *AnyVariantAction) GetAction() isAnyVariantAction_Action { @@ -8230,7 +8314,7 @@ type RewriteAddressAction struct { func (x *RewriteAddressAction) Reset() { *x = RewriteAddressAction{} - mi := &file_common_proto_msgTypes[95] + mi := &file_common_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8242,7 +8326,7 @@ func (x *RewriteAddressAction) String() string { func (*RewriteAddressAction) ProtoMessage() {} func (x *RewriteAddressAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[95] + mi := &file_common_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8255,7 +8339,7 @@ func (x *RewriteAddressAction) ProtoReflect() protoreflect.Message { // Deprecated: Use RewriteAddressAction.ProtoReflect.Descriptor instead. func (*RewriteAddressAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{95} + return file_common_proto_rawDescGZIP(), []int{96} } func (x *RewriteAddressAction) GetPattern() string { @@ -8298,7 +8382,7 @@ type SetMetadataAction struct { func (x *SetMetadataAction) Reset() { *x = SetMetadataAction{} - mi := &file_common_proto_msgTypes[96] + mi := &file_common_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8310,7 +8394,7 @@ func (x *SetMetadataAction) String() string { func (*SetMetadataAction) ProtoMessage() {} func (x *SetMetadataAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[96] + mi := &file_common_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8323,7 +8407,7 @@ func (x *SetMetadataAction) ProtoReflect() protoreflect.Message { // Deprecated: Use SetMetadataAction.ProtoReflect.Descriptor instead. func (*SetMetadataAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{96} + return file_common_proto_rawDescGZIP(), []int{97} } func (x *SetMetadataAction) GetKey() string { @@ -8390,7 +8474,7 @@ type DeleteMetadataAction struct { func (x *DeleteMetadataAction) Reset() { *x = DeleteMetadataAction{} - mi := &file_common_proto_msgTypes[97] + mi := &file_common_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8402,7 +8486,7 @@ func (x *DeleteMetadataAction) String() string { func (*DeleteMetadataAction) ProtoMessage() {} func (x *DeleteMetadataAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[97] + mi := &file_common_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8415,7 +8499,7 @@ func (x *DeleteMetadataAction) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteMetadataAction.ProtoReflect.Descriptor instead. func (*DeleteMetadataAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{97} + return file_common_proto_rawDescGZIP(), []int{98} } func (x *DeleteMetadataAction) GetKey() string { @@ -8444,7 +8528,7 @@ type SetAccountMetadataAction struct { func (x *SetAccountMetadataAction) Reset() { *x = SetAccountMetadataAction{} - mi := &file_common_proto_msgTypes[98] + mi := &file_common_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8456,7 +8540,7 @@ func (x *SetAccountMetadataAction) String() string { func (*SetAccountMetadataAction) ProtoMessage() {} func (x *SetAccountMetadataAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[98] + mi := &file_common_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8469,7 +8553,7 @@ func (x *SetAccountMetadataAction) ProtoReflect() protoreflect.Message { // Deprecated: Use SetAccountMetadataAction.ProtoReflect.Descriptor instead. func (*SetAccountMetadataAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{98} + return file_common_proto_rawDescGZIP(), []int{99} } func (x *SetAccountMetadataAction) GetAccount() string { @@ -8544,7 +8628,7 @@ type DeleteAccountMetadataAction struct { func (x *DeleteAccountMetadataAction) Reset() { *x = DeleteAccountMetadataAction{} - mi := &file_common_proto_msgTypes[99] + mi := &file_common_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8556,7 +8640,7 @@ func (x *DeleteAccountMetadataAction) String() string { func (*DeleteAccountMetadataAction) ProtoMessage() {} func (x *DeleteAccountMetadataAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[99] + mi := &file_common_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8569,7 +8653,7 @@ func (x *DeleteAccountMetadataAction) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteAccountMetadataAction.ProtoReflect.Descriptor instead. func (*DeleteAccountMetadataAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{99} + return file_common_proto_rawDescGZIP(), []int{100} } func (x *DeleteAccountMetadataAction) GetAccount() string { @@ -8602,7 +8686,7 @@ type SetAccountMetadataFromAddressAction struct { func (x *SetAccountMetadataFromAddressAction) Reset() { *x = SetAccountMetadataFromAddressAction{} - mi := &file_common_proto_msgTypes[100] + mi := &file_common_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8614,7 +8698,7 @@ func (x *SetAccountMetadataFromAddressAction) String() string { func (*SetAccountMetadataFromAddressAction) ProtoMessage() {} func (x *SetAccountMetadataFromAddressAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[100] + mi := &file_common_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8627,7 +8711,7 @@ func (x *SetAccountMetadataFromAddressAction) ProtoReflect() protoreflect.Messag // Deprecated: Use SetAccountMetadataFromAddressAction.ProtoReflect.Descriptor instead. func (*SetAccountMetadataFromAddressAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{100} + return file_common_proto_rawDescGZIP(), []int{101} } func (x *SetAccountMetadataFromAddressAction) GetPattern() string { @@ -8655,7 +8739,7 @@ type SetAccountMetadataFromAddressReplacement struct { func (x *SetAccountMetadataFromAddressReplacement) Reset() { *x = SetAccountMetadataFromAddressReplacement{} - mi := &file_common_proto_msgTypes[101] + mi := &file_common_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8667,7 +8751,7 @@ func (x *SetAccountMetadataFromAddressReplacement) String() string { func (*SetAccountMetadataFromAddressReplacement) ProtoMessage() {} func (x *SetAccountMetadataFromAddressReplacement) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[101] + mi := &file_common_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8680,7 +8764,7 @@ func (x *SetAccountMetadataFromAddressReplacement) ProtoReflect() protoreflect.M // Deprecated: Use SetAccountMetadataFromAddressReplacement.ProtoReflect.Descriptor instead. func (*SetAccountMetadataFromAddressReplacement) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{101} + return file_common_proto_rawDescGZIP(), []int{102} } func (x *SetAccountMetadataFromAddressReplacement) GetKey() string { @@ -8712,7 +8796,7 @@ type DropAction struct { func (x *DropAction) Reset() { *x = DropAction{} - mi := &file_common_proto_msgTypes[102] + mi := &file_common_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8724,7 +8808,7 @@ func (x *DropAction) String() string { func (*DropAction) ProtoMessage() {} func (x *DropAction) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[102] + mi := &file_common_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8737,7 +8821,7 @@ func (x *DropAction) ProtoReflect() protoreflect.Message { // Deprecated: Use DropAction.ProtoReflect.Descriptor instead. func (*DropAction) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{102} + return file_common_proto_rawDescGZIP(), []int{103} } type HttpMirrorSourceConfig struct { @@ -8750,7 +8834,7 @@ type HttpMirrorSourceConfig struct { func (x *HttpMirrorSourceConfig) Reset() { *x = HttpMirrorSourceConfig{} - mi := &file_common_proto_msgTypes[103] + mi := &file_common_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8762,7 +8846,7 @@ func (x *HttpMirrorSourceConfig) String() string { func (*HttpMirrorSourceConfig) ProtoMessage() {} func (x *HttpMirrorSourceConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[103] + mi := &file_common_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8775,7 +8859,7 @@ func (x *HttpMirrorSourceConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use HttpMirrorSourceConfig.ProtoReflect.Descriptor instead. func (*HttpMirrorSourceConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{103} + return file_common_proto_rawDescGZIP(), []int{104} } func (x *HttpMirrorSourceConfig) GetBaseUrl() string { @@ -8804,7 +8888,7 @@ type OAuth2ClientCredentials struct { func (x *OAuth2ClientCredentials) Reset() { *x = OAuth2ClientCredentials{} - mi := &file_common_proto_msgTypes[104] + mi := &file_common_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8816,7 +8900,7 @@ func (x *OAuth2ClientCredentials) String() string { func (*OAuth2ClientCredentials) ProtoMessage() {} func (x *OAuth2ClientCredentials) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[104] + mi := &file_common_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8829,7 +8913,7 @@ func (x *OAuth2ClientCredentials) ProtoReflect() protoreflect.Message { // Deprecated: Use OAuth2ClientCredentials.ProtoReflect.Descriptor instead. func (*OAuth2ClientCredentials) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{104} + return file_common_proto_rawDescGZIP(), []int{105} } func (x *OAuth2ClientCredentials) GetClientId() string { @@ -8875,7 +8959,7 @@ type PostgresMirrorSourceConfig struct { func (x *PostgresMirrorSourceConfig) Reset() { *x = PostgresMirrorSourceConfig{} - mi := &file_common_proto_msgTypes[105] + mi := &file_common_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8887,7 +8971,7 @@ func (x *PostgresMirrorSourceConfig) String() string { func (*PostgresMirrorSourceConfig) ProtoMessage() {} func (x *PostgresMirrorSourceConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[105] + mi := &file_common_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8900,7 +8984,7 @@ func (x *PostgresMirrorSourceConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use PostgresMirrorSourceConfig.ProtoReflect.Descriptor instead. func (*PostgresMirrorSourceConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{105} + return file_common_proto_rawDescGZIP(), []int{106} } func (x *PostgresMirrorSourceConfig) GetDsn() string { @@ -8933,7 +9017,7 @@ type PostgresAwsIamAuth struct { func (x *PostgresAwsIamAuth) Reset() { *x = PostgresAwsIamAuth{} - mi := &file_common_proto_msgTypes[106] + mi := &file_common_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8945,7 +9029,7 @@ func (x *PostgresAwsIamAuth) String() string { func (*PostgresAwsIamAuth) ProtoMessage() {} func (x *PostgresAwsIamAuth) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[106] + mi := &file_common_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8958,7 +9042,7 @@ func (x *PostgresAwsIamAuth) ProtoReflect() protoreflect.Message { // Deprecated: Use PostgresAwsIamAuth.ProtoReflect.Descriptor instead. func (*PostgresAwsIamAuth) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{106} + return file_common_proto_rawDescGZIP(), []int{107} } func (x *PostgresAwsIamAuth) GetRegion() string { @@ -8985,7 +9069,7 @@ type MirrorSyncError struct { func (x *MirrorSyncError) Reset() { *x = MirrorSyncError{} - mi := &file_common_proto_msgTypes[107] + mi := &file_common_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8997,7 +9081,7 @@ func (x *MirrorSyncError) String() string { func (*MirrorSyncError) ProtoMessage() {} func (x *MirrorSyncError) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[107] + mi := &file_common_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9010,7 +9094,7 @@ func (x *MirrorSyncError) ProtoReflect() protoreflect.Message { // Deprecated: Use MirrorSyncError.ProtoReflect.Descriptor instead. func (*MirrorSyncError) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{107} + return file_common_proto_rawDescGZIP(), []int{108} } func (x *MirrorSyncError) GetMessage() string { @@ -9040,7 +9124,7 @@ type MirrorSyncProgress struct { func (x *MirrorSyncProgress) Reset() { *x = MirrorSyncProgress{} - mi := &file_common_proto_msgTypes[108] + mi := &file_common_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9052,7 +9136,7 @@ func (x *MirrorSyncProgress) String() string { func (*MirrorSyncProgress) ProtoMessage() {} func (x *MirrorSyncProgress) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[108] + mi := &file_common_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9065,7 +9149,7 @@ func (x *MirrorSyncProgress) ProtoReflect() protoreflect.Message { // Deprecated: Use MirrorSyncProgress.ProtoReflect.Descriptor instead. func (*MirrorSyncProgress) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{108} + return file_common_proto_rawDescGZIP(), []int{109} } func (x *MirrorSyncProgress) GetState() MirrorSyncState { @@ -9126,7 +9210,7 @@ type LedgerInfo struct { func (x *LedgerInfo) Reset() { *x = LedgerInfo{} - mi := &file_common_proto_msgTypes[109] + mi := &file_common_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9138,7 +9222,7 @@ func (x *LedgerInfo) String() string { func (*LedgerInfo) ProtoMessage() {} func (x *LedgerInfo) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[109] + mi := &file_common_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9151,7 +9235,7 @@ func (x *LedgerInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use LedgerInfo.ProtoReflect.Descriptor instead. func (*LedgerInfo) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{109} + return file_common_proto_rawDescGZIP(), []int{110} } func (x *LedgerInfo) GetName() string { @@ -9242,7 +9326,7 @@ type SaveMetadataCommand struct { func (x *SaveMetadataCommand) Reset() { *x = SaveMetadataCommand{} - mi := &file_common_proto_msgTypes[110] + mi := &file_common_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9254,7 +9338,7 @@ func (x *SaveMetadataCommand) String() string { func (*SaveMetadataCommand) ProtoMessage() {} func (x *SaveMetadataCommand) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[110] + mi := &file_common_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9267,7 +9351,7 @@ func (x *SaveMetadataCommand) ProtoReflect() protoreflect.Message { // Deprecated: Use SaveMetadataCommand.ProtoReflect.Descriptor instead. func (*SaveMetadataCommand) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{110} + return file_common_proto_rawDescGZIP(), []int{111} } func (x *SaveMetadataCommand) GetTarget() *Target { @@ -9295,7 +9379,7 @@ type DeleteMetadataCommand struct { func (x *DeleteMetadataCommand) Reset() { *x = DeleteMetadataCommand{} - mi := &file_common_proto_msgTypes[111] + mi := &file_common_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9307,7 +9391,7 @@ func (x *DeleteMetadataCommand) String() string { func (*DeleteMetadataCommand) ProtoMessage() {} func (x *DeleteMetadataCommand) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[111] + mi := &file_common_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9320,7 +9404,7 @@ func (x *DeleteMetadataCommand) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteMetadataCommand.ProtoReflect.Descriptor instead. func (*DeleteMetadataCommand) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{111} + return file_common_proto_rawDescGZIP(), []int{112} } func (x *DeleteMetadataCommand) GetTarget() *Target { @@ -9366,7 +9450,7 @@ type TransactionState struct { func (x *TransactionState) Reset() { *x = TransactionState{} - mi := &file_common_proto_msgTypes[112] + mi := &file_common_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9378,7 +9462,7 @@ func (x *TransactionState) String() string { func (*TransactionState) ProtoMessage() {} func (x *TransactionState) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[112] + mi := &file_common_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9391,7 +9475,7 @@ func (x *TransactionState) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionState.ProtoReflect.Descriptor instead. func (*TransactionState) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{112} + return file_common_proto_rawDescGZIP(), []int{113} } func (x *TransactionState) GetCreatedByLog() uint64 { @@ -9462,7 +9546,7 @@ type IdempotencyKeyValue struct { func (x *IdempotencyKeyValue) Reset() { *x = IdempotencyKeyValue{} - mi := &file_common_proto_msgTypes[113] + mi := &file_common_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9474,7 +9558,7 @@ func (x *IdempotencyKeyValue) String() string { func (*IdempotencyKeyValue) ProtoMessage() {} func (x *IdempotencyKeyValue) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[113] + mi := &file_common_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9487,7 +9571,7 @@ func (x *IdempotencyKeyValue) ProtoReflect() protoreflect.Message { // Deprecated: Use IdempotencyKeyValue.ProtoReflect.Descriptor instead. func (*IdempotencyKeyValue) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{113} + return file_common_proto_rawDescGZIP(), []int{114} } func (x *IdempotencyKeyValue) GetFirstLogSequence() uint64 { @@ -9548,7 +9632,7 @@ type IdempotencyFailure struct { func (x *IdempotencyFailure) Reset() { *x = IdempotencyFailure{} - mi := &file_common_proto_msgTypes[114] + mi := &file_common_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9560,7 +9644,7 @@ func (x *IdempotencyFailure) String() string { func (*IdempotencyFailure) ProtoMessage() {} func (x *IdempotencyFailure) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[114] + mi := &file_common_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9573,7 +9657,7 @@ func (x *IdempotencyFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use IdempotencyFailure.ProtoReflect.Descriptor instead. func (*IdempotencyFailure) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{114} + return file_common_proto_rawDescGZIP(), []int{115} } func (x *IdempotencyFailure) GetReason() ErrorReason { @@ -9607,7 +9691,7 @@ type TransactionReferenceValue struct { func (x *TransactionReferenceValue) Reset() { *x = TransactionReferenceValue{} - mi := &file_common_proto_msgTypes[115] + mi := &file_common_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9619,7 +9703,7 @@ func (x *TransactionReferenceValue) String() string { func (*TransactionReferenceValue) ProtoMessage() {} func (x *TransactionReferenceValue) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[115] + mi := &file_common_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9632,7 +9716,7 @@ func (x *TransactionReferenceValue) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionReferenceValue.ProtoReflect.Descriptor instead. func (*TransactionReferenceValue) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{115} + return file_common_proto_rawDescGZIP(), []int{116} } func (x *TransactionReferenceValue) GetTransactionId() uint64 { @@ -9652,7 +9736,7 @@ type NumscriptVersionValue struct { func (x *NumscriptVersionValue) Reset() { *x = NumscriptVersionValue{} - mi := &file_common_proto_msgTypes[116] + mi := &file_common_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9664,7 +9748,7 @@ func (x *NumscriptVersionValue) String() string { func (*NumscriptVersionValue) ProtoMessage() {} func (x *NumscriptVersionValue) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[116] + mi := &file_common_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9677,7 +9761,7 @@ func (x *NumscriptVersionValue) ProtoReflect() protoreflect.Message { // Deprecated: Use NumscriptVersionValue.ProtoReflect.Descriptor instead. func (*NumscriptVersionValue) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{116} + return file_common_proto_rawDescGZIP(), []int{117} } func (x *NumscriptVersionValue) GetVersion() string { @@ -9704,7 +9788,7 @@ type SegmentType struct { func (x *SegmentType) Reset() { *x = SegmentType{} - mi := &file_common_proto_msgTypes[117] + mi := &file_common_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9716,7 +9800,7 @@ func (x *SegmentType) String() string { func (*SegmentType) ProtoMessage() {} func (x *SegmentType) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[117] + mi := &file_common_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9729,7 +9813,7 @@ func (x *SegmentType) ProtoReflect() protoreflect.Message { // Deprecated: Use SegmentType.ProtoReflect.Descriptor instead. func (*SegmentType) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{117} + return file_common_proto_rawDescGZIP(), []int{118} } func (x *SegmentType) GetConstraint() isSegmentType_Constraint { @@ -9811,7 +9895,7 @@ type UUIDConstraint struct { func (x *UUIDConstraint) Reset() { *x = UUIDConstraint{} - mi := &file_common_proto_msgTypes[118] + mi := &file_common_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9823,7 +9907,7 @@ func (x *UUIDConstraint) String() string { func (*UUIDConstraint) ProtoMessage() {} func (x *UUIDConstraint) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[118] + mi := &file_common_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9836,7 +9920,7 @@ func (x *UUIDConstraint) ProtoReflect() protoreflect.Message { // Deprecated: Use UUIDConstraint.ProtoReflect.Descriptor instead. func (*UUIDConstraint) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{118} + return file_common_proto_rawDescGZIP(), []int{119} } type Uint64Constraint struct { @@ -9847,7 +9931,7 @@ type Uint64Constraint struct { func (x *Uint64Constraint) Reset() { *x = Uint64Constraint{} - mi := &file_common_proto_msgTypes[119] + mi := &file_common_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9859,7 +9943,7 @@ func (x *Uint64Constraint) String() string { func (*Uint64Constraint) ProtoMessage() {} func (x *Uint64Constraint) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[119] + mi := &file_common_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9872,7 +9956,7 @@ func (x *Uint64Constraint) ProtoReflect() protoreflect.Message { // Deprecated: Use Uint64Constraint.ProtoReflect.Descriptor instead. func (*Uint64Constraint) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{119} + return file_common_proto_rawDescGZIP(), []int{120} } type BytesConstraint struct { @@ -9883,7 +9967,7 @@ type BytesConstraint struct { func (x *BytesConstraint) Reset() { *x = BytesConstraint{} - mi := &file_common_proto_msgTypes[120] + mi := &file_common_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9895,7 +9979,7 @@ func (x *BytesConstraint) String() string { func (*BytesConstraint) ProtoMessage() {} func (x *BytesConstraint) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[120] + mi := &file_common_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9908,7 +9992,7 @@ func (x *BytesConstraint) ProtoReflect() protoreflect.Message { // Deprecated: Use BytesConstraint.ProtoReflect.Descriptor instead. func (*BytesConstraint) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{120} + return file_common_proto_rawDescGZIP(), []int{121} } // AccountType defines a single account address pattern for a ledger. @@ -9924,7 +10008,7 @@ type AccountType struct { func (x *AccountType) Reset() { *x = AccountType{} - mi := &file_common_proto_msgTypes[121] + mi := &file_common_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9936,7 +10020,7 @@ func (x *AccountType) String() string { func (*AccountType) ProtoMessage() {} func (x *AccountType) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[121] + mi := &file_common_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9949,7 +10033,7 @@ func (x *AccountType) ProtoReflect() protoreflect.Message { // Deprecated: Use AccountType.ProtoReflect.Descriptor instead. func (*AccountType) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{121} + return file_common_proto_rawDescGZIP(), []int{122} } func (x *AccountType) GetName() string { @@ -9990,7 +10074,7 @@ type AddedAccountTypeLog struct { func (x *AddedAccountTypeLog) Reset() { *x = AddedAccountTypeLog{} - mi := &file_common_proto_msgTypes[122] + mi := &file_common_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10002,7 +10086,7 @@ func (x *AddedAccountTypeLog) String() string { func (*AddedAccountTypeLog) ProtoMessage() {} func (x *AddedAccountTypeLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[122] + mi := &file_common_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10015,7 +10099,7 @@ func (x *AddedAccountTypeLog) ProtoReflect() protoreflect.Message { // Deprecated: Use AddedAccountTypeLog.ProtoReflect.Descriptor instead. func (*AddedAccountTypeLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{122} + return file_common_proto_rawDescGZIP(), []int{123} } func (x *AddedAccountTypeLog) GetAccountType() *AccountType { @@ -10035,7 +10119,7 @@ type RemovedAccountTypeLog struct { func (x *RemovedAccountTypeLog) Reset() { *x = RemovedAccountTypeLog{} - mi := &file_common_proto_msgTypes[123] + mi := &file_common_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10047,7 +10131,7 @@ func (x *RemovedAccountTypeLog) String() string { func (*RemovedAccountTypeLog) ProtoMessage() {} func (x *RemovedAccountTypeLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[123] + mi := &file_common_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10060,7 +10144,7 @@ func (x *RemovedAccountTypeLog) ProtoReflect() protoreflect.Message { // Deprecated: Use RemovedAccountTypeLog.ProtoReflect.Descriptor instead. func (*RemovedAccountTypeLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{123} + return file_common_proto_rawDescGZIP(), []int{124} } func (x *RemovedAccountTypeLog) GetName() string { @@ -10080,7 +10164,7 @@ type UpdatedDefaultEnforcementModeLog struct { func (x *UpdatedDefaultEnforcementModeLog) Reset() { *x = UpdatedDefaultEnforcementModeLog{} - mi := &file_common_proto_msgTypes[124] + mi := &file_common_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10092,7 +10176,7 @@ func (x *UpdatedDefaultEnforcementModeLog) String() string { func (*UpdatedDefaultEnforcementModeLog) ProtoMessage() {} func (x *UpdatedDefaultEnforcementModeLog) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[124] + mi := &file_common_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10105,7 +10189,7 @@ func (x *UpdatedDefaultEnforcementModeLog) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdatedDefaultEnforcementModeLog.ProtoReflect.Descriptor instead. func (*UpdatedDefaultEnforcementModeLog) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{124} + return file_common_proto_rawDescGZIP(), []int{125} } func (x *UpdatedDefaultEnforcementModeLog) GetEnforcementMode() ChartEnforcementMode { @@ -10139,7 +10223,7 @@ type QueryFilter struct { func (x *QueryFilter) Reset() { *x = QueryFilter{} - mi := &file_common_proto_msgTypes[125] + mi := &file_common_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10151,7 +10235,7 @@ func (x *QueryFilter) String() string { func (*QueryFilter) ProtoMessage() {} func (x *QueryFilter) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[125] + mi := &file_common_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10164,7 +10248,7 @@ func (x *QueryFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryFilter.ProtoReflect.Descriptor instead. func (*QueryFilter) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{125} + return file_common_proto_rawDescGZIP(), []int{126} } func (x *QueryFilter) GetFilter() isQueryFilter_Filter { @@ -10416,7 +10500,7 @@ type ReferenceCondition struct { func (x *ReferenceCondition) Reset() { *x = ReferenceCondition{} - mi := &file_common_proto_msgTypes[126] + mi := &file_common_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10428,7 +10512,7 @@ func (x *ReferenceCondition) String() string { func (*ReferenceCondition) ProtoMessage() {} func (x *ReferenceCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[126] + mi := &file_common_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10441,7 +10525,7 @@ func (x *ReferenceCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use ReferenceCondition.ProtoReflect.Descriptor instead. func (*ReferenceCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{126} + return file_common_proto_rawDescGZIP(), []int{127} } func (x *ReferenceCondition) GetCond() *StringCondition { @@ -10463,7 +10547,7 @@ type RevertedCondition struct { func (x *RevertedCondition) Reset() { *x = RevertedCondition{} - mi := &file_common_proto_msgTypes[127] + mi := &file_common_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10475,7 +10559,7 @@ func (x *RevertedCondition) String() string { func (*RevertedCondition) ProtoMessage() {} func (x *RevertedCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[127] + mi := &file_common_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10488,7 +10572,7 @@ func (x *RevertedCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertedCondition.ProtoReflect.Descriptor instead. func (*RevertedCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{127} + return file_common_proto_rawDescGZIP(), []int{128} } func (x *RevertedCondition) GetValue() bool { @@ -10530,7 +10614,7 @@ type AuditCondition struct { func (x *AuditCondition) Reset() { *x = AuditCondition{} - mi := &file_common_proto_msgTypes[128] + mi := &file_common_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10542,7 +10626,7 @@ func (x *AuditCondition) String() string { func (*AuditCondition) ProtoMessage() {} func (x *AuditCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[128] + mi := &file_common_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10555,7 +10639,7 @@ func (x *AuditCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use AuditCondition.ProtoReflect.Descriptor instead. func (*AuditCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{128} + return file_common_proto_rawDescGZIP(), []int{129} } func (x *AuditCondition) GetField() AuditField { @@ -10616,7 +10700,7 @@ type LedgerCondition struct { func (x *LedgerCondition) Reset() { *x = LedgerCondition{} - mi := &file_common_proto_msgTypes[129] + mi := &file_common_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10628,7 +10712,7 @@ func (x *LedgerCondition) String() string { func (*LedgerCondition) ProtoMessage() {} func (x *LedgerCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[129] + mi := &file_common_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10641,7 +10725,7 @@ func (x *LedgerCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use LedgerCondition.ProtoReflect.Descriptor instead. func (*LedgerCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{129} + return file_common_proto_rawDescGZIP(), []int{130} } func (x *LedgerCondition) GetCond() *StringCondition { @@ -10661,7 +10745,7 @@ type LogIdCondition struct { func (x *LogIdCondition) Reset() { *x = LogIdCondition{} - mi := &file_common_proto_msgTypes[130] + mi := &file_common_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10673,7 +10757,7 @@ func (x *LogIdCondition) String() string { func (*LogIdCondition) ProtoMessage() {} func (x *LogIdCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[130] + mi := &file_common_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10686,7 +10770,7 @@ func (x *LogIdCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use LogIdCondition.ProtoReflect.Descriptor instead. func (*LogIdCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{130} + return file_common_proto_rawDescGZIP(), []int{131} } func (x *LogIdCondition) GetCond() *UintCondition { @@ -10707,7 +10791,7 @@ type BuiltinUintCondition struct { func (x *BuiltinUintCondition) Reset() { *x = BuiltinUintCondition{} - mi := &file_common_proto_msgTypes[131] + mi := &file_common_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10719,7 +10803,7 @@ func (x *BuiltinUintCondition) String() string { func (*BuiltinUintCondition) ProtoMessage() {} func (x *BuiltinUintCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[131] + mi := &file_common_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10732,7 +10816,7 @@ func (x *BuiltinUintCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use BuiltinUintCondition.ProtoReflect.Descriptor instead. func (*BuiltinUintCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{131} + return file_common_proto_rawDescGZIP(), []int{132} } func (x *BuiltinUintCondition) GetField() TransactionBuiltinIndex { @@ -10760,7 +10844,7 @@ type LogBuiltinUintCondition struct { func (x *LogBuiltinUintCondition) Reset() { *x = LogBuiltinUintCondition{} - mi := &file_common_proto_msgTypes[132] + mi := &file_common_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10772,7 +10856,7 @@ func (x *LogBuiltinUintCondition) String() string { func (*LogBuiltinUintCondition) ProtoMessage() {} func (x *LogBuiltinUintCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[132] + mi := &file_common_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10785,7 +10869,7 @@ func (x *LogBuiltinUintCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use LogBuiltinUintCondition.ProtoReflect.Descriptor instead. func (*LogBuiltinUintCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{132} + return file_common_proto_rawDescGZIP(), []int{133} } func (x *LogBuiltinUintCondition) GetField() LogBuiltinIndex { @@ -10816,7 +10900,7 @@ type AccountHasAssetCondition struct { func (x *AccountHasAssetCondition) Reset() { *x = AccountHasAssetCondition{} - mi := &file_common_proto_msgTypes[133] + mi := &file_common_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10828,7 +10912,7 @@ func (x *AccountHasAssetCondition) String() string { func (*AccountHasAssetCondition) ProtoMessage() {} func (x *AccountHasAssetCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[133] + mi := &file_common_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10841,7 +10925,7 @@ func (x *AccountHasAssetCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use AccountHasAssetCondition.ProtoReflect.Descriptor instead. func (*AccountHasAssetCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{133} + return file_common_proto_rawDescGZIP(), []int{134} } func (x *AccountHasAssetCondition) GetAssetBase() string { @@ -10867,7 +10951,7 @@ type AndFilter struct { func (x *AndFilter) Reset() { *x = AndFilter{} - mi := &file_common_proto_msgTypes[134] + mi := &file_common_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10879,7 +10963,7 @@ func (x *AndFilter) String() string { func (*AndFilter) ProtoMessage() {} func (x *AndFilter) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[134] + mi := &file_common_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10892,7 +10976,7 @@ func (x *AndFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use AndFilter.ProtoReflect.Descriptor instead. func (*AndFilter) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{134} + return file_common_proto_rawDescGZIP(), []int{135} } func (x *AndFilter) GetFilters() []*QueryFilter { @@ -10911,7 +10995,7 @@ type OrFilter struct { func (x *OrFilter) Reset() { *x = OrFilter{} - mi := &file_common_proto_msgTypes[135] + mi := &file_common_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10923,7 +11007,7 @@ func (x *OrFilter) String() string { func (*OrFilter) ProtoMessage() {} func (x *OrFilter) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[135] + mi := &file_common_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10936,7 +11020,7 @@ func (x *OrFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use OrFilter.ProtoReflect.Descriptor instead. func (*OrFilter) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{135} + return file_common_proto_rawDescGZIP(), []int{136} } func (x *OrFilter) GetFilters() []*QueryFilter { @@ -10955,7 +11039,7 @@ type NotFilter struct { func (x *NotFilter) Reset() { *x = NotFilter{} - mi := &file_common_proto_msgTypes[136] + mi := &file_common_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10967,7 +11051,7 @@ func (x *NotFilter) String() string { func (*NotFilter) ProtoMessage() {} func (x *NotFilter) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[136] + mi := &file_common_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10980,7 +11064,7 @@ func (x *NotFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use NotFilter.ProtoReflect.Descriptor instead. func (*NotFilter) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{136} + return file_common_proto_rawDescGZIP(), []int{137} } func (x *NotFilter) GetFilter() *QueryFilter { @@ -11002,7 +11086,7 @@ type FieldRef struct { func (x *FieldRef) Reset() { *x = FieldRef{} - mi := &file_common_proto_msgTypes[137] + mi := &file_common_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11014,7 +11098,7 @@ func (x *FieldRef) String() string { func (*FieldRef) ProtoMessage() {} func (x *FieldRef) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[137] + mi := &file_common_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11027,7 +11111,7 @@ func (x *FieldRef) ProtoReflect() protoreflect.Message { // Deprecated: Use FieldRef.ProtoReflect.Descriptor instead. func (*FieldRef) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{137} + return file_common_proto_rawDescGZIP(), []int{138} } func (x *FieldRef) GetMetadata() string { @@ -11055,7 +11139,7 @@ type FieldCondition struct { func (x *FieldCondition) Reset() { *x = FieldCondition{} - mi := &file_common_proto_msgTypes[138] + mi := &file_common_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11067,7 +11151,7 @@ func (x *FieldCondition) String() string { func (*FieldCondition) ProtoMessage() {} func (x *FieldCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[138] + mi := &file_common_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11080,7 +11164,7 @@ func (x *FieldCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use FieldCondition.ProtoReflect.Descriptor instead. func (*FieldCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{138} + return file_common_proto_rawDescGZIP(), []int{139} } func (x *FieldCondition) GetField() *FieldRef { @@ -11189,7 +11273,7 @@ type StringCondition struct { func (x *StringCondition) Reset() { *x = StringCondition{} - mi := &file_common_proto_msgTypes[139] + mi := &file_common_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11201,7 +11285,7 @@ func (x *StringCondition) String() string { func (*StringCondition) ProtoMessage() {} func (x *StringCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[139] + mi := &file_common_proto_msgTypes[140] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11214,7 +11298,7 @@ func (x *StringCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use StringCondition.ProtoReflect.Descriptor instead. func (*StringCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{139} + return file_common_proto_rawDescGZIP(), []int{140} } func (x *StringCondition) GetValue() isStringCondition_Value { @@ -11272,7 +11356,7 @@ type IntCondition struct { func (x *IntCondition) Reset() { *x = IntCondition{} - mi := &file_common_proto_msgTypes[140] + mi := &file_common_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11284,7 +11368,7 @@ func (x *IntCondition) String() string { func (*IntCondition) ProtoMessage() {} func (x *IntCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[140] + mi := &file_common_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11297,7 +11381,7 @@ func (x *IntCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use IntCondition.ProtoReflect.Descriptor instead. func (*IntCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{140} + return file_common_proto_rawDescGZIP(), []int{141} } func (x *IntCondition) GetMin() int64 { @@ -11356,7 +11440,7 @@ type UintCondition struct { func (x *UintCondition) Reset() { *x = UintCondition{} - mi := &file_common_proto_msgTypes[141] + mi := &file_common_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11368,7 +11452,7 @@ func (x *UintCondition) String() string { func (*UintCondition) ProtoMessage() {} func (x *UintCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[141] + mi := &file_common_proto_msgTypes[142] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11381,7 +11465,7 @@ func (x *UintCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use UintCondition.ProtoReflect.Descriptor instead. func (*UintCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{141} + return file_common_proto_rawDescGZIP(), []int{142} } func (x *UintCondition) GetMin() uint64 { @@ -11439,7 +11523,7 @@ type BoolCondition struct { func (x *BoolCondition) Reset() { *x = BoolCondition{} - mi := &file_common_proto_msgTypes[142] + mi := &file_common_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11451,7 +11535,7 @@ func (x *BoolCondition) String() string { func (*BoolCondition) ProtoMessage() {} func (x *BoolCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[142] + mi := &file_common_proto_msgTypes[143] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11464,7 +11548,7 @@ func (x *BoolCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use BoolCondition.ProtoReflect.Descriptor instead. func (*BoolCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{142} + return file_common_proto_rawDescGZIP(), []int{143} } func (x *BoolCondition) GetValue() isBoolCondition_Value { @@ -11517,7 +11601,7 @@ type ExistsCondition struct { func (x *ExistsCondition) Reset() { *x = ExistsCondition{} - mi := &file_common_proto_msgTypes[143] + mi := &file_common_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11529,7 +11613,7 @@ func (x *ExistsCondition) String() string { func (*ExistsCondition) ProtoMessage() {} func (x *ExistsCondition) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[143] + mi := &file_common_proto_msgTypes[144] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11542,7 +11626,7 @@ func (x *ExistsCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use ExistsCondition.ProtoReflect.Descriptor instead. func (*ExistsCondition) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{143} + return file_common_proto_rawDescGZIP(), []int{144} } func (x *ExistsCondition) GetIncludeNull() bool { @@ -11568,7 +11652,7 @@ type AddressMatch struct { func (x *AddressMatch) Reset() { *x = AddressMatch{} - mi := &file_common_proto_msgTypes[144] + mi := &file_common_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11580,7 +11664,7 @@ func (x *AddressMatch) String() string { func (*AddressMatch) ProtoMessage() {} func (x *AddressMatch) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[144] + mi := &file_common_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11593,7 +11677,7 @@ func (x *AddressMatch) ProtoReflect() protoreflect.Message { // Deprecated: Use AddressMatch.ProtoReflect.Descriptor instead. func (*AddressMatch) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{144} + return file_common_proto_rawDescGZIP(), []int{145} } func (x *AddressMatch) GetMatch() isAddressMatch_Match { @@ -11689,7 +11773,7 @@ type PreparedQuery struct { func (x *PreparedQuery) Reset() { *x = PreparedQuery{} - mi := &file_common_proto_msgTypes[145] + mi := &file_common_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11701,7 +11785,7 @@ func (x *PreparedQuery) String() string { func (*PreparedQuery) ProtoMessage() {} func (x *PreparedQuery) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[145] + mi := &file_common_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11714,7 +11798,7 @@ func (x *PreparedQuery) ProtoReflect() protoreflect.Message { // Deprecated: Use PreparedQuery.ProtoReflect.Descriptor instead. func (*PreparedQuery) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{145} + return file_common_proto_rawDescGZIP(), []int{146} } func (x *PreparedQuery) GetName() string { @@ -11754,7 +11838,7 @@ type AggregatedVolume struct { func (x *AggregatedVolume) Reset() { *x = AggregatedVolume{} - mi := &file_common_proto_msgTypes[146] + mi := &file_common_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11766,7 +11850,7 @@ func (x *AggregatedVolume) String() string { func (*AggregatedVolume) ProtoMessage() {} func (x *AggregatedVolume) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[146] + mi := &file_common_proto_msgTypes[147] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11779,7 +11863,7 @@ func (x *AggregatedVolume) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregatedVolume.ProtoReflect.Descriptor instead. func (*AggregatedVolume) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{146} + return file_common_proto_rawDescGZIP(), []int{147} } func (x *AggregatedVolume) GetAsset() string { @@ -11821,7 +11905,7 @@ type AggregateResult struct { func (x *AggregateResult) Reset() { *x = AggregateResult{} - mi := &file_common_proto_msgTypes[147] + mi := &file_common_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11833,7 +11917,7 @@ func (x *AggregateResult) String() string { func (*AggregateResult) ProtoMessage() {} func (x *AggregateResult) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[147] + mi := &file_common_proto_msgTypes[148] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11846,7 +11930,7 @@ func (x *AggregateResult) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregateResult.ProtoReflect.Descriptor instead. func (*AggregateResult) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{147} + return file_common_proto_rawDescGZIP(), []int{148} } func (x *AggregateResult) GetVolumes() []*AggregatedVolume { @@ -11874,7 +11958,7 @@ type GroupedAggregateResult struct { func (x *GroupedAggregateResult) Reset() { *x = GroupedAggregateResult{} - mi := &file_common_proto_msgTypes[148] + mi := &file_common_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11886,7 +11970,7 @@ func (x *GroupedAggregateResult) String() string { func (*GroupedAggregateResult) ProtoMessage() {} func (x *GroupedAggregateResult) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[148] + mi := &file_common_proto_msgTypes[149] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11899,7 +11983,7 @@ func (x *GroupedAggregateResult) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupedAggregateResult.ProtoReflect.Descriptor instead. func (*GroupedAggregateResult) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{148} + return file_common_proto_rawDescGZIP(), []int{149} } func (x *GroupedAggregateResult) GetPrefix() string { @@ -11932,7 +12016,7 @@ type PreparedQueryCursor struct { func (x *PreparedQueryCursor) Reset() { *x = PreparedQueryCursor{} - mi := &file_common_proto_msgTypes[149] + mi := &file_common_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11944,7 +12028,7 @@ func (x *PreparedQueryCursor) String() string { func (*PreparedQueryCursor) ProtoMessage() {} func (x *PreparedQueryCursor) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[149] + mi := &file_common_proto_msgTypes[150] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11957,7 +12041,7 @@ func (x *PreparedQueryCursor) ProtoReflect() protoreflect.Message { // Deprecated: Use PreparedQueryCursor.ProtoReflect.Descriptor instead. func (*PreparedQueryCursor) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{149} + return file_common_proto_rawDescGZIP(), []int{150} } func (x *PreparedQueryCursor) GetPageSize() uint32 { @@ -12014,7 +12098,6 @@ type LedgerStats struct { state protoimpl.MessageState `protogen:"open.v1"` TransactionCount uint64 `protobuf:"fixed64,1,opt,name=transaction_count,json=transactionCount,proto3" json:"transaction_count,omitempty"` VolumeCount uint64 `protobuf:"fixed64,2,opt,name=volume_count,json=volumeCount,proto3" json:"volume_count,omitempty"` - MetadataCount uint64 `protobuf:"fixed64,3,opt,name=metadata_count,json=metadataCount,proto3" json:"metadata_count,omitempty"` ReferenceCount uint64 `protobuf:"fixed64,4,opt,name=reference_count,json=referenceCount,proto3" json:"reference_count,omitempty"` PostingCount uint64 `protobuf:"fixed64,5,opt,name=posting_count,json=postingCount,proto3" json:"posting_count,omitempty"` EphemeralEvictedCount uint64 `protobuf:"fixed64,6,opt,name=ephemeral_evicted_count,json=ephemeralEvictedCount,proto3" json:"ephemeral_evicted_count,omitempty"` @@ -12028,7 +12111,7 @@ type LedgerStats struct { func (x *LedgerStats) Reset() { *x = LedgerStats{} - mi := &file_common_proto_msgTypes[150] + mi := &file_common_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12040,7 +12123,7 @@ func (x *LedgerStats) String() string { func (*LedgerStats) ProtoMessage() {} func (x *LedgerStats) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[150] + mi := &file_common_proto_msgTypes[151] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12053,7 +12136,7 @@ func (x *LedgerStats) ProtoReflect() protoreflect.Message { // Deprecated: Use LedgerStats.ProtoReflect.Descriptor instead. func (*LedgerStats) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{150} + return file_common_proto_rawDescGZIP(), []int{151} } func (x *LedgerStats) GetTransactionCount() uint64 { @@ -12070,13 +12153,6 @@ func (x *LedgerStats) GetVolumeCount() uint64 { return 0 } -func (x *LedgerStats) GetMetadataCount() uint64 { - if x != nil { - return x.MetadataCount - } - return 0 -} - func (x *LedgerStats) GetReferenceCount() uint64 { if x != nil { return x.ReferenceCount @@ -12141,7 +12217,7 @@ type PersistedConfig struct { func (x *PersistedConfig) Reset() { *x = PersistedConfig{} - mi := &file_common_proto_msgTypes[151] + mi := &file_common_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12153,7 +12229,7 @@ func (x *PersistedConfig) String() string { func (*PersistedConfig) ProtoMessage() {} func (x *PersistedConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[151] + mi := &file_common_proto_msgTypes[152] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12166,7 +12242,7 @@ func (x *PersistedConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use PersistedConfig.ProtoReflect.Descriptor instead. func (*PersistedConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{151} + return file_common_proto_rawDescGZIP(), []int{152} } func (x *PersistedConfig) GetNodeId() uint64 { @@ -12224,7 +12300,7 @@ type CallerIdentity struct { func (x *CallerIdentity) Reset() { *x = CallerIdentity{} - mi := &file_common_proto_msgTypes[152] + mi := &file_common_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12236,7 +12312,7 @@ func (x *CallerIdentity) String() string { func (*CallerIdentity) ProtoMessage() {} func (x *CallerIdentity) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[152] + mi := &file_common_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12249,7 +12325,7 @@ func (x *CallerIdentity) ProtoReflect() protoreflect.Message { // Deprecated: Use CallerIdentity.ProtoReflect.Descriptor instead. func (*CallerIdentity) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{152} + return file_common_proto_rawDescGZIP(), []int{153} } func (x *CallerIdentity) GetSubject() string { @@ -12336,7 +12412,7 @@ type CallerSnapshot struct { func (x *CallerSnapshot) Reset() { *x = CallerSnapshot{} - mi := &file_common_proto_msgTypes[153] + mi := &file_common_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12348,7 +12424,7 @@ func (x *CallerSnapshot) String() string { func (*CallerSnapshot) ProtoMessage() {} func (x *CallerSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[153] + mi := &file_common_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12361,7 +12437,7 @@ func (x *CallerSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use CallerSnapshot.ProtoReflect.Descriptor instead. func (*CallerSnapshot) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{153} + return file_common_proto_rawDescGZIP(), []int{154} } func (x *CallerSnapshot) GetIdentity() *CallerIdentity { @@ -12399,7 +12475,7 @@ type S3StorageConfig struct { func (x *S3StorageConfig) Reset() { *x = S3StorageConfig{} - mi := &file_common_proto_msgTypes[154] + mi := &file_common_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12411,7 +12487,7 @@ func (x *S3StorageConfig) String() string { func (*S3StorageConfig) ProtoMessage() {} func (x *S3StorageConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[154] + mi := &file_common_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12424,7 +12500,7 @@ func (x *S3StorageConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use S3StorageConfig.ProtoReflect.Descriptor instead. func (*S3StorageConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{154} + return file_common_proto_rawDescGZIP(), []int{155} } func (x *S3StorageConfig) GetBucket() string { @@ -12475,7 +12551,7 @@ type AzureStorageConfig struct { func (x *AzureStorageConfig) Reset() { *x = AzureStorageConfig{} - mi := &file_common_proto_msgTypes[155] + mi := &file_common_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12487,7 +12563,7 @@ func (x *AzureStorageConfig) String() string { func (*AzureStorageConfig) ProtoMessage() {} func (x *AzureStorageConfig) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[155] + mi := &file_common_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12500,7 +12576,7 @@ func (x *AzureStorageConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use AzureStorageConfig.ProtoReflect.Descriptor instead. func (*AzureStorageConfig) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{155} + return file_common_proto_rawDescGZIP(), []int{156} } func (x *AzureStorageConfig) GetAccountName() string { @@ -12547,7 +12623,7 @@ type BackupStorage struct { func (x *BackupStorage) Reset() { *x = BackupStorage{} - mi := &file_common_proto_msgTypes[156] + mi := &file_common_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12559,7 +12635,7 @@ func (x *BackupStorage) String() string { func (*BackupStorage) ProtoMessage() {} func (x *BackupStorage) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[156] + mi := &file_common_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12572,7 +12648,7 @@ func (x *BackupStorage) ProtoReflect() protoreflect.Message { // Deprecated: Use BackupStorage.ProtoReflect.Descriptor instead. func (*BackupStorage) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{156} + return file_common_proto_rawDescGZIP(), []int{157} } func (x *BackupStorage) GetProvider() isBackupStorage_Provider { @@ -12635,7 +12711,7 @@ type ReadOptions struct { func (x *ReadOptions) Reset() { *x = ReadOptions{} - mi := &file_common_proto_msgTypes[157] + mi := &file_common_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12647,7 +12723,7 @@ func (x *ReadOptions) String() string { func (*ReadOptions) ProtoMessage() {} func (x *ReadOptions) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[157] + mi := &file_common_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12660,7 +12736,7 @@ func (x *ReadOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadOptions.ProtoReflect.Descriptor instead. func (*ReadOptions) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{157} + return file_common_proto_rawDescGZIP(), []int{158} } func (x *ReadOptions) GetCheckpointId() uint64 { @@ -12712,7 +12788,7 @@ type ListOptions struct { func (x *ListOptions) Reset() { *x = ListOptions{} - mi := &file_common_proto_msgTypes[158] + mi := &file_common_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12724,7 +12800,7 @@ func (x *ListOptions) String() string { func (*ListOptions) ProtoMessage() {} func (x *ListOptions) ProtoReflect() protoreflect.Message { - mi := &file_common_proto_msgTypes[158] + mi := &file_common_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12737,7 +12813,7 @@ func (x *ListOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use ListOptions.ProtoReflect.Descriptor instead. func (*ListOptions) Descriptor() ([]byte, []int) { - return file_common_proto_rawDescGZIP(), []int{158} + return file_common_proto_rawDescGZIP(), []int{159} } func (x *ListOptions) GetRead() *ReadOptions { @@ -13081,7 +13157,10 @@ const file_common_proto_rawDesc = "" + "\x04info\x18\x01 \x01(\v2\x15.common.NumscriptInfoR\x04info\"A\n" + "\x13DeletedNumscriptLog\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x16\n" + - "\x06ledger\x18\x02 \x01(\tR\x06ledger\"3\n" + + "\x06ledger\x18\x02 \x01(\tR\x06ledger\"U\n" + + "\rTemplateUsage\x12\x14\n" + + "\x05count\x18\x01 \x01(\x06R\x05count\x12.\n" + + "\tlast_used\x18\x02 \x01(\v2\x11.common.TimestampR\blastUsed\"3\n" + "\x1dSetQueryCheckpointScheduleLog\x12\x12\n" + "\x04cron\x18\x01 \x01(\tR\x04cron\"#\n" + "!DeletedQueryCheckpointScheduleLog\"c\n" + @@ -13168,12 +13247,14 @@ const file_common_proto_rawDesc = "" + "\x0eApplyLedgerLog\x12\x1f\n" + "\vledger_name\x18\x01 \x01(\tR\n" + "ledgerName\x12#\n" + - "\x03log\x18\x02 \x01(\v2\x11.common.LedgerLogR\x03log\"\xae\x01\n" + + "\x03log\x18\x02 \x01(\v2\x11.common.LedgerLogR\x03log\"\xb3\x02\n" + "\tLedgerLog\x12,\n" + "\x04data\x18\x01 \x01(\v2\x18.common.LedgerLogPayloadR\x04data\x12%\n" + "\x04date\x18\x02 \x01(\v2\x11.common.TimestampR\x04date\x12\x0e\n" + "\x02id\x18\x03 \x01(\x06R\x02id\x12<\n" + - "\x0epurged_volumes\x18\x04 \x03(\v2\x15.common.TouchedVolumeR\rpurgedVolumes\"U\n" + + "\x0epurged_volumes\x18\x04 \x03(\v2\x15.common.TouchedVolumeR\rpurgedVolumes\x12?\n" + + "\x10new_kept_volumes\x18\x05 \x03(\v2\x15.common.TouchedVolumeR\x0enewKeptVolumes\x12B\n" + + "\x11ephemeral_volumes\x18\x06 \x03(\v2\x15.common.TouchedVolumeR\x10ephemeralVolumes\"U\n" + "\rTouchedVolume\x12\x18\n" + "\aaccount\x18\x01 \x01(\tR\aaccount\x12\x14\n" + "\x05asset\x18\x02 \x01(\tR\x05asset\x12\x14\n" + @@ -13585,11 +13666,10 @@ const file_common_proto_rawDesc = "" + "\x04next\x18\x04 \x01(\tR\x04next\x122\n" + "\faccount_data\x18\x05 \x03(\v2\x0f.common.AccountR\vaccountData\x12>\n" + "\x10transaction_data\x18\x06 \x03(\v2\x13.common.TransactionR\x0ftransactionData\x12&\n" + - "\blog_data\x18\a \x03(\v2\v.common.LogR\alogData\"\xb8\x03\n" + + "\blog_data\x18\a \x03(\v2\v.common.LogR\alogData\"\x91\x03\n" + "\vLedgerStats\x12+\n" + "\x11transaction_count\x18\x01 \x01(\x06R\x10transactionCount\x12!\n" + - "\fvolume_count\x18\x02 \x01(\x06R\vvolumeCount\x12%\n" + - "\x0emetadata_count\x18\x03 \x01(\x06R\rmetadataCount\x12'\n" + + "\fvolume_count\x18\x02 \x01(\x06R\vvolumeCount\x12'\n" + "\x0freference_count\x18\x04 \x01(\x06R\x0ereferenceCount\x12#\n" + "\rposting_count\x18\x05 \x01(\x06R\fpostingCount\x126\n" + "\x17ephemeral_evicted_count\x18\x06 \x01(\x06R\x15ephemeralEvictedCount\x120\n" + @@ -13819,7 +13899,7 @@ func file_common_proto_rawDescGZIP() []byte { } var file_common_proto_enumTypes = make([]protoimpl.EnumInfo, 18) -var file_common_proto_msgTypes = make([]protoimpl.MessageInfo, 178) +var file_common_proto_msgTypes = make([]protoimpl.MessageInfo, 179) var file_common_proto_goTypes = []any{ (TargetType)(0), // 0: common.TargetType (MetadataType)(0), // 1: common.MetadataType @@ -13888,163 +13968,164 @@ var file_common_proto_goTypes = []any{ (*NumscriptInfo)(nil), // 64: common.NumscriptInfo (*SavedNumscriptLog)(nil), // 65: common.SavedNumscriptLog (*DeletedNumscriptLog)(nil), // 66: common.DeletedNumscriptLog - (*SetQueryCheckpointScheduleLog)(nil), // 67: common.SetQueryCheckpointScheduleLog - (*DeletedQueryCheckpointScheduleLog)(nil), // 68: common.DeletedQueryCheckpointScheduleLog - (*CreatedQueryCheckpointLog)(nil), // 69: common.CreatedQueryCheckpointLog - (*DeletedQueryCheckpointLog)(nil), // 70: common.DeletedQueryCheckpointLog - (*SinkConfig)(nil), // 71: common.SinkConfig - (*SinkStatus)(nil), // 72: common.SinkStatus - (*SinkError)(nil), // 73: common.SinkError - (*NatsSinkConfig)(nil), // 74: common.NatsSinkConfig - (*ClickHouseSinkConfig)(nil), // 75: common.ClickHouseSinkConfig - (*KafkaSinkConfig)(nil), // 76: common.KafkaSinkConfig - (*HttpSinkConfig)(nil), // 77: common.HttpSinkConfig - (*DatabricksSinkConfig)(nil), // 78: common.DatabricksSinkConfig - (*DatabricksOAuthM2M)(nil), // 79: common.DatabricksOAuthM2M - (*CreatedLedgerLog)(nil), // 80: common.CreatedLedgerLog - (*DeletedLedgerLog)(nil), // 81: common.DeletedLedgerLog - (*ApplyLedgerLog)(nil), // 82: common.ApplyLedgerLog - (*LedgerLog)(nil), // 83: common.LedgerLog - (*TouchedVolume)(nil), // 84: common.TouchedVolume - (*LedgerLogPayload)(nil), // 85: common.LedgerLogPayload - (*OrderSkippedLog)(nil), // 86: common.OrderSkippedLog - (*CreatedIndexLog)(nil), // 87: common.CreatedIndexLog - (*DroppedIndexLog)(nil), // 88: common.DroppedIndexLog - (*FilledGapLog)(nil), // 89: common.FilledGapLog - (*CreatedTransaction)(nil), // 90: common.CreatedTransaction - (*RevertedTransaction)(nil), // 91: common.RevertedTransaction - (*SavedMetadata)(nil), // 92: common.SavedMetadata - (*DeletedMetadata)(nil), // 93: common.DeletedMetadata - (*SetMetadataFieldTypeLog)(nil), // 94: common.SetMetadataFieldTypeLog - (*RemovedMetadataFieldTypeLog)(nil), // 95: common.RemovedMetadataFieldTypeLog - (*Chapter)(nil), // 96: common.Chapter - (*ClosedChapterLog)(nil), // 97: common.ClosedChapterLog - (*SealedChapterLog)(nil), // 98: common.SealedChapterLog - (*ArchivedChapterLog)(nil), // 99: common.ArchivedChapterLog - (*ConfirmedArchiveChapterLog)(nil), // 100: common.ConfirmedArchiveChapterLog - (*MirrorSourceConfig)(nil), // 101: common.MirrorSourceConfig - (*MirrorRewriteRule)(nil), // 102: common.MirrorRewriteRule - (*CreatedTransactionRule)(nil), // 103: common.CreatedTransactionRule - (*RevertedTransactionRule)(nil), // 104: common.RevertedTransactionRule - (*SavedMetadataRule)(nil), // 105: common.SavedMetadataRule - (*DeletedMetadataRule)(nil), // 106: common.DeletedMetadataRule - (*AnyVariantRule)(nil), // 107: common.AnyVariantRule - (*CreatedTransactionAction)(nil), // 108: common.CreatedTransactionAction - (*RevertedTransactionAction)(nil), // 109: common.RevertedTransactionAction - (*SavedMetadataAction)(nil), // 110: common.SavedMetadataAction - (*DeletedMetadataAction)(nil), // 111: common.DeletedMetadataAction - (*AnyVariantAction)(nil), // 112: common.AnyVariantAction - (*RewriteAddressAction)(nil), // 113: common.RewriteAddressAction - (*SetMetadataAction)(nil), // 114: common.SetMetadataAction - (*DeleteMetadataAction)(nil), // 115: common.DeleteMetadataAction - (*SetAccountMetadataAction)(nil), // 116: common.SetAccountMetadataAction - (*DeleteAccountMetadataAction)(nil), // 117: common.DeleteAccountMetadataAction - (*SetAccountMetadataFromAddressAction)(nil), // 118: common.SetAccountMetadataFromAddressAction - (*SetAccountMetadataFromAddressReplacement)(nil), // 119: common.SetAccountMetadataFromAddressReplacement - (*DropAction)(nil), // 120: common.DropAction - (*HttpMirrorSourceConfig)(nil), // 121: common.HttpMirrorSourceConfig - (*OAuth2ClientCredentials)(nil), // 122: common.OAuth2ClientCredentials - (*PostgresMirrorSourceConfig)(nil), // 123: common.PostgresMirrorSourceConfig - (*PostgresAwsIamAuth)(nil), // 124: common.PostgresAwsIamAuth - (*MirrorSyncError)(nil), // 125: common.MirrorSyncError - (*MirrorSyncProgress)(nil), // 126: common.MirrorSyncProgress - (*LedgerInfo)(nil), // 127: common.LedgerInfo - (*SaveMetadataCommand)(nil), // 128: common.SaveMetadataCommand - (*DeleteMetadataCommand)(nil), // 129: common.DeleteMetadataCommand - (*TransactionState)(nil), // 130: common.TransactionState - (*IdempotencyKeyValue)(nil), // 131: common.IdempotencyKeyValue - (*IdempotencyFailure)(nil), // 132: common.IdempotencyFailure - (*TransactionReferenceValue)(nil), // 133: common.TransactionReferenceValue - (*NumscriptVersionValue)(nil), // 134: common.NumscriptVersionValue - (*SegmentType)(nil), // 135: common.SegmentType - (*UUIDConstraint)(nil), // 136: common.UUIDConstraint - (*Uint64Constraint)(nil), // 137: common.Uint64Constraint - (*BytesConstraint)(nil), // 138: common.BytesConstraint - (*AccountType)(nil), // 139: common.AccountType - (*AddedAccountTypeLog)(nil), // 140: common.AddedAccountTypeLog - (*RemovedAccountTypeLog)(nil), // 141: common.RemovedAccountTypeLog - (*UpdatedDefaultEnforcementModeLog)(nil), // 142: common.UpdatedDefaultEnforcementModeLog - (*QueryFilter)(nil), // 143: common.QueryFilter - (*ReferenceCondition)(nil), // 144: common.ReferenceCondition - (*RevertedCondition)(nil), // 145: common.RevertedCondition - (*AuditCondition)(nil), // 146: common.AuditCondition - (*LedgerCondition)(nil), // 147: common.LedgerCondition - (*LogIdCondition)(nil), // 148: common.LogIdCondition - (*BuiltinUintCondition)(nil), // 149: common.BuiltinUintCondition - (*LogBuiltinUintCondition)(nil), // 150: common.LogBuiltinUintCondition - (*AccountHasAssetCondition)(nil), // 151: common.AccountHasAssetCondition - (*AndFilter)(nil), // 152: common.AndFilter - (*OrFilter)(nil), // 153: common.OrFilter - (*NotFilter)(nil), // 154: common.NotFilter - (*FieldRef)(nil), // 155: common.FieldRef - (*FieldCondition)(nil), // 156: common.FieldCondition - (*StringCondition)(nil), // 157: common.StringCondition - (*IntCondition)(nil), // 158: common.IntCondition - (*UintCondition)(nil), // 159: common.UintCondition - (*BoolCondition)(nil), // 160: common.BoolCondition - (*ExistsCondition)(nil), // 161: common.ExistsCondition - (*AddressMatch)(nil), // 162: common.AddressMatch - (*PreparedQuery)(nil), // 163: common.PreparedQuery - (*AggregatedVolume)(nil), // 164: common.AggregatedVolume - (*AggregateResult)(nil), // 165: common.AggregateResult - (*GroupedAggregateResult)(nil), // 166: common.GroupedAggregateResult - (*PreparedQueryCursor)(nil), // 167: common.PreparedQueryCursor - (*LedgerStats)(nil), // 168: common.LedgerStats - (*PersistedConfig)(nil), // 169: common.PersistedConfig - (*CallerIdentity)(nil), // 170: common.CallerIdentity - (*CallerSnapshot)(nil), // 171: common.CallerSnapshot - (*S3StorageConfig)(nil), // 172: common.S3StorageConfig - (*AzureStorageConfig)(nil), // 173: common.AzureStorageConfig - (*BackupStorage)(nil), // 174: common.BackupStorage - (*ReadOptions)(nil), // 175: common.ReadOptions - (*ListOptions)(nil), // 176: common.ListOptions - nil, // 177: common.MetadataMap.ValuesEntry - nil, // 178: common.Transaction.MetadataEntry - nil, // 179: common.Script.VarsEntry - nil, // 180: common.PostCommitVolumes.VolumesByAccountEntry - nil, // 181: common.Account.MetadataEntry - nil, // 182: common.MetadataSchema.AccountFieldsEntry - nil, // 183: common.MetadataSchema.TransactionFieldsEntry - nil, // 184: common.MetadataSchema.LedgerFieldsEntry - nil, // 185: common.SavedLedgerMetadataLog.MetadataEntry - nil, // 186: common.CreatedLedgerLog.AccountTypesEntry - nil, // 187: common.OrderSkippedLog.ContextEntry - nil, // 188: common.CreatedTransaction.AccountMetadataEntry - nil, // 189: common.SavedMetadata.MetadataEntry - nil, // 190: common.LedgerInfo.AccountTypesEntry - nil, // 191: common.LedgerInfo.MetadataEntry - nil, // 192: common.SaveMetadataCommand.MetadataEntry - nil, // 193: common.TransactionState.MetadataEntry - nil, // 194: common.IdempotencyFailure.MetadataEntry - nil, // 195: common.AccountType.SegmentTypesEntry - (*signaturepb.SignedLog)(nil), // 196: signature.SignedLog - (*descriptorpb.FieldOptions)(nil), // 197: google.protobuf.FieldOptions + (*TemplateUsage)(nil), // 67: common.TemplateUsage + (*SetQueryCheckpointScheduleLog)(nil), // 68: common.SetQueryCheckpointScheduleLog + (*DeletedQueryCheckpointScheduleLog)(nil), // 69: common.DeletedQueryCheckpointScheduleLog + (*CreatedQueryCheckpointLog)(nil), // 70: common.CreatedQueryCheckpointLog + (*DeletedQueryCheckpointLog)(nil), // 71: common.DeletedQueryCheckpointLog + (*SinkConfig)(nil), // 72: common.SinkConfig + (*SinkStatus)(nil), // 73: common.SinkStatus + (*SinkError)(nil), // 74: common.SinkError + (*NatsSinkConfig)(nil), // 75: common.NatsSinkConfig + (*ClickHouseSinkConfig)(nil), // 76: common.ClickHouseSinkConfig + (*KafkaSinkConfig)(nil), // 77: common.KafkaSinkConfig + (*HttpSinkConfig)(nil), // 78: common.HttpSinkConfig + (*DatabricksSinkConfig)(nil), // 79: common.DatabricksSinkConfig + (*DatabricksOAuthM2M)(nil), // 80: common.DatabricksOAuthM2M + (*CreatedLedgerLog)(nil), // 81: common.CreatedLedgerLog + (*DeletedLedgerLog)(nil), // 82: common.DeletedLedgerLog + (*ApplyLedgerLog)(nil), // 83: common.ApplyLedgerLog + (*LedgerLog)(nil), // 84: common.LedgerLog + (*TouchedVolume)(nil), // 85: common.TouchedVolume + (*LedgerLogPayload)(nil), // 86: common.LedgerLogPayload + (*OrderSkippedLog)(nil), // 87: common.OrderSkippedLog + (*CreatedIndexLog)(nil), // 88: common.CreatedIndexLog + (*DroppedIndexLog)(nil), // 89: common.DroppedIndexLog + (*FilledGapLog)(nil), // 90: common.FilledGapLog + (*CreatedTransaction)(nil), // 91: common.CreatedTransaction + (*RevertedTransaction)(nil), // 92: common.RevertedTransaction + (*SavedMetadata)(nil), // 93: common.SavedMetadata + (*DeletedMetadata)(nil), // 94: common.DeletedMetadata + (*SetMetadataFieldTypeLog)(nil), // 95: common.SetMetadataFieldTypeLog + (*RemovedMetadataFieldTypeLog)(nil), // 96: common.RemovedMetadataFieldTypeLog + (*Chapter)(nil), // 97: common.Chapter + (*ClosedChapterLog)(nil), // 98: common.ClosedChapterLog + (*SealedChapterLog)(nil), // 99: common.SealedChapterLog + (*ArchivedChapterLog)(nil), // 100: common.ArchivedChapterLog + (*ConfirmedArchiveChapterLog)(nil), // 101: common.ConfirmedArchiveChapterLog + (*MirrorSourceConfig)(nil), // 102: common.MirrorSourceConfig + (*MirrorRewriteRule)(nil), // 103: common.MirrorRewriteRule + (*CreatedTransactionRule)(nil), // 104: common.CreatedTransactionRule + (*RevertedTransactionRule)(nil), // 105: common.RevertedTransactionRule + (*SavedMetadataRule)(nil), // 106: common.SavedMetadataRule + (*DeletedMetadataRule)(nil), // 107: common.DeletedMetadataRule + (*AnyVariantRule)(nil), // 108: common.AnyVariantRule + (*CreatedTransactionAction)(nil), // 109: common.CreatedTransactionAction + (*RevertedTransactionAction)(nil), // 110: common.RevertedTransactionAction + (*SavedMetadataAction)(nil), // 111: common.SavedMetadataAction + (*DeletedMetadataAction)(nil), // 112: common.DeletedMetadataAction + (*AnyVariantAction)(nil), // 113: common.AnyVariantAction + (*RewriteAddressAction)(nil), // 114: common.RewriteAddressAction + (*SetMetadataAction)(nil), // 115: common.SetMetadataAction + (*DeleteMetadataAction)(nil), // 116: common.DeleteMetadataAction + (*SetAccountMetadataAction)(nil), // 117: common.SetAccountMetadataAction + (*DeleteAccountMetadataAction)(nil), // 118: common.DeleteAccountMetadataAction + (*SetAccountMetadataFromAddressAction)(nil), // 119: common.SetAccountMetadataFromAddressAction + (*SetAccountMetadataFromAddressReplacement)(nil), // 120: common.SetAccountMetadataFromAddressReplacement + (*DropAction)(nil), // 121: common.DropAction + (*HttpMirrorSourceConfig)(nil), // 122: common.HttpMirrorSourceConfig + (*OAuth2ClientCredentials)(nil), // 123: common.OAuth2ClientCredentials + (*PostgresMirrorSourceConfig)(nil), // 124: common.PostgresMirrorSourceConfig + (*PostgresAwsIamAuth)(nil), // 125: common.PostgresAwsIamAuth + (*MirrorSyncError)(nil), // 126: common.MirrorSyncError + (*MirrorSyncProgress)(nil), // 127: common.MirrorSyncProgress + (*LedgerInfo)(nil), // 128: common.LedgerInfo + (*SaveMetadataCommand)(nil), // 129: common.SaveMetadataCommand + (*DeleteMetadataCommand)(nil), // 130: common.DeleteMetadataCommand + (*TransactionState)(nil), // 131: common.TransactionState + (*IdempotencyKeyValue)(nil), // 132: common.IdempotencyKeyValue + (*IdempotencyFailure)(nil), // 133: common.IdempotencyFailure + (*TransactionReferenceValue)(nil), // 134: common.TransactionReferenceValue + (*NumscriptVersionValue)(nil), // 135: common.NumscriptVersionValue + (*SegmentType)(nil), // 136: common.SegmentType + (*UUIDConstraint)(nil), // 137: common.UUIDConstraint + (*Uint64Constraint)(nil), // 138: common.Uint64Constraint + (*BytesConstraint)(nil), // 139: common.BytesConstraint + (*AccountType)(nil), // 140: common.AccountType + (*AddedAccountTypeLog)(nil), // 141: common.AddedAccountTypeLog + (*RemovedAccountTypeLog)(nil), // 142: common.RemovedAccountTypeLog + (*UpdatedDefaultEnforcementModeLog)(nil), // 143: common.UpdatedDefaultEnforcementModeLog + (*QueryFilter)(nil), // 144: common.QueryFilter + (*ReferenceCondition)(nil), // 145: common.ReferenceCondition + (*RevertedCondition)(nil), // 146: common.RevertedCondition + (*AuditCondition)(nil), // 147: common.AuditCondition + (*LedgerCondition)(nil), // 148: common.LedgerCondition + (*LogIdCondition)(nil), // 149: common.LogIdCondition + (*BuiltinUintCondition)(nil), // 150: common.BuiltinUintCondition + (*LogBuiltinUintCondition)(nil), // 151: common.LogBuiltinUintCondition + (*AccountHasAssetCondition)(nil), // 152: common.AccountHasAssetCondition + (*AndFilter)(nil), // 153: common.AndFilter + (*OrFilter)(nil), // 154: common.OrFilter + (*NotFilter)(nil), // 155: common.NotFilter + (*FieldRef)(nil), // 156: common.FieldRef + (*FieldCondition)(nil), // 157: common.FieldCondition + (*StringCondition)(nil), // 158: common.StringCondition + (*IntCondition)(nil), // 159: common.IntCondition + (*UintCondition)(nil), // 160: common.UintCondition + (*BoolCondition)(nil), // 161: common.BoolCondition + (*ExistsCondition)(nil), // 162: common.ExistsCondition + (*AddressMatch)(nil), // 163: common.AddressMatch + (*PreparedQuery)(nil), // 164: common.PreparedQuery + (*AggregatedVolume)(nil), // 165: common.AggregatedVolume + (*AggregateResult)(nil), // 166: common.AggregateResult + (*GroupedAggregateResult)(nil), // 167: common.GroupedAggregateResult + (*PreparedQueryCursor)(nil), // 168: common.PreparedQueryCursor + (*LedgerStats)(nil), // 169: common.LedgerStats + (*PersistedConfig)(nil), // 170: common.PersistedConfig + (*CallerIdentity)(nil), // 171: common.CallerIdentity + (*CallerSnapshot)(nil), // 172: common.CallerSnapshot + (*S3StorageConfig)(nil), // 173: common.S3StorageConfig + (*AzureStorageConfig)(nil), // 174: common.AzureStorageConfig + (*BackupStorage)(nil), // 175: common.BackupStorage + (*ReadOptions)(nil), // 176: common.ReadOptions + (*ListOptions)(nil), // 177: common.ListOptions + nil, // 178: common.MetadataMap.ValuesEntry + nil, // 179: common.Transaction.MetadataEntry + nil, // 180: common.Script.VarsEntry + nil, // 181: common.PostCommitVolumes.VolumesByAccountEntry + nil, // 182: common.Account.MetadataEntry + nil, // 183: common.MetadataSchema.AccountFieldsEntry + nil, // 184: common.MetadataSchema.TransactionFieldsEntry + nil, // 185: common.MetadataSchema.LedgerFieldsEntry + nil, // 186: common.SavedLedgerMetadataLog.MetadataEntry + nil, // 187: common.CreatedLedgerLog.AccountTypesEntry + nil, // 188: common.OrderSkippedLog.ContextEntry + nil, // 189: common.CreatedTransaction.AccountMetadataEntry + nil, // 190: common.SavedMetadata.MetadataEntry + nil, // 191: common.LedgerInfo.AccountTypesEntry + nil, // 192: common.LedgerInfo.MetadataEntry + nil, // 193: common.SaveMetadataCommand.MetadataEntry + nil, // 194: common.TransactionState.MetadataEntry + nil, // 195: common.IdempotencyFailure.MetadataEntry + nil, // 196: common.AccountType.SegmentTypesEntry + (*signaturepb.SignedLog)(nil), // 197: signature.SignedLog + (*descriptorpb.FieldOptions)(nil), // 198: google.protobuf.FieldOptions } var file_common_proto_depIdxs = []int32{ 19, // 0: common.MetadataValue.null_value:type_name -> common.NullValue - 177, // 1: common.MetadataMap.values:type_name -> common.MetadataMap.ValuesEntry + 178, // 1: common.MetadataMap.values:type_name -> common.MetadataMap.ValuesEntry 23, // 2: common.Posting.amount:type_name -> common.Uint256 24, // 3: common.Transaction.postings:type_name -> common.Posting - 178, // 4: common.Transaction.metadata:type_name -> common.Transaction.MetadataEntry + 179, // 4: common.Transaction.metadata:type_name -> common.Transaction.MetadataEntry 18, // 5: common.Transaction.timestamp:type_name -> common.Timestamp 18, // 6: common.Transaction.inserted_at:type_name -> common.Timestamp 18, // 7: common.Transaction.updated_at:type_name -> common.Timestamp 18, // 8: common.Transaction.reverted_at:type_name -> common.Timestamp - 179, // 9: common.Script.vars:type_name -> common.Script.VarsEntry + 180, // 9: common.Script.vars:type_name -> common.Script.VarsEntry 30, // 10: common.VolumesByAssets.volumes:type_name -> common.VolumeEntry 27, // 11: common.VolumeEntry.volumes:type_name -> common.Volumes - 180, // 12: common.PostCommitVolumes.volumes_by_account:type_name -> common.PostCommitVolumes.VolumesByAccountEntry + 181, // 12: common.PostCommitVolumes.volumes_by_account:type_name -> common.PostCommitVolumes.VolumesByAccountEntry 28, // 13: common.AccountVolume.volumes:type_name -> common.VolumesWithBalance - 181, // 14: common.Account.metadata:type_name -> common.Account.MetadataEntry + 182, // 14: common.Account.metadata:type_name -> common.Account.MetadataEntry 18, // 15: common.Account.first_usage:type_name -> common.Timestamp 18, // 16: common.Account.insertion_date:type_name -> common.Timestamp 18, // 17: common.Account.updated_at:type_name -> common.Timestamp 32, // 18: common.Account.volumes:type_name -> common.AccountVolume 34, // 19: common.Target.account:type_name -> common.TargetAccount 1, // 20: common.MetadataFieldSchema.type:type_name -> common.MetadataType - 182, // 21: common.MetadataSchema.account_fields:type_name -> common.MetadataSchema.AccountFieldsEntry - 183, // 22: common.MetadataSchema.transaction_fields:type_name -> common.MetadataSchema.TransactionFieldsEntry - 184, // 23: common.MetadataSchema.ledger_fields:type_name -> common.MetadataSchema.LedgerFieldsEntry + 183, // 21: common.MetadataSchema.account_fields:type_name -> common.MetadataSchema.AccountFieldsEntry + 184, // 22: common.MetadataSchema.transaction_fields:type_name -> common.MetadataSchema.TransactionFieldsEntry + 185, // 23: common.MetadataSchema.ledger_fields:type_name -> common.MetadataSchema.LedgerFieldsEntry 0, // 24: common.SetMetadataFieldTypeCommand.target_type:type_name -> common.TargetType 1, // 25: common.SetMetadataFieldTypeCommand.type:type_name -> common.MetadataType 0, // 26: common.MetadataIndexID.target:type_name -> common.TargetType @@ -14057,19 +14138,19 @@ var file_common_proto_depIdxs = []int32{ 18, // 33: common.Index.created_at:type_name -> common.Timestamp 18, // 34: common.Index.last_built_at:type_name -> common.Timestamp 45, // 35: common.Log.payload:type_name -> common.LogPayload - 196, // 36: common.Log.response_signature:type_name -> signature.SignedLog - 80, // 37: common.LogPayload.create_ledger:type_name -> common.CreatedLedgerLog - 81, // 38: common.LogPayload.delete_ledger:type_name -> common.DeletedLedgerLog - 82, // 39: common.LogPayload.apply:type_name -> common.ApplyLedgerLog + 197, // 36: common.Log.response_signature:type_name -> signature.SignedLog + 81, // 37: common.LogPayload.create_ledger:type_name -> common.CreatedLedgerLog + 82, // 38: common.LogPayload.delete_ledger:type_name -> common.DeletedLedgerLog + 83, // 39: common.LogPayload.apply:type_name -> common.ApplyLedgerLog 47, // 40: common.LogPayload.register_signing_key:type_name -> common.RegisteredSigningKeyLog 48, // 41: common.LogPayload.revoke_signing_key:type_name -> common.RevokedSigningKeyLog 50, // 42: common.LogPayload.set_signing_config:type_name -> common.SetSigningConfigLog 51, // 43: common.LogPayload.added_events_sink:type_name -> common.AddedEventsSinkLog 52, // 44: common.LogPayload.removed_events_sink:type_name -> common.RemovedEventsSinkLog - 97, // 45: common.LogPayload.close_chapter:type_name -> common.ClosedChapterLog - 98, // 46: common.LogPayload.seal_chapter:type_name -> common.SealedChapterLog - 99, // 47: common.LogPayload.archive_chapter:type_name -> common.ArchivedChapterLog - 100, // 48: common.LogPayload.confirm_archive_chapter:type_name -> common.ConfirmedArchiveChapterLog + 98, // 45: common.LogPayload.close_chapter:type_name -> common.ClosedChapterLog + 99, // 46: common.LogPayload.seal_chapter:type_name -> common.SealedChapterLog + 100, // 47: common.LogPayload.archive_chapter:type_name -> common.ArchivedChapterLog + 101, // 48: common.LogPayload.confirm_archive_chapter:type_name -> common.ConfirmedArchiveChapterLog 53, // 49: common.LogPayload.set_maintenance_mode:type_name -> common.SetMaintenanceModeLog 57, // 50: common.LogPayload.set_chapter_schedule:type_name -> common.SetChapterScheduleLog 58, // 51: common.LogPayload.delete_chapter_schedule:type_name -> common.DeletedChapterScheduleLog @@ -14079,13 +14160,13 @@ var file_common_proto_depIdxs = []int32{ 61, // 55: common.LogPayload.deleted_prepared_query:type_name -> common.DeletedPreparedQueryLog 65, // 56: common.LogPayload.saved_numscript:type_name -> common.SavedNumscriptLog 66, // 57: common.LogPayload.deleted_numscript:type_name -> common.DeletedNumscriptLog - 69, // 58: common.LogPayload.created_query_checkpoint:type_name -> common.CreatedQueryCheckpointLog - 70, // 59: common.LogPayload.deleted_query_checkpoint:type_name -> common.DeletedQueryCheckpointLog - 67, // 60: common.LogPayload.set_query_checkpoint_schedule:type_name -> common.SetQueryCheckpointScheduleLog - 68, // 61: common.LogPayload.delete_query_checkpoint_schedule:type_name -> common.DeletedQueryCheckpointScheduleLog + 70, // 58: common.LogPayload.created_query_checkpoint:type_name -> common.CreatedQueryCheckpointLog + 71, // 59: common.LogPayload.deleted_query_checkpoint:type_name -> common.DeletedQueryCheckpointLog + 68, // 60: common.LogPayload.set_query_checkpoint_schedule:type_name -> common.SetQueryCheckpointScheduleLog + 69, // 61: common.LogPayload.delete_query_checkpoint_schedule:type_name -> common.DeletedQueryCheckpointScheduleLog 62, // 62: common.LogPayload.saved_ledger_metadata:type_name -> common.SavedLedgerMetadataLog 63, // 63: common.LogPayload.deleted_ledger_metadata:type_name -> common.DeletedLedgerMetadataLog - 71, // 64: common.AddedEventsSinkLog.config:type_name -> common.SinkConfig + 72, // 64: common.AddedEventsSinkLog.config:type_name -> common.SinkConfig 54, // 65: common.ClusterConfig.bloom_volumes:type_name -> common.BloomTypeConfig 54, // 66: common.ClusterConfig.bloom_metadata:type_name -> common.BloomTypeConfig 54, // 67: common.ClusterConfig.bloom_references:type_name -> common.BloomTypeConfig @@ -14100,205 +14181,208 @@ var file_common_proto_depIdxs = []int32{ 54, // 76: common.ClusterConfig.bloom_prepared_queries:type_name -> common.BloomTypeConfig 54, // 77: common.ClusterConfig.bloom_indexes:type_name -> common.BloomTypeConfig 55, // 78: common.PersistedClusterState.config:type_name -> common.ClusterConfig - 163, // 79: common.CreatedPreparedQueryLog.query:type_name -> common.PreparedQuery - 143, // 80: common.UpdatedPreparedQueryLog.previous_filter:type_name -> common.QueryFilter - 143, // 81: common.UpdatedPreparedQueryLog.new_filter:type_name -> common.QueryFilter - 185, // 82: common.SavedLedgerMetadataLog.metadata:type_name -> common.SavedLedgerMetadataLog.MetadataEntry + 164, // 79: common.CreatedPreparedQueryLog.query:type_name -> common.PreparedQuery + 144, // 80: common.UpdatedPreparedQueryLog.previous_filter:type_name -> common.QueryFilter + 144, // 81: common.UpdatedPreparedQueryLog.new_filter:type_name -> common.QueryFilter + 186, // 82: common.SavedLedgerMetadataLog.metadata:type_name -> common.SavedLedgerMetadataLog.MetadataEntry 18, // 83: common.NumscriptInfo.created_at:type_name -> common.Timestamp 64, // 84: common.SavedNumscriptLog.info:type_name -> common.NumscriptInfo - 74, // 85: common.SinkConfig.nats:type_name -> common.NatsSinkConfig - 75, // 86: common.SinkConfig.clickhouse:type_name -> common.ClickHouseSinkConfig - 76, // 87: common.SinkConfig.kafka:type_name -> common.KafkaSinkConfig - 77, // 88: common.SinkConfig.http:type_name -> common.HttpSinkConfig - 78, // 89: common.SinkConfig.databricks:type_name -> common.DatabricksSinkConfig - 7, // 90: common.SinkConfig.event_types:type_name -> common.EventType - 73, // 91: common.SinkStatus.error:type_name -> common.SinkError - 18, // 92: common.SinkError.occurred_at:type_name -> common.Timestamp - 79, // 93: common.DatabricksSinkConfig.oauth_m2m:type_name -> common.DatabricksOAuthM2M - 18, // 94: common.CreatedLedgerLog.created_at:type_name -> common.Timestamp - 37, // 95: common.CreatedLedgerLog.metadata_schema:type_name -> common.MetadataSchema - 9, // 96: common.CreatedLedgerLog.mode:type_name -> common.LedgerMode - 101, // 97: common.CreatedLedgerLog.mirror_source:type_name -> common.MirrorSourceConfig - 186, // 98: common.CreatedLedgerLog.account_types:type_name -> common.CreatedLedgerLog.AccountTypesEntry - 12, // 99: common.CreatedLedgerLog.default_enforcement_mode:type_name -> common.ChartEnforcementMode - 18, // 100: common.DeletedLedgerLog.deleted_at:type_name -> common.Timestamp - 83, // 101: common.ApplyLedgerLog.log:type_name -> common.LedgerLog - 85, // 102: common.LedgerLog.data:type_name -> common.LedgerLogPayload - 18, // 103: common.LedgerLog.date:type_name -> common.Timestamp - 84, // 104: common.LedgerLog.purged_volumes:type_name -> common.TouchedVolume - 90, // 105: common.LedgerLogPayload.created_transaction:type_name -> common.CreatedTransaction - 91, // 106: common.LedgerLogPayload.reverted_transaction:type_name -> common.RevertedTransaction - 92, // 107: common.LedgerLogPayload.saved_metadata:type_name -> common.SavedMetadata - 93, // 108: common.LedgerLogPayload.deleted_metadata:type_name -> common.DeletedMetadata - 94, // 109: common.LedgerLogPayload.set_metadata_field_type:type_name -> common.SetMetadataFieldTypeLog - 95, // 110: common.LedgerLogPayload.removed_metadata_field_type:type_name -> common.RemovedMetadataFieldTypeLog - 89, // 111: common.LedgerLogPayload.fill_gap:type_name -> common.FilledGapLog - 87, // 112: common.LedgerLogPayload.create_index:type_name -> common.CreatedIndexLog - 88, // 113: common.LedgerLogPayload.drop_index:type_name -> common.DroppedIndexLog - 140, // 114: common.LedgerLogPayload.added_account_type:type_name -> common.AddedAccountTypeLog - 141, // 115: common.LedgerLogPayload.removed_account_type:type_name -> common.RemovedAccountTypeLog - 142, // 116: common.LedgerLogPayload.updated_default_enforcement_mode:type_name -> common.UpdatedDefaultEnforcementModeLog - 86, // 117: common.LedgerLogPayload.order_skipped:type_name -> common.OrderSkippedLog - 11, // 118: common.OrderSkippedLog.reason:type_name -> common.ErrorReason - 187, // 119: common.OrderSkippedLog.context:type_name -> common.OrderSkippedLog.ContextEntry - 40, // 120: common.CreatedIndexLog.id:type_name -> common.IndexID - 40, // 121: common.DroppedIndexLog.id:type_name -> common.IndexID - 25, // 122: common.CreatedTransaction.transaction:type_name -> common.Transaction - 188, // 123: common.CreatedTransaction.account_metadata:type_name -> common.CreatedTransaction.AccountMetadataEntry - 31, // 124: common.CreatedTransaction.post_commit_volumes:type_name -> common.PostCommitVolumes - 25, // 125: common.RevertedTransaction.revert_transaction:type_name -> common.Transaction - 31, // 126: common.RevertedTransaction.post_commit_volumes:type_name -> common.PostCommitVolumes - 35, // 127: common.SavedMetadata.target:type_name -> common.Target - 189, // 128: common.SavedMetadata.metadata:type_name -> common.SavedMetadata.MetadataEntry - 35, // 129: common.DeletedMetadata.target:type_name -> common.Target - 0, // 130: common.SetMetadataFieldTypeLog.target_type:type_name -> common.TargetType - 1, // 131: common.SetMetadataFieldTypeLog.type:type_name -> common.MetadataType - 0, // 132: common.RemovedMetadataFieldTypeLog.target_type:type_name -> common.TargetType - 40, // 133: common.RemovedMetadataFieldTypeLog.dropped_index:type_name -> common.IndexID - 18, // 134: common.Chapter.start:type_name -> common.Timestamp - 18, // 135: common.Chapter.end:type_name -> common.Timestamp - 8, // 136: common.Chapter.status:type_name -> common.ChapterStatus - 96, // 137: common.ClosedChapterLog.closed_chapter:type_name -> common.Chapter - 96, // 138: common.ClosedChapterLog.new_chapter:type_name -> common.Chapter - 96, // 139: common.SealedChapterLog.chapter:type_name -> common.Chapter - 96, // 140: common.ArchivedChapterLog.chapter:type_name -> common.Chapter - 96, // 141: common.ConfirmedArchiveChapterLog.chapter:type_name -> common.Chapter - 121, // 142: common.MirrorSourceConfig.http:type_name -> common.HttpMirrorSourceConfig - 123, // 143: common.MirrorSourceConfig.postgres:type_name -> common.PostgresMirrorSourceConfig - 102, // 144: common.MirrorSourceConfig.rewrite_rules:type_name -> common.MirrorRewriteRule - 103, // 145: common.MirrorRewriteRule.created_transaction:type_name -> common.CreatedTransactionRule - 104, // 146: common.MirrorRewriteRule.reverted_transaction:type_name -> common.RevertedTransactionRule - 105, // 147: common.MirrorRewriteRule.saved_metadata:type_name -> common.SavedMetadataRule - 106, // 148: common.MirrorRewriteRule.deleted_metadata:type_name -> common.DeletedMetadataRule - 107, // 149: common.MirrorRewriteRule.any_variant:type_name -> common.AnyVariantRule - 108, // 150: common.CreatedTransactionRule.actions:type_name -> common.CreatedTransactionAction - 109, // 151: common.RevertedTransactionRule.actions:type_name -> common.RevertedTransactionAction - 110, // 152: common.SavedMetadataRule.actions:type_name -> common.SavedMetadataAction - 111, // 153: common.DeletedMetadataRule.actions:type_name -> common.DeletedMetadataAction - 112, // 154: common.AnyVariantRule.actions:type_name -> common.AnyVariantAction - 113, // 155: common.CreatedTransactionAction.rewrite_address:type_name -> common.RewriteAddressAction - 114, // 156: common.CreatedTransactionAction.set_metadata:type_name -> common.SetMetadataAction - 115, // 157: common.CreatedTransactionAction.delete_metadata:type_name -> common.DeleteMetadataAction - 116, // 158: common.CreatedTransactionAction.set_account_metadata:type_name -> common.SetAccountMetadataAction - 117, // 159: common.CreatedTransactionAction.delete_account_metadata:type_name -> common.DeleteAccountMetadataAction - 118, // 160: common.CreatedTransactionAction.set_account_metadata_from_address:type_name -> common.SetAccountMetadataFromAddressAction - 120, // 161: common.CreatedTransactionAction.drop:type_name -> common.DropAction - 113, // 162: common.RevertedTransactionAction.rewrite_address:type_name -> common.RewriteAddressAction - 114, // 163: common.RevertedTransactionAction.set_metadata:type_name -> common.SetMetadataAction - 115, // 164: common.RevertedTransactionAction.delete_metadata:type_name -> common.DeleteMetadataAction - 120, // 165: common.RevertedTransactionAction.drop:type_name -> common.DropAction - 113, // 166: common.SavedMetadataAction.rewrite_address:type_name -> common.RewriteAddressAction - 114, // 167: common.SavedMetadataAction.set_metadata:type_name -> common.SetMetadataAction - 115, // 168: common.SavedMetadataAction.delete_metadata:type_name -> common.DeleteMetadataAction - 120, // 169: common.SavedMetadataAction.drop:type_name -> common.DropAction - 113, // 170: common.DeletedMetadataAction.rewrite_address:type_name -> common.RewriteAddressAction - 120, // 171: common.DeletedMetadataAction.drop:type_name -> common.DropAction - 113, // 172: common.AnyVariantAction.rewrite_address:type_name -> common.RewriteAddressAction - 120, // 173: common.AnyVariantAction.drop:type_name -> common.DropAction - 119, // 174: common.SetAccountMetadataFromAddressAction.replacements:type_name -> common.SetAccountMetadataFromAddressReplacement - 122, // 175: common.HttpMirrorSourceConfig.oauth2_client_credentials:type_name -> common.OAuth2ClientCredentials - 124, // 176: common.PostgresMirrorSourceConfig.aws_iam_auth:type_name -> common.PostgresAwsIamAuth - 18, // 177: common.MirrorSyncError.occurred_at:type_name -> common.Timestamp - 10, // 178: common.MirrorSyncProgress.state:type_name -> common.MirrorSyncState - 125, // 179: common.MirrorSyncProgress.error:type_name -> common.MirrorSyncError - 18, // 180: common.LedgerInfo.created_at:type_name -> common.Timestamp - 18, // 181: common.LedgerInfo.deleted_at:type_name -> common.Timestamp - 37, // 182: common.LedgerInfo.metadata_schema:type_name -> common.MetadataSchema - 9, // 183: common.LedgerInfo.mode:type_name -> common.LedgerMode - 101, // 184: common.LedgerInfo.mirror_source:type_name -> common.MirrorSourceConfig - 126, // 185: common.LedgerInfo.mirror_sync_progress:type_name -> common.MirrorSyncProgress - 190, // 186: common.LedgerInfo.account_types:type_name -> common.LedgerInfo.AccountTypesEntry - 12, // 187: common.LedgerInfo.default_enforcement_mode:type_name -> common.ChartEnforcementMode - 191, // 188: common.LedgerInfo.metadata:type_name -> common.LedgerInfo.MetadataEntry - 35, // 189: common.SaveMetadataCommand.target:type_name -> common.Target - 192, // 190: common.SaveMetadataCommand.metadata:type_name -> common.SaveMetadataCommand.MetadataEntry - 35, // 191: common.DeleteMetadataCommand.target:type_name -> common.Target - 193, // 192: common.TransactionState.metadata:type_name -> common.TransactionState.MetadataEntry - 18, // 193: common.TransactionState.timestamp:type_name -> common.Timestamp - 24, // 194: common.TransactionState.postings:type_name -> common.Posting - 18, // 195: common.TransactionState.reverted_at:type_name -> common.Timestamp - 132, // 196: common.IdempotencyKeyValue.failure:type_name -> common.IdempotencyFailure - 11, // 197: common.IdempotencyFailure.reason:type_name -> common.ErrorReason - 194, // 198: common.IdempotencyFailure.metadata:type_name -> common.IdempotencyFailure.MetadataEntry - 136, // 199: common.SegmentType.uuid:type_name -> common.UUIDConstraint - 137, // 200: common.SegmentType.uint64:type_name -> common.Uint64Constraint - 138, // 201: common.SegmentType.bytes:type_name -> common.BytesConstraint - 13, // 202: common.AccountType.persistence:type_name -> common.AccountTypePersistence - 195, // 203: common.AccountType.segment_types:type_name -> common.AccountType.SegmentTypesEntry - 139, // 204: common.AddedAccountTypeLog.account_type:type_name -> common.AccountType - 12, // 205: common.UpdatedDefaultEnforcementModeLog.enforcement_mode:type_name -> common.ChartEnforcementMode - 156, // 206: common.QueryFilter.field:type_name -> common.FieldCondition - 162, // 207: common.QueryFilter.address:type_name -> common.AddressMatch - 152, // 208: common.QueryFilter.and:type_name -> common.AndFilter - 153, // 209: common.QueryFilter.or:type_name -> common.OrFilter - 154, // 210: common.QueryFilter.not:type_name -> common.NotFilter - 144, // 211: common.QueryFilter.reference:type_name -> common.ReferenceCondition - 149, // 212: common.QueryFilter.builtin_uint:type_name -> common.BuiltinUintCondition - 147, // 213: common.QueryFilter.ledger:type_name -> common.LedgerCondition - 148, // 214: common.QueryFilter.log_id:type_name -> common.LogIdCondition - 150, // 215: common.QueryFilter.log_builtin_uint:type_name -> common.LogBuiltinUintCondition - 151, // 216: common.QueryFilter.account_has_asset:type_name -> common.AccountHasAssetCondition - 145, // 217: common.QueryFilter.reverted:type_name -> common.RevertedCondition - 146, // 218: common.QueryFilter.audit:type_name -> common.AuditCondition - 157, // 219: common.ReferenceCondition.cond:type_name -> common.StringCondition - 14, // 220: common.AuditCondition.field:type_name -> common.AuditField - 157, // 221: common.AuditCondition.string_cond:type_name -> common.StringCondition - 159, // 222: common.AuditCondition.uint_cond:type_name -> common.UintCondition - 157, // 223: common.LedgerCondition.cond:type_name -> common.StringCondition - 159, // 224: common.LogIdCondition.cond:type_name -> common.UintCondition - 3, // 225: common.BuiltinUintCondition.field:type_name -> common.TransactionBuiltinIndex - 159, // 226: common.BuiltinUintCondition.cond:type_name -> common.UintCondition - 5, // 227: common.LogBuiltinUintCondition.field:type_name -> common.LogBuiltinIndex - 159, // 228: common.LogBuiltinUintCondition.cond:type_name -> common.UintCondition - 143, // 229: common.AndFilter.filters:type_name -> common.QueryFilter - 143, // 230: common.OrFilter.filters:type_name -> common.QueryFilter - 143, // 231: common.NotFilter.filter:type_name -> common.QueryFilter - 155, // 232: common.FieldCondition.field:type_name -> common.FieldRef - 157, // 233: common.FieldCondition.string_cond:type_name -> common.StringCondition - 158, // 234: common.FieldCondition.int_cond:type_name -> common.IntCondition - 159, // 235: common.FieldCondition.uint_cond:type_name -> common.UintCondition - 160, // 236: common.FieldCondition.bool_cond:type_name -> common.BoolCondition - 161, // 237: common.FieldCondition.exists_cond:type_name -> common.ExistsCondition - 15, // 238: common.AddressMatch.role:type_name -> common.AddressRole - 143, // 239: common.PreparedQuery.filter:type_name -> common.QueryFilter - 16, // 240: common.PreparedQuery.target:type_name -> common.QueryTarget - 23, // 241: common.AggregatedVolume.input:type_name -> common.Uint256 - 23, // 242: common.AggregatedVolume.output:type_name -> common.Uint256 - 164, // 243: common.AggregateResult.volumes:type_name -> common.AggregatedVolume - 166, // 244: common.AggregateResult.groups:type_name -> common.GroupedAggregateResult - 164, // 245: common.GroupedAggregateResult.volumes:type_name -> common.AggregatedVolume - 33, // 246: common.PreparedQueryCursor.account_data:type_name -> common.Account - 25, // 247: common.PreparedQueryCursor.transaction_data:type_name -> common.Transaction - 44, // 248: common.PreparedQueryCursor.log_data:type_name -> common.Log - 170, // 249: common.CallerSnapshot.identity:type_name -> common.CallerIdentity - 172, // 250: common.BackupStorage.s3:type_name -> common.S3StorageConfig - 173, // 251: common.BackupStorage.azure:type_name -> common.AzureStorageConfig - 175, // 252: common.ListOptions.read:type_name -> common.ReadOptions - 143, // 253: common.ListOptions.filter:type_name -> common.QueryFilter - 20, // 254: common.MetadataMap.ValuesEntry.value:type_name -> common.MetadataValue - 20, // 255: common.Transaction.MetadataEntry.value:type_name -> common.MetadataValue - 29, // 256: common.PostCommitVolumes.VolumesByAccountEntry.value:type_name -> common.VolumesByAssets - 20, // 257: common.Account.MetadataEntry.value:type_name -> common.MetadataValue - 36, // 258: common.MetadataSchema.AccountFieldsEntry.value:type_name -> common.MetadataFieldSchema - 36, // 259: common.MetadataSchema.TransactionFieldsEntry.value:type_name -> common.MetadataFieldSchema - 36, // 260: common.MetadataSchema.LedgerFieldsEntry.value:type_name -> common.MetadataFieldSchema - 20, // 261: common.SavedLedgerMetadataLog.MetadataEntry.value:type_name -> common.MetadataValue - 139, // 262: common.CreatedLedgerLog.AccountTypesEntry.value:type_name -> common.AccountType - 21, // 263: common.CreatedTransaction.AccountMetadataEntry.value:type_name -> common.MetadataMap - 20, // 264: common.SavedMetadata.MetadataEntry.value:type_name -> common.MetadataValue - 139, // 265: common.LedgerInfo.AccountTypesEntry.value:type_name -> common.AccountType - 20, // 266: common.LedgerInfo.MetadataEntry.value:type_name -> common.MetadataValue - 20, // 267: common.SaveMetadataCommand.MetadataEntry.value:type_name -> common.MetadataValue - 20, // 268: common.TransactionState.MetadataEntry.value:type_name -> common.MetadataValue - 135, // 269: common.AccountType.SegmentTypesEntry.value:type_name -> common.SegmentType - 197, // 270: common.allowed_query_targets:extendee -> google.protobuf.FieldOptions - 197, // 271: common.valid_on_no_query_target:extendee -> google.protobuf.FieldOptions - 16, // 272: common.allowed_query_targets:type_name -> common.QueryTarget - 273, // [273:273] is the sub-list for method output_type - 273, // [273:273] is the sub-list for method input_type - 272, // [272:273] is the sub-list for extension type_name - 270, // [270:272] is the sub-list for extension extendee - 0, // [0:270] is the sub-list for field type_name + 18, // 85: common.TemplateUsage.last_used:type_name -> common.Timestamp + 75, // 86: common.SinkConfig.nats:type_name -> common.NatsSinkConfig + 76, // 87: common.SinkConfig.clickhouse:type_name -> common.ClickHouseSinkConfig + 77, // 88: common.SinkConfig.kafka:type_name -> common.KafkaSinkConfig + 78, // 89: common.SinkConfig.http:type_name -> common.HttpSinkConfig + 79, // 90: common.SinkConfig.databricks:type_name -> common.DatabricksSinkConfig + 7, // 91: common.SinkConfig.event_types:type_name -> common.EventType + 74, // 92: common.SinkStatus.error:type_name -> common.SinkError + 18, // 93: common.SinkError.occurred_at:type_name -> common.Timestamp + 80, // 94: common.DatabricksSinkConfig.oauth_m2m:type_name -> common.DatabricksOAuthM2M + 18, // 95: common.CreatedLedgerLog.created_at:type_name -> common.Timestamp + 37, // 96: common.CreatedLedgerLog.metadata_schema:type_name -> common.MetadataSchema + 9, // 97: common.CreatedLedgerLog.mode:type_name -> common.LedgerMode + 102, // 98: common.CreatedLedgerLog.mirror_source:type_name -> common.MirrorSourceConfig + 187, // 99: common.CreatedLedgerLog.account_types:type_name -> common.CreatedLedgerLog.AccountTypesEntry + 12, // 100: common.CreatedLedgerLog.default_enforcement_mode:type_name -> common.ChartEnforcementMode + 18, // 101: common.DeletedLedgerLog.deleted_at:type_name -> common.Timestamp + 84, // 102: common.ApplyLedgerLog.log:type_name -> common.LedgerLog + 86, // 103: common.LedgerLog.data:type_name -> common.LedgerLogPayload + 18, // 104: common.LedgerLog.date:type_name -> common.Timestamp + 85, // 105: common.LedgerLog.purged_volumes:type_name -> common.TouchedVolume + 85, // 106: common.LedgerLog.new_kept_volumes:type_name -> common.TouchedVolume + 85, // 107: common.LedgerLog.ephemeral_volumes:type_name -> common.TouchedVolume + 91, // 108: common.LedgerLogPayload.created_transaction:type_name -> common.CreatedTransaction + 92, // 109: common.LedgerLogPayload.reverted_transaction:type_name -> common.RevertedTransaction + 93, // 110: common.LedgerLogPayload.saved_metadata:type_name -> common.SavedMetadata + 94, // 111: common.LedgerLogPayload.deleted_metadata:type_name -> common.DeletedMetadata + 95, // 112: common.LedgerLogPayload.set_metadata_field_type:type_name -> common.SetMetadataFieldTypeLog + 96, // 113: common.LedgerLogPayload.removed_metadata_field_type:type_name -> common.RemovedMetadataFieldTypeLog + 90, // 114: common.LedgerLogPayload.fill_gap:type_name -> common.FilledGapLog + 88, // 115: common.LedgerLogPayload.create_index:type_name -> common.CreatedIndexLog + 89, // 116: common.LedgerLogPayload.drop_index:type_name -> common.DroppedIndexLog + 141, // 117: common.LedgerLogPayload.added_account_type:type_name -> common.AddedAccountTypeLog + 142, // 118: common.LedgerLogPayload.removed_account_type:type_name -> common.RemovedAccountTypeLog + 143, // 119: common.LedgerLogPayload.updated_default_enforcement_mode:type_name -> common.UpdatedDefaultEnforcementModeLog + 87, // 120: common.LedgerLogPayload.order_skipped:type_name -> common.OrderSkippedLog + 11, // 121: common.OrderSkippedLog.reason:type_name -> common.ErrorReason + 188, // 122: common.OrderSkippedLog.context:type_name -> common.OrderSkippedLog.ContextEntry + 40, // 123: common.CreatedIndexLog.id:type_name -> common.IndexID + 40, // 124: common.DroppedIndexLog.id:type_name -> common.IndexID + 25, // 125: common.CreatedTransaction.transaction:type_name -> common.Transaction + 189, // 126: common.CreatedTransaction.account_metadata:type_name -> common.CreatedTransaction.AccountMetadataEntry + 31, // 127: common.CreatedTransaction.post_commit_volumes:type_name -> common.PostCommitVolumes + 25, // 128: common.RevertedTransaction.revert_transaction:type_name -> common.Transaction + 31, // 129: common.RevertedTransaction.post_commit_volumes:type_name -> common.PostCommitVolumes + 35, // 130: common.SavedMetadata.target:type_name -> common.Target + 190, // 131: common.SavedMetadata.metadata:type_name -> common.SavedMetadata.MetadataEntry + 35, // 132: common.DeletedMetadata.target:type_name -> common.Target + 0, // 133: common.SetMetadataFieldTypeLog.target_type:type_name -> common.TargetType + 1, // 134: common.SetMetadataFieldTypeLog.type:type_name -> common.MetadataType + 0, // 135: common.RemovedMetadataFieldTypeLog.target_type:type_name -> common.TargetType + 40, // 136: common.RemovedMetadataFieldTypeLog.dropped_index:type_name -> common.IndexID + 18, // 137: common.Chapter.start:type_name -> common.Timestamp + 18, // 138: common.Chapter.end:type_name -> common.Timestamp + 8, // 139: common.Chapter.status:type_name -> common.ChapterStatus + 97, // 140: common.ClosedChapterLog.closed_chapter:type_name -> common.Chapter + 97, // 141: common.ClosedChapterLog.new_chapter:type_name -> common.Chapter + 97, // 142: common.SealedChapterLog.chapter:type_name -> common.Chapter + 97, // 143: common.ArchivedChapterLog.chapter:type_name -> common.Chapter + 97, // 144: common.ConfirmedArchiveChapterLog.chapter:type_name -> common.Chapter + 122, // 145: common.MirrorSourceConfig.http:type_name -> common.HttpMirrorSourceConfig + 124, // 146: common.MirrorSourceConfig.postgres:type_name -> common.PostgresMirrorSourceConfig + 103, // 147: common.MirrorSourceConfig.rewrite_rules:type_name -> common.MirrorRewriteRule + 104, // 148: common.MirrorRewriteRule.created_transaction:type_name -> common.CreatedTransactionRule + 105, // 149: common.MirrorRewriteRule.reverted_transaction:type_name -> common.RevertedTransactionRule + 106, // 150: common.MirrorRewriteRule.saved_metadata:type_name -> common.SavedMetadataRule + 107, // 151: common.MirrorRewriteRule.deleted_metadata:type_name -> common.DeletedMetadataRule + 108, // 152: common.MirrorRewriteRule.any_variant:type_name -> common.AnyVariantRule + 109, // 153: common.CreatedTransactionRule.actions:type_name -> common.CreatedTransactionAction + 110, // 154: common.RevertedTransactionRule.actions:type_name -> common.RevertedTransactionAction + 111, // 155: common.SavedMetadataRule.actions:type_name -> common.SavedMetadataAction + 112, // 156: common.DeletedMetadataRule.actions:type_name -> common.DeletedMetadataAction + 113, // 157: common.AnyVariantRule.actions:type_name -> common.AnyVariantAction + 114, // 158: common.CreatedTransactionAction.rewrite_address:type_name -> common.RewriteAddressAction + 115, // 159: common.CreatedTransactionAction.set_metadata:type_name -> common.SetMetadataAction + 116, // 160: common.CreatedTransactionAction.delete_metadata:type_name -> common.DeleteMetadataAction + 117, // 161: common.CreatedTransactionAction.set_account_metadata:type_name -> common.SetAccountMetadataAction + 118, // 162: common.CreatedTransactionAction.delete_account_metadata:type_name -> common.DeleteAccountMetadataAction + 119, // 163: common.CreatedTransactionAction.set_account_metadata_from_address:type_name -> common.SetAccountMetadataFromAddressAction + 121, // 164: common.CreatedTransactionAction.drop:type_name -> common.DropAction + 114, // 165: common.RevertedTransactionAction.rewrite_address:type_name -> common.RewriteAddressAction + 115, // 166: common.RevertedTransactionAction.set_metadata:type_name -> common.SetMetadataAction + 116, // 167: common.RevertedTransactionAction.delete_metadata:type_name -> common.DeleteMetadataAction + 121, // 168: common.RevertedTransactionAction.drop:type_name -> common.DropAction + 114, // 169: common.SavedMetadataAction.rewrite_address:type_name -> common.RewriteAddressAction + 115, // 170: common.SavedMetadataAction.set_metadata:type_name -> common.SetMetadataAction + 116, // 171: common.SavedMetadataAction.delete_metadata:type_name -> common.DeleteMetadataAction + 121, // 172: common.SavedMetadataAction.drop:type_name -> common.DropAction + 114, // 173: common.DeletedMetadataAction.rewrite_address:type_name -> common.RewriteAddressAction + 121, // 174: common.DeletedMetadataAction.drop:type_name -> common.DropAction + 114, // 175: common.AnyVariantAction.rewrite_address:type_name -> common.RewriteAddressAction + 121, // 176: common.AnyVariantAction.drop:type_name -> common.DropAction + 120, // 177: common.SetAccountMetadataFromAddressAction.replacements:type_name -> common.SetAccountMetadataFromAddressReplacement + 123, // 178: common.HttpMirrorSourceConfig.oauth2_client_credentials:type_name -> common.OAuth2ClientCredentials + 125, // 179: common.PostgresMirrorSourceConfig.aws_iam_auth:type_name -> common.PostgresAwsIamAuth + 18, // 180: common.MirrorSyncError.occurred_at:type_name -> common.Timestamp + 10, // 181: common.MirrorSyncProgress.state:type_name -> common.MirrorSyncState + 126, // 182: common.MirrorSyncProgress.error:type_name -> common.MirrorSyncError + 18, // 183: common.LedgerInfo.created_at:type_name -> common.Timestamp + 18, // 184: common.LedgerInfo.deleted_at:type_name -> common.Timestamp + 37, // 185: common.LedgerInfo.metadata_schema:type_name -> common.MetadataSchema + 9, // 186: common.LedgerInfo.mode:type_name -> common.LedgerMode + 102, // 187: common.LedgerInfo.mirror_source:type_name -> common.MirrorSourceConfig + 127, // 188: common.LedgerInfo.mirror_sync_progress:type_name -> common.MirrorSyncProgress + 191, // 189: common.LedgerInfo.account_types:type_name -> common.LedgerInfo.AccountTypesEntry + 12, // 190: common.LedgerInfo.default_enforcement_mode:type_name -> common.ChartEnforcementMode + 192, // 191: common.LedgerInfo.metadata:type_name -> common.LedgerInfo.MetadataEntry + 35, // 192: common.SaveMetadataCommand.target:type_name -> common.Target + 193, // 193: common.SaveMetadataCommand.metadata:type_name -> common.SaveMetadataCommand.MetadataEntry + 35, // 194: common.DeleteMetadataCommand.target:type_name -> common.Target + 194, // 195: common.TransactionState.metadata:type_name -> common.TransactionState.MetadataEntry + 18, // 196: common.TransactionState.timestamp:type_name -> common.Timestamp + 24, // 197: common.TransactionState.postings:type_name -> common.Posting + 18, // 198: common.TransactionState.reverted_at:type_name -> common.Timestamp + 133, // 199: common.IdempotencyKeyValue.failure:type_name -> common.IdempotencyFailure + 11, // 200: common.IdempotencyFailure.reason:type_name -> common.ErrorReason + 195, // 201: common.IdempotencyFailure.metadata:type_name -> common.IdempotencyFailure.MetadataEntry + 137, // 202: common.SegmentType.uuid:type_name -> common.UUIDConstraint + 138, // 203: common.SegmentType.uint64:type_name -> common.Uint64Constraint + 139, // 204: common.SegmentType.bytes:type_name -> common.BytesConstraint + 13, // 205: common.AccountType.persistence:type_name -> common.AccountTypePersistence + 196, // 206: common.AccountType.segment_types:type_name -> common.AccountType.SegmentTypesEntry + 140, // 207: common.AddedAccountTypeLog.account_type:type_name -> common.AccountType + 12, // 208: common.UpdatedDefaultEnforcementModeLog.enforcement_mode:type_name -> common.ChartEnforcementMode + 157, // 209: common.QueryFilter.field:type_name -> common.FieldCondition + 163, // 210: common.QueryFilter.address:type_name -> common.AddressMatch + 153, // 211: common.QueryFilter.and:type_name -> common.AndFilter + 154, // 212: common.QueryFilter.or:type_name -> common.OrFilter + 155, // 213: common.QueryFilter.not:type_name -> common.NotFilter + 145, // 214: common.QueryFilter.reference:type_name -> common.ReferenceCondition + 150, // 215: common.QueryFilter.builtin_uint:type_name -> common.BuiltinUintCondition + 148, // 216: common.QueryFilter.ledger:type_name -> common.LedgerCondition + 149, // 217: common.QueryFilter.log_id:type_name -> common.LogIdCondition + 151, // 218: common.QueryFilter.log_builtin_uint:type_name -> common.LogBuiltinUintCondition + 152, // 219: common.QueryFilter.account_has_asset:type_name -> common.AccountHasAssetCondition + 146, // 220: common.QueryFilter.reverted:type_name -> common.RevertedCondition + 147, // 221: common.QueryFilter.audit:type_name -> common.AuditCondition + 158, // 222: common.ReferenceCondition.cond:type_name -> common.StringCondition + 14, // 223: common.AuditCondition.field:type_name -> common.AuditField + 158, // 224: common.AuditCondition.string_cond:type_name -> common.StringCondition + 160, // 225: common.AuditCondition.uint_cond:type_name -> common.UintCondition + 158, // 226: common.LedgerCondition.cond:type_name -> common.StringCondition + 160, // 227: common.LogIdCondition.cond:type_name -> common.UintCondition + 3, // 228: common.BuiltinUintCondition.field:type_name -> common.TransactionBuiltinIndex + 160, // 229: common.BuiltinUintCondition.cond:type_name -> common.UintCondition + 5, // 230: common.LogBuiltinUintCondition.field:type_name -> common.LogBuiltinIndex + 160, // 231: common.LogBuiltinUintCondition.cond:type_name -> common.UintCondition + 144, // 232: common.AndFilter.filters:type_name -> common.QueryFilter + 144, // 233: common.OrFilter.filters:type_name -> common.QueryFilter + 144, // 234: common.NotFilter.filter:type_name -> common.QueryFilter + 156, // 235: common.FieldCondition.field:type_name -> common.FieldRef + 158, // 236: common.FieldCondition.string_cond:type_name -> common.StringCondition + 159, // 237: common.FieldCondition.int_cond:type_name -> common.IntCondition + 160, // 238: common.FieldCondition.uint_cond:type_name -> common.UintCondition + 161, // 239: common.FieldCondition.bool_cond:type_name -> common.BoolCondition + 162, // 240: common.FieldCondition.exists_cond:type_name -> common.ExistsCondition + 15, // 241: common.AddressMatch.role:type_name -> common.AddressRole + 144, // 242: common.PreparedQuery.filter:type_name -> common.QueryFilter + 16, // 243: common.PreparedQuery.target:type_name -> common.QueryTarget + 23, // 244: common.AggregatedVolume.input:type_name -> common.Uint256 + 23, // 245: common.AggregatedVolume.output:type_name -> common.Uint256 + 165, // 246: common.AggregateResult.volumes:type_name -> common.AggregatedVolume + 167, // 247: common.AggregateResult.groups:type_name -> common.GroupedAggregateResult + 165, // 248: common.GroupedAggregateResult.volumes:type_name -> common.AggregatedVolume + 33, // 249: common.PreparedQueryCursor.account_data:type_name -> common.Account + 25, // 250: common.PreparedQueryCursor.transaction_data:type_name -> common.Transaction + 44, // 251: common.PreparedQueryCursor.log_data:type_name -> common.Log + 171, // 252: common.CallerSnapshot.identity:type_name -> common.CallerIdentity + 173, // 253: common.BackupStorage.s3:type_name -> common.S3StorageConfig + 174, // 254: common.BackupStorage.azure:type_name -> common.AzureStorageConfig + 176, // 255: common.ListOptions.read:type_name -> common.ReadOptions + 144, // 256: common.ListOptions.filter:type_name -> common.QueryFilter + 20, // 257: common.MetadataMap.ValuesEntry.value:type_name -> common.MetadataValue + 20, // 258: common.Transaction.MetadataEntry.value:type_name -> common.MetadataValue + 29, // 259: common.PostCommitVolumes.VolumesByAccountEntry.value:type_name -> common.VolumesByAssets + 20, // 260: common.Account.MetadataEntry.value:type_name -> common.MetadataValue + 36, // 261: common.MetadataSchema.AccountFieldsEntry.value:type_name -> common.MetadataFieldSchema + 36, // 262: common.MetadataSchema.TransactionFieldsEntry.value:type_name -> common.MetadataFieldSchema + 36, // 263: common.MetadataSchema.LedgerFieldsEntry.value:type_name -> common.MetadataFieldSchema + 20, // 264: common.SavedLedgerMetadataLog.MetadataEntry.value:type_name -> common.MetadataValue + 140, // 265: common.CreatedLedgerLog.AccountTypesEntry.value:type_name -> common.AccountType + 21, // 266: common.CreatedTransaction.AccountMetadataEntry.value:type_name -> common.MetadataMap + 20, // 267: common.SavedMetadata.MetadataEntry.value:type_name -> common.MetadataValue + 140, // 268: common.LedgerInfo.AccountTypesEntry.value:type_name -> common.AccountType + 20, // 269: common.LedgerInfo.MetadataEntry.value:type_name -> common.MetadataValue + 20, // 270: common.SaveMetadataCommand.MetadataEntry.value:type_name -> common.MetadataValue + 20, // 271: common.TransactionState.MetadataEntry.value:type_name -> common.MetadataValue + 136, // 272: common.AccountType.SegmentTypesEntry.value:type_name -> common.SegmentType + 198, // 273: common.allowed_query_targets:extendee -> google.protobuf.FieldOptions + 198, // 274: common.valid_on_no_query_target:extendee -> google.protobuf.FieldOptions + 16, // 275: common.allowed_query_targets:type_name -> common.QueryTarget + 276, // [276:276] is the sub-list for method output_type + 276, // [276:276] is the sub-list for method input_type + 275, // [275:276] is the sub-list for extension type_name + 273, // [273:275] is the sub-list for extension extendee + 0, // [0:273] is the sub-list for field type_name } func init() { file_common_proto_init() } @@ -14359,18 +14443,18 @@ func file_common_proto_init() { (*LogPayload_SavedLedgerMetadata)(nil), (*LogPayload_DeletedLedgerMetadata)(nil), } - file_common_proto_msgTypes[53].OneofWrappers = []any{ + file_common_proto_msgTypes[54].OneofWrappers = []any{ (*SinkConfig_Nats)(nil), (*SinkConfig_Clickhouse)(nil), (*SinkConfig_Kafka)(nil), (*SinkConfig_Http)(nil), (*SinkConfig_Databricks)(nil), } - file_common_proto_msgTypes[60].OneofWrappers = []any{ + file_common_proto_msgTypes[61].OneofWrappers = []any{ (*DatabricksSinkConfig_Token)(nil), (*DatabricksSinkConfig_OauthM2M)(nil), } - file_common_proto_msgTypes[67].OneofWrappers = []any{ + file_common_proto_msgTypes[68].OneofWrappers = []any{ (*LedgerLogPayload_CreatedTransaction)(nil), (*LedgerLogPayload_RevertedTransaction)(nil), (*LedgerLogPayload_SavedMetadata)(nil), @@ -14385,18 +14469,18 @@ func file_common_proto_init() { (*LedgerLogPayload_UpdatedDefaultEnforcementMode)(nil), (*LedgerLogPayload_OrderSkipped)(nil), } - file_common_proto_msgTypes[83].OneofWrappers = []any{ + file_common_proto_msgTypes[84].OneofWrappers = []any{ (*MirrorSourceConfig_Http)(nil), (*MirrorSourceConfig_Postgres)(nil), } - file_common_proto_msgTypes[84].OneofWrappers = []any{ + file_common_proto_msgTypes[85].OneofWrappers = []any{ (*MirrorRewriteRule_CreatedTransaction)(nil), (*MirrorRewriteRule_RevertedTransaction)(nil), (*MirrorRewriteRule_SavedMetadata)(nil), (*MirrorRewriteRule_DeletedMetadata)(nil), (*MirrorRewriteRule_AnyVariant)(nil), } - file_common_proto_msgTypes[90].OneofWrappers = []any{ + file_common_proto_msgTypes[91].OneofWrappers = []any{ (*CreatedTransactionAction_RewriteAddress)(nil), (*CreatedTransactionAction_SetMetadata)(nil), (*CreatedTransactionAction_DeleteMetadata)(nil), @@ -14405,41 +14489,41 @@ func file_common_proto_init() { (*CreatedTransactionAction_SetAccountMetadataFromAddress)(nil), (*CreatedTransactionAction_Drop)(nil), } - file_common_proto_msgTypes[91].OneofWrappers = []any{ + file_common_proto_msgTypes[92].OneofWrappers = []any{ (*RevertedTransactionAction_RewriteAddress)(nil), (*RevertedTransactionAction_SetMetadata)(nil), (*RevertedTransactionAction_DeleteMetadata)(nil), (*RevertedTransactionAction_Drop)(nil), } - file_common_proto_msgTypes[92].OneofWrappers = []any{ + file_common_proto_msgTypes[93].OneofWrappers = []any{ (*SavedMetadataAction_RewriteAddress)(nil), (*SavedMetadataAction_SetMetadata)(nil), (*SavedMetadataAction_DeleteMetadata)(nil), (*SavedMetadataAction_Drop)(nil), } - file_common_proto_msgTypes[93].OneofWrappers = []any{ + file_common_proto_msgTypes[94].OneofWrappers = []any{ (*DeletedMetadataAction_RewriteAddress)(nil), (*DeletedMetadataAction_Drop)(nil), } - file_common_proto_msgTypes[94].OneofWrappers = []any{ + file_common_proto_msgTypes[95].OneofWrappers = []any{ (*AnyVariantAction_RewriteAddress)(nil), (*AnyVariantAction_Drop)(nil), } - file_common_proto_msgTypes[96].OneofWrappers = []any{ + file_common_proto_msgTypes[97].OneofWrappers = []any{ (*SetMetadataAction_Value)(nil), (*SetMetadataAction_ValueExpr)(nil), } - file_common_proto_msgTypes[98].OneofWrappers = []any{ + file_common_proto_msgTypes[99].OneofWrappers = []any{ (*SetAccountMetadataAction_Value)(nil), (*SetAccountMetadataAction_ValueExpr)(nil), } - file_common_proto_msgTypes[117].OneofWrappers = []any{ + file_common_proto_msgTypes[118].OneofWrappers = []any{ (*SegmentType_Regex)(nil), (*SegmentType_Uuid)(nil), (*SegmentType_Uint64)(nil), (*SegmentType_Bytes)(nil), } - file_common_proto_msgTypes[125].OneofWrappers = []any{ + file_common_proto_msgTypes[126].OneofWrappers = []any{ (*QueryFilter_Field)(nil), (*QueryFilter_Address)(nil), (*QueryFilter_And)(nil), @@ -14454,39 +14538,39 @@ func file_common_proto_init() { (*QueryFilter_Reverted)(nil), (*QueryFilter_Audit)(nil), } - file_common_proto_msgTypes[128].OneofWrappers = []any{ + file_common_proto_msgTypes[129].OneofWrappers = []any{ (*AuditCondition_StringCond)(nil), (*AuditCondition_UintCond)(nil), } - file_common_proto_msgTypes[138].OneofWrappers = []any{ + file_common_proto_msgTypes[139].OneofWrappers = []any{ (*FieldCondition_StringCond)(nil), (*FieldCondition_IntCond)(nil), (*FieldCondition_UintCond)(nil), (*FieldCondition_BoolCond)(nil), (*FieldCondition_ExistsCond)(nil), } - file_common_proto_msgTypes[139].OneofWrappers = []any{ + file_common_proto_msgTypes[140].OneofWrappers = []any{ (*StringCondition_Hardcoded)(nil), (*StringCondition_Param)(nil), } - file_common_proto_msgTypes[140].OneofWrappers = []any{} file_common_proto_msgTypes[141].OneofWrappers = []any{} - file_common_proto_msgTypes[142].OneofWrappers = []any{ + file_common_proto_msgTypes[142].OneofWrappers = []any{} + file_common_proto_msgTypes[143].OneofWrappers = []any{ (*BoolCondition_Hardcoded)(nil), (*BoolCondition_Param)(nil), } - file_common_proto_msgTypes[144].OneofWrappers = []any{ + file_common_proto_msgTypes[145].OneofWrappers = []any{ (*AddressMatch_HardcodedPrefix)(nil), (*AddressMatch_HardcodedExact)(nil), (*AddressMatch_ParamPrefix)(nil), (*AddressMatch_ParamExact)(nil), } - file_common_proto_msgTypes[152].OneofWrappers = []any{ + file_common_proto_msgTypes[153].OneofWrappers = []any{ (*CallerIdentity_Issuer)(nil), (*CallerIdentity_KeyId)(nil), (*CallerIdentity_SystemComponent)(nil), } - file_common_proto_msgTypes[156].OneofWrappers = []any{ + file_common_proto_msgTypes[157].OneofWrappers = []any{ (*BackupStorage_S3)(nil), (*BackupStorage_Azure)(nil), } @@ -14496,7 +14580,7 @@ func file_common_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_common_proto_rawDesc), len(file_common_proto_rawDesc)), NumEnums: 18, - NumMessages: 178, + NumMessages: 179, NumExtensions: 2, NumServices: 0, }, diff --git a/internal/proto/commonpb/common_dethash.pb.go b/internal/proto/commonpb/common_dethash.pb.go index e8537f1ee7..25dbe2c75e 100644 --- a/internal/proto/commonpb/common_dethash.pb.go +++ b/internal/proto/commonpb/common_dethash.pb.go @@ -1311,6 +1311,17 @@ func (m *DeletedNumscriptLog) MarshalDeterministicVT(dAtA []byte) []byte { return append(dAtA, b...) } +func (m *TemplateUsage) MarshalDeterministicVT(dAtA []byte) []byte { + if m == nil { + return dAtA + } + b, err := m.MarshalVT() + if err != nil { + panic("MarshalDeterministicVT: " + err.Error()) + } + return append(dAtA, b...) +} + func (m *SetQueryCheckpointScheduleLog) MarshalDeterministicVT(dAtA []byte) []byte { if m == nil { return dAtA @@ -1613,6 +1624,24 @@ func (m *LedgerLog) MarshalToSizedBufferDeterministicVT(dAtA []byte) (int, error i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.EphemeralVolumes) > 0 { + for iNdEx := len(m.EphemeralVolumes) - 1; iNdEx >= 0; iNdEx-- { + size, _ := m.EphemeralVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x32 + } + } + if len(m.NewKeptVolumes) > 0 { + for iNdEx := len(m.NewKeptVolumes) - 1; iNdEx >= 0; iNdEx-- { + size, _ := m.NewKeptVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + } if len(m.PurgedVolumes) > 0 { for iNdEx := len(m.PurgedVolumes) - 1; iNdEx >= 0; iNdEx-- { size, _ := m.PurgedVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) diff --git a/internal/proto/commonpb/common_reader.pb.go b/internal/proto/commonpb/common_reader.pb.go index ce66dfea7b..d7b3e245bb 100644 --- a/internal/proto/commonpb/common_reader.pb.go +++ b/internal/proto/commonpb/common_reader.pb.go @@ -4070,6 +4070,82 @@ func NewDeletedNumscriptLogListReader(s []*DeletedNumscriptLog) DeletedNumscript return deletedNumscriptLogListReadonly(s) } +// TemplateUsageReader provides read-only access to TemplateUsage. +// Call Mutate() to obtain a mutable clone. +type TemplateUsageReader interface { + GetCount() uint64 + GetLastUsed() TimestampReader + Mutate() *TemplateUsage +} + +type templateUsageReadonly TemplateUsage + +func (r *templateUsageReadonly) GetCount() uint64 { + return (*TemplateUsage)(r).GetCount() +} + +func (r *templateUsageReadonly) GetLastUsed() TimestampReader { + v := (*TemplateUsage)(r).GetLastUsed() + if v == nil { + return nil + } + return v.AsReader() +} + +func (r *templateUsageReadonly) Mutate() *TemplateUsage { + return (*TemplateUsage)(r).CloneVT() +} + +// AsReader returns a read-only view of this TemplateUsage. +func (m *TemplateUsage) AsReader() TemplateUsageReader { + if m == nil { + return nil + } + return (*templateUsageReadonly)(m) +} + +// Mutate returns a mutable deep clone of this TemplateUsage. +func (m *TemplateUsage) Mutate() *TemplateUsage { + return m.CloneVT() +} + +// TemplateUsageListReader provides read-only iteration over []*TemplateUsage. +type TemplateUsageListReader interface { + Len() int + Get(i int) TemplateUsageReader + Range(yield func(int, TemplateUsageReader) bool) +} + +type templateUsageListReadonly []*TemplateUsage + +func (l templateUsageListReadonly) Len() int { return len(l) } + +func (l templateUsageListReadonly) Get(i int) TemplateUsageReader { + v := l[i] + if v == nil { + return nil + } + return v.AsReader() +} + +func (l templateUsageListReadonly) Range(yield func(int, TemplateUsageReader) bool) { + for i, v := range l { + var r TemplateUsageReader + if v != nil { + r = v.AsReader() + } + if !yield(i, r) { + return + } + } +} + +// NewTemplateUsageListReader wraps s for read-only iteration. The returned +// view aliases the underlying slice; do not mutate s afterwards. +func NewTemplateUsageListReader(s []*TemplateUsage) TemplateUsageListReader { + return templateUsageListReadonly(s) +} + // SetQueryCheckpointScheduleLogReader provides read-only access to SetQueryCheckpointScheduleLog. // Call Mutate() to obtain a mutable clone. type SetQueryCheckpointScheduleLogReader interface { @@ -5362,6 +5438,8 @@ type LedgerLogReader interface { GetDate() TimestampReader GetId() uint64 GetPurgedVolumes() TouchedVolumeListReader + GetNewKeptVolumes() TouchedVolumeListReader + GetEphemeralVolumes() TouchedVolumeListReader Mutate() *LedgerLog } @@ -5391,6 +5469,14 @@ func (r *ledgerLogReadonly) GetPurgedVolumes() TouchedVolumeListReader { return NewTouchedVolumeListReader((*LedgerLog)(r).GetPurgedVolumes()) } +func (r *ledgerLogReadonly) GetNewKeptVolumes() TouchedVolumeListReader { + return NewTouchedVolumeListReader((*LedgerLog)(r).GetNewKeptVolumes()) +} + +func (r *ledgerLogReadonly) GetEphemeralVolumes() TouchedVolumeListReader { + return NewTouchedVolumeListReader((*LedgerLog)(r).GetEphemeralVolumes()) +} + func (r *ledgerLogReadonly) Mutate() *LedgerLog { return (*LedgerLog)(r).CloneVT() } @@ -12031,7 +12117,6 @@ func NewPreparedQueryCursorListReader(s []*PreparedQueryCursor) PreparedQueryCur type LedgerStatsReader interface { GetTransactionCount() uint64 GetVolumeCount() uint64 - GetMetadataCount() uint64 GetReferenceCount() uint64 GetPostingCount() uint64 GetEphemeralEvictedCount() uint64 @@ -12052,10 +12137,6 @@ func (r *ledgerStatsReadonly) GetVolumeCount() uint64 { return (*LedgerStats)(r).GetVolumeCount() } -func (r *ledgerStatsReadonly) GetMetadataCount() uint64 { - return (*LedgerStats)(r).GetMetadataCount() -} - func (r *ledgerStatsReadonly) GetReferenceCount() uint64 { return (*LedgerStats)(r).GetReferenceCount() } diff --git a/internal/proto/commonpb/common_vtproto.pb.go b/internal/proto/commonpb/common_vtproto.pb.go index a5c523911d..1b0379797b 100644 --- a/internal/proto/commonpb/common_vtproto.pb.go +++ b/internal/proto/commonpb/common_vtproto.pb.go @@ -1421,6 +1421,24 @@ func (m *DeletedNumscriptLog) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *TemplateUsage) CloneVT() *TemplateUsage { + if m == nil { + return (*TemplateUsage)(nil) + } + r := new(TemplateUsage) + r.Count = m.Count + r.LastUsed = m.LastUsed.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TemplateUsage) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *SetQueryCheckpointScheduleLog) CloneVT() *SetQueryCheckpointScheduleLog { if m == nil { return (*SetQueryCheckpointScheduleLog)(nil) @@ -1823,6 +1841,20 @@ func (m *LedgerLog) CloneVT() *LedgerLog { } r.PurgedVolumes = tmpContainer } + if rhs := m.NewKeptVolumes; rhs != nil { + tmpContainer := make([]*TouchedVolume, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.NewKeptVolumes = tmpContainer + } + if rhs := m.EphemeralVolumes; rhs != nil { + tmpContainer := make([]*TouchedVolume, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.EphemeralVolumes = tmpContainer + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -4296,7 +4328,6 @@ func (m *LedgerStats) CloneVT() *LedgerStats { r := new(LedgerStats) r.TransactionCount = m.TransactionCount r.VolumeCount = m.VolumeCount - r.MetadataCount = m.MetadataCount r.ReferenceCount = m.ReferenceCount r.PostingCount = m.PostingCount r.EphemeralEvictedCount = m.EphemeralEvictedCount @@ -6891,6 +6922,28 @@ func (this *DeletedNumscriptLog) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *TemplateUsage) EqualVT(that *TemplateUsage) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Count != that.Count { + return false + } + if !this.LastUsed.EqualVT(that.LastUsed) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TemplateUsage) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TemplateUsage) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *SetQueryCheckpointScheduleLog) EqualVT(that *SetQueryCheckpointScheduleLog) bool { if this == that { return true @@ -7535,6 +7588,40 @@ func (this *LedgerLog) EqualVT(that *LedgerLog) bool { } } } + if len(this.NewKeptVolumes) != len(that.NewKeptVolumes) { + return false + } + for i, vx := range this.NewKeptVolumes { + vy := that.NewKeptVolumes[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &TouchedVolume{} + } + if q == nil { + q = &TouchedVolume{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.EphemeralVolumes) != len(that.EphemeralVolumes) { + return false + } + for i, vx := range this.EphemeralVolumes { + vy := that.EphemeralVolumes[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &TouchedVolume{} + } + if q == nil { + q = &TouchedVolume{} + } + if !p.EqualVT(q) { + return false + } + } + } return string(this.unknownFields) == string(that.unknownFields) } @@ -11768,9 +11855,6 @@ func (this *LedgerStats) EqualVT(that *LedgerStats) bool { if this.VolumeCount != that.VolumeCount { return false } - if this.MetadataCount != that.MetadataCount { - return false - } if this.ReferenceCount != that.ReferenceCount { return false } @@ -15637,6 +15721,55 @@ func (m *DeletedNumscriptLog) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TemplateUsage) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TemplateUsage) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TemplateUsage) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.LastUsed != nil { + size, err := m.LastUsed.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.Count != 0 { + i -= 8 + binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.Count)) + i-- + dAtA[i] = 0x9 + } + return len(dAtA) - i, nil +} + func (m *SetQueryCheckpointScheduleLog) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -16702,6 +16835,30 @@ func (m *LedgerLog) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.EphemeralVolumes) > 0 { + for iNdEx := len(m.EphemeralVolumes) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.EphemeralVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x32 + } + } + if len(m.NewKeptVolumes) > 0 { + for iNdEx := len(m.NewKeptVolumes) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.NewKeptVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + } if len(m.PurgedVolumes) > 0 { for iNdEx := len(m.PurgedVolumes) - 1; iNdEx >= 0; iNdEx-- { size, err := m.PurgedVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) @@ -22621,12 +22778,6 @@ func (m *LedgerStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i-- dAtA[i] = 0x21 } - if m.MetadataCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.MetadataCount)) - i-- - dAtA[i] = 0x19 - } if m.VolumeCount != 0 { i -= 8 binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.VolumeCount)) @@ -24707,6 +24858,23 @@ func (m *DeletedNumscriptLog) SizeVT() (n int) { return n } +func (m *TemplateUsage) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Count != 0 { + n += 9 + } + if m.LastUsed != nil { + l = m.LastUsed.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + func (m *SetQueryCheckpointScheduleLog) SizeVT() (n int) { if m == nil { return 0 @@ -25165,6 +25333,18 @@ func (m *LedgerLog) SizeVT() (n int) { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } } + if len(m.NewKeptVolumes) > 0 { + for _, e := range m.NewKeptVolumes { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.EphemeralVolumes) > 0 { + for _, e := range m.EphemeralVolumes { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } n += len(m.unknownFields) return n } @@ -27699,9 +27879,6 @@ func (m *LedgerStats) SizeVT() (n int) { if m.VolumeCount != 0 { n += 9 } - if m.MetadataCount != 0 { - n += 9 - } if m.ReferenceCount != 0 { n += 9 } @@ -36440,6 +36617,103 @@ func (m *DeletedNumscriptLog) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *TemplateUsage) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TemplateUsage: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TemplateUsage: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) + } + m.Count = 0 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + m.Count = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastUsed", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.LastUsed == nil { + m.LastUsed = &Timestamp{} + } + if err := m.LastUsed.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *SetQueryCheckpointScheduleLog) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -39135,6 +39409,74 @@ func (m *LedgerLog) UnmarshalVT(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewKeptVolumes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewKeptVolumes = append(m.NewKeptVolumes, &TouchedVolume{}) + if err := m.NewKeptVolumes[len(m.NewKeptVolumes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EphemeralVolumes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EphemeralVolumes = append(m.EphemeralVolumes, &TouchedVolume{}) + if err := m.EphemeralVolumes[len(m.EphemeralVolumes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -52288,16 +52630,6 @@ func (m *LedgerStats) UnmarshalVT(dAtA []byte) error { } m.VolumeCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) iNdEx += 8 - case 3: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field MetadataCount", wireType) - } - m.MetadataCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.MetadataCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 case 4: if wireType != 1 { return fmt.Errorf("proto: wrong wireType = %d for field ReferenceCount", wireType) diff --git a/internal/proto/raftcmdpb/raft_cmd.pb.go b/internal/proto/raftcmdpb/raft_cmd.pb.go index c183fe56da..98f8c8ec00 100644 --- a/internal/proto/raftcmdpb/raft_cmd.pb.go +++ b/internal/proto/raftcmdpb/raft_cmd.pb.go @@ -4998,17 +4998,9 @@ func (*CreatedLogOrReference_CreatedLog) isCreatedLogOrReference_Type() {} func (*CreatedLogOrReference_ReferenceSequence) isCreatedLogOrReference_Type() {} type LedgerBoundaries struct { - state protoimpl.MessageState `protogen:"open.v1"` - NextTransactionId uint64 `protobuf:"fixed64,1,opt,name=next_transaction_id,json=nextTransactionId,proto3" json:"next_transaction_id,omitempty"` - NextLogId uint64 `protobuf:"fixed64,2,opt,name=next_log_id,json=nextLogId,proto3" json:"next_log_id,omitempty"` - VolumeCount uint64 `protobuf:"fixed64,3,opt,name=volume_count,json=volumeCount,proto3" json:"volume_count,omitempty"` - MetadataCount uint64 `protobuf:"fixed64,4,opt,name=metadata_count,json=metadataCount,proto3" json:"metadata_count,omitempty"` - ReferenceCount uint64 `protobuf:"fixed64,5,opt,name=reference_count,json=referenceCount,proto3" json:"reference_count,omitempty"` - PostingCount uint64 `protobuf:"fixed64,6,opt,name=posting_count,json=postingCount,proto3" json:"posting_count,omitempty"` - EphemeralEvictedCount uint64 `protobuf:"fixed64,7,opt,name=ephemeral_evicted_count,json=ephemeralEvictedCount,proto3" json:"ephemeral_evicted_count,omitempty"` - TransientUsedCount uint64 `protobuf:"fixed64,8,opt,name=transient_used_count,json=transientUsedCount,proto3" json:"transient_used_count,omitempty"` - RevertCount uint64 `protobuf:"fixed64,9,opt,name=revert_count,json=revertCount,proto3" json:"revert_count,omitempty"` - NumscriptExecutionCount uint64 `protobuf:"fixed64,10,opt,name=numscript_execution_count,json=numscriptExecutionCount,proto3" json:"numscript_execution_count,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + NextTransactionId uint64 `protobuf:"fixed64,1,opt,name=next_transaction_id,json=nextTransactionId,proto3" json:"next_transaction_id,omitempty"` + NextLogId uint64 `protobuf:"fixed64,2,opt,name=next_log_id,json=nextLogId,proto3" json:"next_log_id,omitempty"` // Highest source (v2) log ID already applied to this mirror ledger. Gates // idempotent replay: a MirrorIngest whose v2LogId is <= this value is a // deterministic no-op on the FSM apply path (see processMirrorIngest). @@ -5061,62 +5053,6 @@ func (x *LedgerBoundaries) GetNextLogId() uint64 { return 0 } -func (x *LedgerBoundaries) GetVolumeCount() uint64 { - if x != nil { - return x.VolumeCount - } - return 0 -} - -func (x *LedgerBoundaries) GetMetadataCount() uint64 { - if x != nil { - return x.MetadataCount - } - return 0 -} - -func (x *LedgerBoundaries) GetReferenceCount() uint64 { - if x != nil { - return x.ReferenceCount - } - return 0 -} - -func (x *LedgerBoundaries) GetPostingCount() uint64 { - if x != nil { - return x.PostingCount - } - return 0 -} - -func (x *LedgerBoundaries) GetEphemeralEvictedCount() uint64 { - if x != nil { - return x.EphemeralEvictedCount - } - return 0 -} - -func (x *LedgerBoundaries) GetTransientUsedCount() uint64 { - if x != nil { - return x.TransientUsedCount - } - return 0 -} - -func (x *LedgerBoundaries) GetRevertCount() uint64 { - if x != nil { - return x.RevertCount - } - return 0 -} - -func (x *LedgerBoundaries) GetNumscriptExecutionCount() uint64 { - if x != nil { - return x.NumscriptExecutionCount - } - return 0 -} - func (x *LedgerBoundaries) GetLastMirrorV2LogId() uint64 { if x != nil { return x.LastMirrorV2LogId @@ -6554,20 +6490,13 @@ const file_raft_cmd_proto_rawDesc = "" + "\vcreated_log\x18\x01 \x01(\v2\v.common.LogH\x00R\n" + "createdLog\x12/\n" + "\x12reference_sequence\x18\x02 \x01(\x06H\x00R\x11referenceSequenceB\x06\n" + - "\x04type\"\xf5\x03\n" + + "\x04type\"\xda\x02\n" + "\x10LedgerBoundaries\x12.\n" + "\x13next_transaction_id\x18\x01 \x01(\x06R\x11nextTransactionId\x12\x1e\n" + - "\vnext_log_id\x18\x02 \x01(\x06R\tnextLogId\x12!\n" + - "\fvolume_count\x18\x03 \x01(\x06R\vvolumeCount\x12%\n" + - "\x0emetadata_count\x18\x04 \x01(\x06R\rmetadataCount\x12'\n" + - "\x0freference_count\x18\x05 \x01(\x06R\x0ereferenceCount\x12#\n" + - "\rposting_count\x18\x06 \x01(\x06R\fpostingCount\x126\n" + - "\x17ephemeral_evicted_count\x18\a \x01(\x06R\x15ephemeralEvictedCount\x120\n" + - "\x14transient_used_count\x18\b \x01(\x06R\x12transientUsedCount\x12!\n" + - "\frevert_count\x18\t \x01(\x06R\vrevertCount\x12:\n" + - "\x19numscript_execution_count\x18\n" + - " \x01(\x06R\x17numscriptExecutionCount\x120\n" + - "\x15last_mirror_v2_log_id\x18\v \x01(\x06R\x11lastMirrorV2LogId\"\\\n" + + "\vnext_log_id\x18\x02 \x01(\x06R\tnextLogId\x120\n" + + "\x15last_mirror_v2_log_id\x18\v \x01(\x06R\x11lastMirrorV2LogIdJ\x04\b\x03\x10\x04J\x04\b\x04\x10\x05J\x04\b\x05\x10\x06J\x04\b\x06\x10\aJ\x04\b\a\x10\bJ\x04\b\b\x10\tJ\x04\b\t\x10\n" + + "J\x04\b\n" + + "\x10\vR\fvolume_countR\x0emetadata_countR\x0freference_countR\rposting_countR\x17ephemeral_evicted_countR\x14transient_used_countR\frevert_countR\x19numscript_execution_count\"\\\n" + "\n" + "VolumePair\x12%\n" + "\x05input\x18\x01 \x01(\v2\x0f.common.Uint256R\x05input\x12'\n" + diff --git a/internal/proto/raftcmdpb/raft_cmd_reader.pb.go b/internal/proto/raftcmdpb/raft_cmd_reader.pb.go index 57b386da98..4cfc80c588 100644 --- a/internal/proto/raftcmdpb/raft_cmd_reader.pb.go +++ b/internal/proto/raftcmdpb/raft_cmd_reader.pb.go @@ -5335,14 +5335,6 @@ func NewCreatedLogOrReferenceListReader(s []*CreatedLogOrReference) CreatedLogOr type LedgerBoundariesReader interface { GetNextTransactionId() uint64 GetNextLogId() uint64 - GetVolumeCount() uint64 - GetMetadataCount() uint64 - GetReferenceCount() uint64 - GetPostingCount() uint64 - GetEphemeralEvictedCount() uint64 - GetTransientUsedCount() uint64 - GetRevertCount() uint64 - GetNumscriptExecutionCount() uint64 GetLastMirrorV2LogId() uint64 Mutate() *LedgerBoundaries } @@ -5357,38 +5349,6 @@ func (r *ledgerBoundariesReadonly) GetNextLogId() uint64 { return (*LedgerBoundaries)(r).GetNextLogId() } -func (r *ledgerBoundariesReadonly) GetVolumeCount() uint64 { - return (*LedgerBoundaries)(r).GetVolumeCount() -} - -func (r *ledgerBoundariesReadonly) GetMetadataCount() uint64 { - return (*LedgerBoundaries)(r).GetMetadataCount() -} - -func (r *ledgerBoundariesReadonly) GetReferenceCount() uint64 { - return (*LedgerBoundaries)(r).GetReferenceCount() -} - -func (r *ledgerBoundariesReadonly) GetPostingCount() uint64 { - return (*LedgerBoundaries)(r).GetPostingCount() -} - -func (r *ledgerBoundariesReadonly) GetEphemeralEvictedCount() uint64 { - return (*LedgerBoundaries)(r).GetEphemeralEvictedCount() -} - -func (r *ledgerBoundariesReadonly) GetTransientUsedCount() uint64 { - return (*LedgerBoundaries)(r).GetTransientUsedCount() -} - -func (r *ledgerBoundariesReadonly) GetRevertCount() uint64 { - return (*LedgerBoundaries)(r).GetRevertCount() -} - -func (r *ledgerBoundariesReadonly) GetNumscriptExecutionCount() uint64 { - return (*LedgerBoundaries)(r).GetNumscriptExecutionCount() -} - func (r *ledgerBoundariesReadonly) GetLastMirrorV2LogId() uint64 { return (*LedgerBoundaries)(r).GetLastMirrorV2LogId() } diff --git a/internal/proto/raftcmdpb/raft_cmd_vtproto.pb.go b/internal/proto/raftcmdpb/raft_cmd_vtproto.pb.go index c8366933ce..4574736cba 100644 --- a/internal/proto/raftcmdpb/raft_cmd_vtproto.pb.go +++ b/internal/proto/raftcmdpb/raft_cmd_vtproto.pb.go @@ -1988,14 +1988,6 @@ func (m *LedgerBoundaries) CloneVT() *LedgerBoundaries { r := new(LedgerBoundaries) r.NextTransactionId = m.NextTransactionId r.NextLogId = m.NextLogId - r.VolumeCount = m.VolumeCount - r.MetadataCount = m.MetadataCount - r.ReferenceCount = m.ReferenceCount - r.PostingCount = m.PostingCount - r.EphemeralEvictedCount = m.EphemeralEvictedCount - r.TransientUsedCount = m.TransientUsedCount - r.RevertCount = m.RevertCount - r.NumscriptExecutionCount = m.NumscriptExecutionCount r.LastMirrorV2LogId = m.LastMirrorV2LogId if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) @@ -5872,30 +5864,6 @@ func (this *LedgerBoundaries) EqualVT(that *LedgerBoundaries) bool { if this.NextLogId != that.NextLogId { return false } - if this.VolumeCount != that.VolumeCount { - return false - } - if this.MetadataCount != that.MetadataCount { - return false - } - if this.ReferenceCount != that.ReferenceCount { - return false - } - if this.PostingCount != that.PostingCount { - return false - } - if this.EphemeralEvictedCount != that.EphemeralEvictedCount { - return false - } - if this.TransientUsedCount != that.TransientUsedCount { - return false - } - if this.RevertCount != that.RevertCount { - return false - } - if this.NumscriptExecutionCount != that.NumscriptExecutionCount { - return false - } if this.LastMirrorV2LogId != that.LastMirrorV2LogId { return false } @@ -11235,54 +11203,6 @@ func (m *LedgerBoundaries) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i-- dAtA[i] = 0x59 } - if m.NumscriptExecutionCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.NumscriptExecutionCount)) - i-- - dAtA[i] = 0x51 - } - if m.RevertCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.RevertCount)) - i-- - dAtA[i] = 0x49 - } - if m.TransientUsedCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.TransientUsedCount)) - i-- - dAtA[i] = 0x41 - } - if m.EphemeralEvictedCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.EphemeralEvictedCount)) - i-- - dAtA[i] = 0x39 - } - if m.PostingCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.PostingCount)) - i-- - dAtA[i] = 0x31 - } - if m.ReferenceCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.ReferenceCount)) - i-- - dAtA[i] = 0x29 - } - if m.MetadataCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.MetadataCount)) - i-- - dAtA[i] = 0x21 - } - if m.VolumeCount != 0 { - i -= 8 - binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.VolumeCount)) - i-- - dAtA[i] = 0x19 - } if m.NextLogId != 0 { i -= 8 binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.NextLogId)) @@ -14574,30 +14494,6 @@ func (m *LedgerBoundaries) SizeVT() (n int) { if m.NextLogId != 0 { n += 9 } - if m.VolumeCount != 0 { - n += 9 - } - if m.MetadataCount != 0 { - n += 9 - } - if m.ReferenceCount != 0 { - n += 9 - } - if m.PostingCount != 0 { - n += 9 - } - if m.EphemeralEvictedCount != 0 { - n += 9 - } - if m.TransientUsedCount != 0 { - n += 9 - } - if m.RevertCount != 0 { - n += 9 - } - if m.NumscriptExecutionCount != 0 { - n += 9 - } if m.LastMirrorV2LogId != 0 { n += 9 } @@ -25978,86 +25874,6 @@ func (m *LedgerBoundaries) UnmarshalVT(dAtA []byte) error { } m.NextLogId = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) iNdEx += 8 - case 3: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field VolumeCount", wireType) - } - m.VolumeCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.VolumeCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - case 4: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field MetadataCount", wireType) - } - m.MetadataCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.MetadataCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - case 5: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field ReferenceCount", wireType) - } - m.ReferenceCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.ReferenceCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - case 6: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field PostingCount", wireType) - } - m.PostingCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.PostingCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - case 7: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field EphemeralEvictedCount", wireType) - } - m.EphemeralEvictedCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.EphemeralEvictedCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - case 8: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field TransientUsedCount", wireType) - } - m.TransientUsedCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.TransientUsedCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - case 9: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field RevertCount", wireType) - } - m.RevertCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.RevertCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - case 10: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field NumscriptExecutionCount", wireType) - } - m.NumscriptExecutionCount = 0 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - m.NumscriptExecutionCount = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 case 11: if wireType != 1 { return fmt.Errorf("proto: wrong wireType = %d for field LastMirrorV2LogId", wireType) diff --git a/internal/proto/servicepb/bucket.pb.go b/internal/proto/servicepb/bucket.pb.go index 2945f9e9e6..47ad7263db 100644 --- a/internal/proto/servicepb/bucket.pb.go +++ b/internal/proto/servicepb/bucket.pb.go @@ -388,7 +388,7 @@ func (x ListIndexesRequest_Scope) Number() protoreflect.EnumNumber { // Deprecated: Use ListIndexesRequest_Scope.Descriptor instead. func (ListIndexesRequest_Scope) EnumDescriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{117, 0} + return file_bucket_proto_rawDescGZIP(), []int{118, 0} } type GetAccountRequest struct { @@ -3111,6 +3111,62 @@ func (x *ListNumscriptsRequest) GetOptions() *commonpb.ListOptions { return nil } +// GetTemplateUsageRequest retrieves the invocation counter + last-used +// timestamp for a Numscript template. The counter is materialised +// asynchronously by the usagebuilder from the audit chain — expect up to +// one tick interval of lag behind the live FSM. +type GetTemplateUsageRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Ledger string `protobuf:"bytes,1,opt,name=ledger,proto3" json:"ledger,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTemplateUsageRequest) Reset() { + *x = GetTemplateUsageRequest{} + mi := &file_bucket_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTemplateUsageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTemplateUsageRequest) ProtoMessage() {} + +func (x *GetTemplateUsageRequest) ProtoReflect() protoreflect.Message { + mi := &file_bucket_proto_msgTypes[41] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTemplateUsageRequest.ProtoReflect.Descriptor instead. +func (*GetTemplateUsageRequest) Descriptor() ([]byte, []int) { + return file_bucket_proto_rawDescGZIP(), []int{41} +} + +func (x *GetTemplateUsageRequest) GetLedger() string { + if x != nil { + return x.Ledger + } + return "" +} + +func (x *GetTemplateUsageRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + // ScriptReference references a numscript from the library by name and optional version. type ScriptReference struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -3123,7 +3179,7 @@ type ScriptReference struct { func (x *ScriptReference) Reset() { *x = ScriptReference{} - mi := &file_bucket_proto_msgTypes[41] + mi := &file_bucket_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3135,7 +3191,7 @@ func (x *ScriptReference) String() string { func (*ScriptReference) ProtoMessage() {} func (x *ScriptReference) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[41] + mi := &file_bucket_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3148,7 +3204,7 @@ func (x *ScriptReference) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptReference.ProtoReflect.Descriptor instead. func (*ScriptReference) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{41} + return file_bucket_proto_rawDescGZIP(), []int{42} } func (x *ScriptReference) GetName() string { @@ -3182,7 +3238,7 @@ type SetQueryCheckpointScheduleRequest struct { func (x *SetQueryCheckpointScheduleRequest) Reset() { *x = SetQueryCheckpointScheduleRequest{} - mi := &file_bucket_proto_msgTypes[42] + mi := &file_bucket_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3194,7 +3250,7 @@ func (x *SetQueryCheckpointScheduleRequest) String() string { func (*SetQueryCheckpointScheduleRequest) ProtoMessage() {} func (x *SetQueryCheckpointScheduleRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[42] + mi := &file_bucket_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3207,7 +3263,7 @@ func (x *SetQueryCheckpointScheduleRequest) ProtoReflect() protoreflect.Message // Deprecated: Use SetQueryCheckpointScheduleRequest.ProtoReflect.Descriptor instead. func (*SetQueryCheckpointScheduleRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{42} + return file_bucket_proto_rawDescGZIP(), []int{43} } func (x *SetQueryCheckpointScheduleRequest) GetCron() string { @@ -3226,7 +3282,7 @@ type DeleteQueryCheckpointScheduleRequest struct { func (x *DeleteQueryCheckpointScheduleRequest) Reset() { *x = DeleteQueryCheckpointScheduleRequest{} - mi := &file_bucket_proto_msgTypes[43] + mi := &file_bucket_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3238,7 +3294,7 @@ func (x *DeleteQueryCheckpointScheduleRequest) String() string { func (*DeleteQueryCheckpointScheduleRequest) ProtoMessage() {} func (x *DeleteQueryCheckpointScheduleRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[43] + mi := &file_bucket_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3251,7 +3307,7 @@ func (x *DeleteQueryCheckpointScheduleRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use DeleteQueryCheckpointScheduleRequest.ProtoReflect.Descriptor instead. func (*DeleteQueryCheckpointScheduleRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{43} + return file_bucket_proto_rawDescGZIP(), []int{44} } type GetChapterScheduleRequest struct { @@ -3262,7 +3318,7 @@ type GetChapterScheduleRequest struct { func (x *GetChapterScheduleRequest) Reset() { *x = GetChapterScheduleRequest{} - mi := &file_bucket_proto_msgTypes[44] + mi := &file_bucket_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3274,7 +3330,7 @@ func (x *GetChapterScheduleRequest) String() string { func (*GetChapterScheduleRequest) ProtoMessage() {} func (x *GetChapterScheduleRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[44] + mi := &file_bucket_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3287,7 +3343,7 @@ func (x *GetChapterScheduleRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChapterScheduleRequest.ProtoReflect.Descriptor instead. func (*GetChapterScheduleRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{44} + return file_bucket_proto_rawDescGZIP(), []int{45} } type GetChapterScheduleResponse struct { @@ -3299,7 +3355,7 @@ type GetChapterScheduleResponse struct { func (x *GetChapterScheduleResponse) Reset() { *x = GetChapterScheduleResponse{} - mi := &file_bucket_proto_msgTypes[45] + mi := &file_bucket_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3311,7 +3367,7 @@ func (x *GetChapterScheduleResponse) String() string { func (*GetChapterScheduleResponse) ProtoMessage() {} func (x *GetChapterScheduleResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[45] + mi := &file_bucket_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3324,7 +3380,7 @@ func (x *GetChapterScheduleResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChapterScheduleResponse.ProtoReflect.Descriptor instead. func (*GetChapterScheduleResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{45} + return file_bucket_proto_rawDescGZIP(), []int{46} } func (x *GetChapterScheduleResponse) GetCron() string { @@ -3342,7 +3398,7 @@ type DiscoveryRequest struct { func (x *DiscoveryRequest) Reset() { *x = DiscoveryRequest{} - mi := &file_bucket_proto_msgTypes[46] + mi := &file_bucket_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3354,7 +3410,7 @@ func (x *DiscoveryRequest) String() string { func (*DiscoveryRequest) ProtoMessage() {} func (x *DiscoveryRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[46] + mi := &file_bucket_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3367,7 +3423,7 @@ func (x *DiscoveryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DiscoveryRequest.ProtoReflect.Descriptor instead. func (*DiscoveryRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{46} + return file_bucket_proto_rawDescGZIP(), []int{47} } // ServerInfo carries the server build metadata (unauthenticated). @@ -3383,7 +3439,7 @@ type ServerInfo struct { func (x *ServerInfo) Reset() { *x = ServerInfo{} - mi := &file_bucket_proto_msgTypes[47] + mi := &file_bucket_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3395,7 +3451,7 @@ func (x *ServerInfo) String() string { func (*ServerInfo) ProtoMessage() {} func (x *ServerInfo) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[47] + mi := &file_bucket_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3408,7 +3464,7 @@ func (x *ServerInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ServerInfo.ProtoReflect.Descriptor instead. func (*ServerInfo) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{47} + return file_bucket_proto_rawDescGZIP(), []int{48} } func (x *ServerInfo) GetVersion() string { @@ -3449,7 +3505,7 @@ type DiscoveryResponse struct { func (x *DiscoveryResponse) Reset() { *x = DiscoveryResponse{} - mi := &file_bucket_proto_msgTypes[48] + mi := &file_bucket_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3461,7 +3517,7 @@ func (x *DiscoveryResponse) String() string { func (*DiscoveryResponse) ProtoMessage() {} func (x *DiscoveryResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[48] + mi := &file_bucket_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3474,7 +3530,7 @@ func (x *DiscoveryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DiscoveryResponse.ProtoReflect.Descriptor instead. func (*DiscoveryResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{48} + return file_bucket_proto_rawDescGZIP(), []int{49} } func (x *DiscoveryResponse) GetResponseSigning() *ResponseSigningInfo { @@ -3502,7 +3558,7 @@ type ResponseSigningInfo struct { func (x *ResponseSigningInfo) Reset() { *x = ResponseSigningInfo{} - mi := &file_bucket_proto_msgTypes[49] + mi := &file_bucket_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3514,7 +3570,7 @@ func (x *ResponseSigningInfo) String() string { func (*ResponseSigningInfo) ProtoMessage() {} func (x *ResponseSigningInfo) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[49] + mi := &file_bucket_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3527,7 +3583,7 @@ func (x *ResponseSigningInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ResponseSigningInfo.ProtoReflect.Descriptor instead. func (*ResponseSigningInfo) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{49} + return file_bucket_proto_rawDescGZIP(), []int{50} } func (x *ResponseSigningInfo) GetPublicKey() []byte { @@ -3562,7 +3618,7 @@ type CreateTransactionPayload struct { func (x *CreateTransactionPayload) Reset() { *x = CreateTransactionPayload{} - mi := &file_bucket_proto_msgTypes[50] + mi := &file_bucket_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3574,7 +3630,7 @@ func (x *CreateTransactionPayload) String() string { func (*CreateTransactionPayload) ProtoMessage() {} func (x *CreateTransactionPayload) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[50] + mi := &file_bucket_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3587,7 +3643,7 @@ func (x *CreateTransactionPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTransactionPayload.ProtoReflect.Descriptor instead. func (*CreateTransactionPayload) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{50} + return file_bucket_proto_rawDescGZIP(), []int{51} } func (x *CreateTransactionPayload) GetPostings() []*commonpb.Posting { @@ -3668,7 +3724,7 @@ type RevertTransactionPayload struct { func (x *RevertTransactionPayload) Reset() { *x = RevertTransactionPayload{} - mi := &file_bucket_proto_msgTypes[51] + mi := &file_bucket_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3680,7 +3736,7 @@ func (x *RevertTransactionPayload) String() string { func (*RevertTransactionPayload) ProtoMessage() {} func (x *RevertTransactionPayload) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[51] + mi := &file_bucket_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3693,7 +3749,7 @@ func (x *RevertTransactionPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertTransactionPayload.ProtoReflect.Descriptor instead. func (*RevertTransactionPayload) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{51} + return file_bucket_proto_rawDescGZIP(), []int{52} } func (x *RevertTransactionPayload) GetTransactionId() uint64 { @@ -3763,7 +3819,7 @@ type LedgerAction struct { func (x *LedgerAction) Reset() { *x = LedgerAction{} - mi := &file_bucket_proto_msgTypes[52] + mi := &file_bucket_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3775,7 +3831,7 @@ func (x *LedgerAction) String() string { func (*LedgerAction) ProtoMessage() {} func (x *LedgerAction) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[52] + mi := &file_bucket_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3788,7 +3844,7 @@ func (x *LedgerAction) ProtoReflect() protoreflect.Message { // Deprecated: Use LedgerAction.ProtoReflect.Descriptor instead. func (*LedgerAction) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{52} + return file_bucket_proto_rawDescGZIP(), []int{53} } func (x *LedgerAction) GetData() isLedgerAction_Data { @@ -3931,7 +3987,7 @@ type LedgerApplyRequest struct { func (x *LedgerApplyRequest) Reset() { *x = LedgerApplyRequest{} - mi := &file_bucket_proto_msgTypes[53] + mi := &file_bucket_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3943,7 +3999,7 @@ func (x *LedgerApplyRequest) String() string { func (*LedgerApplyRequest) ProtoMessage() {} func (x *LedgerApplyRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[53] + mi := &file_bucket_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3956,7 +4012,7 @@ func (x *LedgerApplyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LedgerApplyRequest.ProtoReflect.Descriptor instead. func (*LedgerApplyRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{53} + return file_bucket_proto_rawDescGZIP(), []int{54} } func (x *LedgerApplyRequest) GetLedger() string { @@ -3990,7 +4046,7 @@ type AddAccountTypeRequest struct { func (x *AddAccountTypeRequest) Reset() { *x = AddAccountTypeRequest{} - mi := &file_bucket_proto_msgTypes[54] + mi := &file_bucket_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4002,7 +4058,7 @@ func (x *AddAccountTypeRequest) String() string { func (*AddAccountTypeRequest) ProtoMessage() {} func (x *AddAccountTypeRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[54] + mi := &file_bucket_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4015,7 +4071,7 @@ func (x *AddAccountTypeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAccountTypeRequest.ProtoReflect.Descriptor instead. func (*AddAccountTypeRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{54} + return file_bucket_proto_rawDescGZIP(), []int{55} } func (x *AddAccountTypeRequest) GetAccountType() *commonpb.AccountType { @@ -4035,7 +4091,7 @@ type RemoveAccountTypeRequest struct { func (x *RemoveAccountTypeRequest) Reset() { *x = RemoveAccountTypeRequest{} - mi := &file_bucket_proto_msgTypes[55] + mi := &file_bucket_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4047,7 +4103,7 @@ func (x *RemoveAccountTypeRequest) String() string { func (*RemoveAccountTypeRequest) ProtoMessage() {} func (x *RemoveAccountTypeRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[55] + mi := &file_bucket_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4060,7 +4116,7 @@ func (x *RemoveAccountTypeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveAccountTypeRequest.ProtoReflect.Descriptor instead. func (*RemoveAccountTypeRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{55} + return file_bucket_proto_rawDescGZIP(), []int{56} } func (x *RemoveAccountTypeRequest) GetName() string { @@ -4080,7 +4136,7 @@ type SetDefaultEnforcementModeRequest struct { func (x *SetDefaultEnforcementModeRequest) Reset() { *x = SetDefaultEnforcementModeRequest{} - mi := &file_bucket_proto_msgTypes[56] + mi := &file_bucket_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4092,7 +4148,7 @@ func (x *SetDefaultEnforcementModeRequest) String() string { func (*SetDefaultEnforcementModeRequest) ProtoMessage() {} func (x *SetDefaultEnforcementModeRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[56] + mi := &file_bucket_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4105,7 +4161,7 @@ func (x *SetDefaultEnforcementModeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetDefaultEnforcementModeRequest.ProtoReflect.Descriptor instead. func (*SetDefaultEnforcementModeRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{56} + return file_bucket_proto_rawDescGZIP(), []int{57} } func (x *SetDefaultEnforcementModeRequest) GetEnforcementMode() commonpb.ChartEnforcementMode { @@ -4126,7 +4182,7 @@ type SetDefaultEnforcementModeLedgerRequest struct { func (x *SetDefaultEnforcementModeLedgerRequest) Reset() { *x = SetDefaultEnforcementModeLedgerRequest{} - mi := &file_bucket_proto_msgTypes[57] + mi := &file_bucket_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4138,7 +4194,7 @@ func (x *SetDefaultEnforcementModeLedgerRequest) String() string { func (*SetDefaultEnforcementModeLedgerRequest) ProtoMessage() {} func (x *SetDefaultEnforcementModeLedgerRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[57] + mi := &file_bucket_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4151,7 +4207,7 @@ func (x *SetDefaultEnforcementModeLedgerRequest) ProtoReflect() protoreflect.Mes // Deprecated: Use SetDefaultEnforcementModeLedgerRequest.ProtoReflect.Descriptor instead. func (*SetDefaultEnforcementModeLedgerRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{57} + return file_bucket_proto_rawDescGZIP(), []int{58} } func (x *SetDefaultEnforcementModeLedgerRequest) GetLedger() string { @@ -4179,7 +4235,7 @@ type AddAccountTypeLedgerRequest struct { func (x *AddAccountTypeLedgerRequest) Reset() { *x = AddAccountTypeLedgerRequest{} - mi := &file_bucket_proto_msgTypes[58] + mi := &file_bucket_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4191,7 +4247,7 @@ func (x *AddAccountTypeLedgerRequest) String() string { func (*AddAccountTypeLedgerRequest) ProtoMessage() {} func (x *AddAccountTypeLedgerRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[58] + mi := &file_bucket_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4204,7 +4260,7 @@ func (x *AddAccountTypeLedgerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAccountTypeLedgerRequest.ProtoReflect.Descriptor instead. func (*AddAccountTypeLedgerRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{58} + return file_bucket_proto_rawDescGZIP(), []int{59} } func (x *AddAccountTypeLedgerRequest) GetLedger() string { @@ -4232,7 +4288,7 @@ type RemoveAccountTypeLedgerRequest struct { func (x *RemoveAccountTypeLedgerRequest) Reset() { *x = RemoveAccountTypeLedgerRequest{} - mi := &file_bucket_proto_msgTypes[59] + mi := &file_bucket_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4244,7 +4300,7 @@ func (x *RemoveAccountTypeLedgerRequest) String() string { func (*RemoveAccountTypeLedgerRequest) ProtoMessage() {} func (x *RemoveAccountTypeLedgerRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[59] + mi := &file_bucket_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4257,7 +4313,7 @@ func (x *RemoveAccountTypeLedgerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveAccountTypeLedgerRequest.ProtoReflect.Descriptor instead. func (*RemoveAccountTypeLedgerRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{59} + return file_bucket_proto_rawDescGZIP(), []int{60} } func (x *RemoveAccountTypeLedgerRequest) GetLedger() string { @@ -4284,7 +4340,7 @@ type GetPrimaryMetricsRequest struct { func (x *GetPrimaryMetricsRequest) Reset() { *x = GetPrimaryMetricsRequest{} - mi := &file_bucket_proto_msgTypes[60] + mi := &file_bucket_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4296,7 +4352,7 @@ func (x *GetPrimaryMetricsRequest) String() string { func (*GetPrimaryMetricsRequest) ProtoMessage() {} func (x *GetPrimaryMetricsRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[60] + mi := &file_bucket_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4309,7 +4365,7 @@ func (x *GetPrimaryMetricsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPrimaryMetricsRequest.ProtoReflect.Descriptor instead. func (*GetPrimaryMetricsRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{60} + return file_bucket_proto_rawDescGZIP(), []int{61} } func (x *GetPrimaryMetricsRequest) GetNodeId() uint32 { @@ -4331,7 +4387,7 @@ type GetPrimaryMetricsResponse struct { func (x *GetPrimaryMetricsResponse) Reset() { *x = GetPrimaryMetricsResponse{} - mi := &file_bucket_proto_msgTypes[61] + mi := &file_bucket_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4343,7 +4399,7 @@ func (x *GetPrimaryMetricsResponse) String() string { func (*GetPrimaryMetricsResponse) ProtoMessage() {} func (x *GetPrimaryMetricsResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[61] + mi := &file_bucket_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4356,7 +4412,7 @@ func (x *GetPrimaryMetricsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPrimaryMetricsResponse.ProtoReflect.Descriptor instead. func (*GetPrimaryMetricsResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{61} + return file_bucket_proto_rawDescGZIP(), []int{62} } func (x *GetPrimaryMetricsResponse) GetAvailable() bool { @@ -4383,7 +4439,7 @@ type GetSecondaryMetricsRequest struct { func (x *GetSecondaryMetricsRequest) Reset() { *x = GetSecondaryMetricsRequest{} - mi := &file_bucket_proto_msgTypes[62] + mi := &file_bucket_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4395,7 +4451,7 @@ func (x *GetSecondaryMetricsRequest) String() string { func (*GetSecondaryMetricsRequest) ProtoMessage() {} func (x *GetSecondaryMetricsRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[62] + mi := &file_bucket_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4408,7 +4464,7 @@ func (x *GetSecondaryMetricsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSecondaryMetricsRequest.ProtoReflect.Descriptor instead. func (*GetSecondaryMetricsRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{62} + return file_bucket_proto_rawDescGZIP(), []int{63} } func (x *GetSecondaryMetricsRequest) GetNodeId() uint32 { @@ -4430,7 +4486,7 @@ type GetSecondaryMetricsResponse struct { func (x *GetSecondaryMetricsResponse) Reset() { *x = GetSecondaryMetricsResponse{} - mi := &file_bucket_proto_msgTypes[63] + mi := &file_bucket_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4442,7 +4498,7 @@ func (x *GetSecondaryMetricsResponse) String() string { func (*GetSecondaryMetricsResponse) ProtoMessage() {} func (x *GetSecondaryMetricsResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[63] + mi := &file_bucket_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4455,7 +4511,7 @@ func (x *GetSecondaryMetricsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSecondaryMetricsResponse.ProtoReflect.Descriptor instead. func (*GetSecondaryMetricsResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{63} + return file_bucket_proto_rawDescGZIP(), []int{64} } func (x *GetSecondaryMetricsResponse) GetAvailable() bool { @@ -4492,7 +4548,7 @@ type PebbleMetrics struct { func (x *PebbleMetrics) Reset() { *x = PebbleMetrics{} - mi := &file_bucket_proto_msgTypes[64] + mi := &file_bucket_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4504,7 +4560,7 @@ func (x *PebbleMetrics) String() string { func (*PebbleMetrics) ProtoMessage() {} func (x *PebbleMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[64] + mi := &file_bucket_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4517,7 +4573,7 @@ func (x *PebbleMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use PebbleMetrics.ProtoReflect.Descriptor instead. func (*PebbleMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{64} + return file_bucket_proto_rawDescGZIP(), []int{65} } func (x *PebbleMetrics) GetBlockCache() *BlockCacheMetrics { @@ -4609,7 +4665,7 @@ type BlockCacheMetrics struct { func (x *BlockCacheMetrics) Reset() { *x = BlockCacheMetrics{} - mi := &file_bucket_proto_msgTypes[65] + mi := &file_bucket_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4621,7 +4677,7 @@ func (x *BlockCacheMetrics) String() string { func (*BlockCacheMetrics) ProtoMessage() {} func (x *BlockCacheMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[65] + mi := &file_bucket_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4634,7 +4690,7 @@ func (x *BlockCacheMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockCacheMetrics.ProtoReflect.Descriptor instead. func (*BlockCacheMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{65} + return file_bucket_proto_rawDescGZIP(), []int{66} } func (x *BlockCacheMetrics) GetSize() int64 { @@ -4685,7 +4741,7 @@ type CompactMetrics struct { func (x *CompactMetrics) Reset() { *x = CompactMetrics{} - mi := &file_bucket_proto_msgTypes[66] + mi := &file_bucket_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4697,7 +4753,7 @@ func (x *CompactMetrics) String() string { func (*CompactMetrics) ProtoMessage() {} func (x *CompactMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[66] + mi := &file_bucket_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4710,7 +4766,7 @@ func (x *CompactMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use CompactMetrics.ProtoReflect.Descriptor instead. func (*CompactMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{66} + return file_bucket_proto_rawDescGZIP(), []int{67} } func (x *CompactMetrics) GetCount() int64 { @@ -4810,7 +4866,7 @@ type FlushMetrics struct { func (x *FlushMetrics) Reset() { *x = FlushMetrics{} - mi := &file_bucket_proto_msgTypes[67] + mi := &file_bucket_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4822,7 +4878,7 @@ func (x *FlushMetrics) String() string { func (*FlushMetrics) ProtoMessage() {} func (x *FlushMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[67] + mi := &file_bucket_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4835,7 +4891,7 @@ func (x *FlushMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use FlushMetrics.ProtoReflect.Descriptor instead. func (*FlushMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{67} + return file_bucket_proto_rawDescGZIP(), []int{68} } func (x *FlushMetrics) GetCount() int64 { @@ -4885,7 +4941,7 @@ type MemTableMetrics struct { func (x *MemTableMetrics) Reset() { *x = MemTableMetrics{} - mi := &file_bucket_proto_msgTypes[68] + mi := &file_bucket_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4897,7 +4953,7 @@ func (x *MemTableMetrics) String() string { func (*MemTableMetrics) ProtoMessage() {} func (x *MemTableMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[68] + mi := &file_bucket_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4910,7 +4966,7 @@ func (x *MemTableMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use MemTableMetrics.ProtoReflect.Descriptor instead. func (*MemTableMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{68} + return file_bucket_proto_rawDescGZIP(), []int{69} } func (x *MemTableMetrics) GetSize() uint64 { @@ -4953,7 +5009,7 @@ type SnapshotsMetrics struct { func (x *SnapshotsMetrics) Reset() { *x = SnapshotsMetrics{} - mi := &file_bucket_proto_msgTypes[69] + mi := &file_bucket_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4965,7 +5021,7 @@ func (x *SnapshotsMetrics) String() string { func (*SnapshotsMetrics) ProtoMessage() {} func (x *SnapshotsMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[69] + mi := &file_bucket_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4978,7 +5034,7 @@ func (x *SnapshotsMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use SnapshotsMetrics.ProtoReflect.Descriptor instead. func (*SnapshotsMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{69} + return file_bucket_proto_rawDescGZIP(), []int{70} } func (x *SnapshotsMetrics) GetCount() int32 { @@ -5021,7 +5077,7 @@ type TableMetrics struct { func (x *TableMetrics) Reset() { *x = TableMetrics{} - mi := &file_bucket_proto_msgTypes[70] + mi := &file_bucket_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5033,7 +5089,7 @@ func (x *TableMetrics) String() string { func (*TableMetrics) ProtoMessage() {} func (x *TableMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[70] + mi := &file_bucket_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5046,7 +5102,7 @@ func (x *TableMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use TableMetrics.ProtoReflect.Descriptor instead. func (*TableMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{70} + return file_bucket_proto_rawDescGZIP(), []int{71} } func (x *TableMetrics) GetZombieSize() uint64 { @@ -5089,7 +5145,7 @@ type TableCacheMetrics struct { func (x *TableCacheMetrics) Reset() { *x = TableCacheMetrics{} - mi := &file_bucket_proto_msgTypes[71] + mi := &file_bucket_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5101,7 +5157,7 @@ func (x *TableCacheMetrics) String() string { func (*TableCacheMetrics) ProtoMessage() {} func (x *TableCacheMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[71] + mi := &file_bucket_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5114,7 +5170,7 @@ func (x *TableCacheMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use TableCacheMetrics.ProtoReflect.Descriptor instead. func (*TableCacheMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{71} + return file_bucket_proto_rawDescGZIP(), []int{72} } func (x *TableCacheMetrics) GetSize() int64 { @@ -5158,7 +5214,7 @@ type WALMetrics struct { func (x *WALMetrics) Reset() { *x = WALMetrics{} - mi := &file_bucket_proto_msgTypes[72] + mi := &file_bucket_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5170,7 +5226,7 @@ func (x *WALMetrics) String() string { func (*WALMetrics) ProtoMessage() {} func (x *WALMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[72] + mi := &file_bucket_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5183,7 +5239,7 @@ func (x *WALMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use WALMetrics.ProtoReflect.Descriptor instead. func (*WALMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{72} + return file_bucket_proto_rawDescGZIP(), []int{73} } func (x *WALMetrics) GetFiles() int64 { @@ -5231,7 +5287,7 @@ type KeysMetrics struct { func (x *KeysMetrics) Reset() { *x = KeysMetrics{} - mi := &file_bucket_proto_msgTypes[73] + mi := &file_bucket_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5243,7 +5299,7 @@ func (x *KeysMetrics) String() string { func (*KeysMetrics) ProtoMessage() {} func (x *KeysMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[73] + mi := &file_bucket_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5256,7 +5312,7 @@ func (x *KeysMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use KeysMetrics.ProtoReflect.Descriptor instead. func (*KeysMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{73} + return file_bucket_proto_rawDescGZIP(), []int{74} } func (x *KeysMetrics) GetRangeKeySetsCount() uint64 { @@ -5295,7 +5351,7 @@ type LevelMetrics struct { func (x *LevelMetrics) Reset() { *x = LevelMetrics{} - mi := &file_bucket_proto_msgTypes[74] + mi := &file_bucket_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5307,7 +5363,7 @@ func (x *LevelMetrics) String() string { func (*LevelMetrics) ProtoMessage() {} func (x *LevelMetrics) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[74] + mi := &file_bucket_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5320,7 +5376,7 @@ func (x *LevelMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use LevelMetrics.ProtoReflect.Descriptor instead. func (*LevelMetrics) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{74} + return file_bucket_proto_rawDescGZIP(), []int{75} } func (x *LevelMetrics) GetLevel() int32 { @@ -5429,7 +5485,7 @@ type CheckStoreRequest struct { func (x *CheckStoreRequest) Reset() { *x = CheckStoreRequest{} - mi := &file_bucket_proto_msgTypes[75] + mi := &file_bucket_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5441,7 +5497,7 @@ func (x *CheckStoreRequest) String() string { func (*CheckStoreRequest) ProtoMessage() {} func (x *CheckStoreRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[75] + mi := &file_bucket_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5454,7 +5510,7 @@ func (x *CheckStoreRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckStoreRequest.ProtoReflect.Descriptor instead. func (*CheckStoreRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{75} + return file_bucket_proto_rawDescGZIP(), []int{76} } type CheckStoreEvent struct { @@ -5470,7 +5526,7 @@ type CheckStoreEvent struct { func (x *CheckStoreEvent) Reset() { *x = CheckStoreEvent{} - mi := &file_bucket_proto_msgTypes[76] + mi := &file_bucket_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5482,7 +5538,7 @@ func (x *CheckStoreEvent) String() string { func (*CheckStoreEvent) ProtoMessage() {} func (x *CheckStoreEvent) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[76] + mi := &file_bucket_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5495,7 +5551,7 @@ func (x *CheckStoreEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckStoreEvent.ProtoReflect.Descriptor instead. func (*CheckStoreEvent) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{76} + return file_bucket_proto_rawDescGZIP(), []int{77} } func (x *CheckStoreEvent) GetType() isCheckStoreEvent_Type { @@ -5554,7 +5610,7 @@ type CheckStoreError struct { func (x *CheckStoreError) Reset() { *x = CheckStoreError{} - mi := &file_bucket_proto_msgTypes[77] + mi := &file_bucket_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5566,7 +5622,7 @@ func (x *CheckStoreError) String() string { func (*CheckStoreError) ProtoMessage() {} func (x *CheckStoreError) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[77] + mi := &file_bucket_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5579,7 +5635,7 @@ func (x *CheckStoreError) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckStoreError.ProtoReflect.Descriptor instead. func (*CheckStoreError) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{77} + return file_bucket_proto_rawDescGZIP(), []int{78} } func (x *CheckStoreError) GetErrorType() CheckStoreErrorType { @@ -5641,7 +5697,7 @@ type CheckStoreProgress struct { func (x *CheckStoreProgress) Reset() { *x = CheckStoreProgress{} - mi := &file_bucket_proto_msgTypes[78] + mi := &file_bucket_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5653,7 +5709,7 @@ func (x *CheckStoreProgress) String() string { func (*CheckStoreProgress) ProtoMessage() {} func (x *CheckStoreProgress) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[78] + mi := &file_bucket_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5666,7 +5722,7 @@ func (x *CheckStoreProgress) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckStoreProgress.ProtoReflect.Descriptor instead. func (*CheckStoreProgress) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{78} + return file_bucket_proto_rawDescGZIP(), []int{79} } func (x *CheckStoreProgress) GetLogsChecked() uint64 { @@ -5696,7 +5752,7 @@ type ListAuditEntriesRequest struct { func (x *ListAuditEntriesRequest) Reset() { *x = ListAuditEntriesRequest{} - mi := &file_bucket_proto_msgTypes[79] + mi := &file_bucket_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5708,7 +5764,7 @@ func (x *ListAuditEntriesRequest) String() string { func (*ListAuditEntriesRequest) ProtoMessage() {} func (x *ListAuditEntriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[79] + mi := &file_bucket_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5721,7 +5777,7 @@ func (x *ListAuditEntriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAuditEntriesRequest.ProtoReflect.Descriptor instead. func (*ListAuditEntriesRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{79} + return file_bucket_proto_rawDescGZIP(), []int{80} } func (x *ListAuditEntriesRequest) GetOptions() *commonpb.ListOptions { @@ -5740,7 +5796,7 @@ type GetAuditEntryRequest struct { func (x *GetAuditEntryRequest) Reset() { *x = GetAuditEntryRequest{} - mi := &file_bucket_proto_msgTypes[80] + mi := &file_bucket_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5752,7 +5808,7 @@ func (x *GetAuditEntryRequest) String() string { func (*GetAuditEntryRequest) ProtoMessage() {} func (x *GetAuditEntryRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[80] + mi := &file_bucket_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5765,7 +5821,7 @@ func (x *GetAuditEntryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAuditEntryRequest.ProtoReflect.Descriptor instead. func (*GetAuditEntryRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{80} + return file_bucket_proto_rawDescGZIP(), []int{81} } func (x *GetAuditEntryRequest) GetSequence() uint64 { @@ -5786,7 +5842,7 @@ type ListLogsRequest struct { func (x *ListLogsRequest) Reset() { *x = ListLogsRequest{} - mi := &file_bucket_proto_msgTypes[81] + mi := &file_bucket_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5798,7 +5854,7 @@ func (x *ListLogsRequest) String() string { func (*ListLogsRequest) ProtoMessage() {} func (x *ListLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[81] + mi := &file_bucket_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5811,7 +5867,7 @@ func (x *ListLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListLogsRequest.ProtoReflect.Descriptor instead. func (*ListLogsRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{81} + return file_bucket_proto_rawDescGZIP(), []int{82} } func (x *ListLogsRequest) GetLedger() string { @@ -5839,7 +5895,7 @@ type GetLogRequest struct { func (x *GetLogRequest) Reset() { *x = GetLogRequest{} - mi := &file_bucket_proto_msgTypes[82] + mi := &file_bucket_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5851,7 +5907,7 @@ func (x *GetLogRequest) String() string { func (*GetLogRequest) ProtoMessage() {} func (x *GetLogRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[82] + mi := &file_bucket_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5864,7 +5920,7 @@ func (x *GetLogRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLogRequest.ProtoReflect.Descriptor instead. func (*GetLogRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{82} + return file_bucket_proto_rawDescGZIP(), []int{83} } func (x *GetLogRequest) GetSequence() uint64 { @@ -5889,7 +5945,7 @@ type GetEventsSinksRequest struct { func (x *GetEventsSinksRequest) Reset() { *x = GetEventsSinksRequest{} - mi := &file_bucket_proto_msgTypes[83] + mi := &file_bucket_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5901,7 +5957,7 @@ func (x *GetEventsSinksRequest) String() string { func (*GetEventsSinksRequest) ProtoMessage() {} func (x *GetEventsSinksRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[83] + mi := &file_bucket_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5914,7 +5970,7 @@ func (x *GetEventsSinksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetEventsSinksRequest.ProtoReflect.Descriptor instead. func (*GetEventsSinksRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{83} + return file_bucket_proto_rawDescGZIP(), []int{84} } type GetEventsSinksResponse struct { @@ -5927,7 +5983,7 @@ type GetEventsSinksResponse struct { func (x *GetEventsSinksResponse) Reset() { *x = GetEventsSinksResponse{} - mi := &file_bucket_proto_msgTypes[84] + mi := &file_bucket_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5939,7 +5995,7 @@ func (x *GetEventsSinksResponse) String() string { func (*GetEventsSinksResponse) ProtoMessage() {} func (x *GetEventsSinksResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[84] + mi := &file_bucket_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5952,7 +6008,7 @@ func (x *GetEventsSinksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetEventsSinksResponse.ProtoReflect.Descriptor instead. func (*GetEventsSinksResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{84} + return file_bucket_proto_rawDescGZIP(), []int{85} } func (x *GetEventsSinksResponse) GetSinks() []*commonpb.SinkConfig { @@ -5978,7 +6034,7 @@ type GetMetadataSchemaStatusRequest struct { func (x *GetMetadataSchemaStatusRequest) Reset() { *x = GetMetadataSchemaStatusRequest{} - mi := &file_bucket_proto_msgTypes[85] + mi := &file_bucket_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5990,7 +6046,7 @@ func (x *GetMetadataSchemaStatusRequest) String() string { func (*GetMetadataSchemaStatusRequest) ProtoMessage() {} func (x *GetMetadataSchemaStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[85] + mi := &file_bucket_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6003,7 +6059,7 @@ func (x *GetMetadataSchemaStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMetadataSchemaStatusRequest.ProtoReflect.Descriptor instead. func (*GetMetadataSchemaStatusRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{85} + return file_bucket_proto_rawDescGZIP(), []int{86} } func (x *GetMetadataSchemaStatusRequest) GetLedger() string { @@ -6024,7 +6080,7 @@ type GetMetadataSchemaStatusResponse struct { func (x *GetMetadataSchemaStatusResponse) Reset() { *x = GetMetadataSchemaStatusResponse{} - mi := &file_bucket_proto_msgTypes[86] + mi := &file_bucket_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6036,7 +6092,7 @@ func (x *GetMetadataSchemaStatusResponse) String() string { func (*GetMetadataSchemaStatusResponse) ProtoMessage() {} func (x *GetMetadataSchemaStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[86] + mi := &file_bucket_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6049,7 +6105,7 @@ func (x *GetMetadataSchemaStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMetadataSchemaStatusResponse.ProtoReflect.Descriptor instead. func (*GetMetadataSchemaStatusResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{86} + return file_bucket_proto_rawDescGZIP(), []int{87} } func (x *GetMetadataSchemaStatusResponse) GetAccountFields() map[string]*MetadataFieldStatus { @@ -6082,7 +6138,7 @@ type MetadataFieldStatus struct { func (x *MetadataFieldStatus) Reset() { *x = MetadataFieldStatus{} - mi := &file_bucket_proto_msgTypes[87] + mi := &file_bucket_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6094,7 +6150,7 @@ func (x *MetadataFieldStatus) String() string { func (*MetadataFieldStatus) ProtoMessage() {} func (x *MetadataFieldStatus) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[87] + mi := &file_bucket_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6107,7 +6163,7 @@ func (x *MetadataFieldStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use MetadataFieldStatus.ProtoReflect.Descriptor instead. func (*MetadataFieldStatus) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{87} + return file_bucket_proto_rawDescGZIP(), []int{88} } func (x *MetadataFieldStatus) GetDeclaredType() commonpb.MetadataType { @@ -6129,7 +6185,7 @@ type AnalyzeAccountsRequest struct { func (x *AnalyzeAccountsRequest) Reset() { *x = AnalyzeAccountsRequest{} - mi := &file_bucket_proto_msgTypes[88] + mi := &file_bucket_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6141,7 +6197,7 @@ func (x *AnalyzeAccountsRequest) String() string { func (*AnalyzeAccountsRequest) ProtoMessage() {} func (x *AnalyzeAccountsRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[88] + mi := &file_bucket_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6154,7 +6210,7 @@ func (x *AnalyzeAccountsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeAccountsRequest.ProtoReflect.Descriptor instead. func (*AnalyzeAccountsRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{88} + return file_bucket_proto_rawDescGZIP(), []int{89} } func (x *AnalyzeAccountsRequest) GetLedger() string { @@ -6181,7 +6237,7 @@ type AnalyzeAccountsResponse struct { func (x *AnalyzeAccountsResponse) Reset() { *x = AnalyzeAccountsResponse{} - mi := &file_bucket_proto_msgTypes[89] + mi := &file_bucket_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6193,7 +6249,7 @@ func (x *AnalyzeAccountsResponse) String() string { func (*AnalyzeAccountsResponse) ProtoMessage() {} func (x *AnalyzeAccountsResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[89] + mi := &file_bucket_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6206,7 +6262,7 @@ func (x *AnalyzeAccountsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeAccountsResponse.ProtoReflect.Descriptor instead. func (*AnalyzeAccountsResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{89} + return file_bucket_proto_rawDescGZIP(), []int{90} } func (x *AnalyzeAccountsResponse) GetPatterns() []*AccountPattern { @@ -6235,7 +6291,7 @@ type AnalyzeProgress struct { func (x *AnalyzeProgress) Reset() { *x = AnalyzeProgress{} - mi := &file_bucket_proto_msgTypes[90] + mi := &file_bucket_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6247,7 +6303,7 @@ func (x *AnalyzeProgress) String() string { func (*AnalyzeProgress) ProtoMessage() {} func (x *AnalyzeProgress) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[90] + mi := &file_bucket_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6260,7 +6316,7 @@ func (x *AnalyzeProgress) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeProgress.ProtoReflect.Descriptor instead. func (*AnalyzeProgress) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{90} + return file_bucket_proto_rawDescGZIP(), []int{91} } func (x *AnalyzeProgress) GetProcessed() uint64 { @@ -6298,7 +6354,7 @@ type AnalyzeAccountsEvent struct { func (x *AnalyzeAccountsEvent) Reset() { *x = AnalyzeAccountsEvent{} - mi := &file_bucket_proto_msgTypes[91] + mi := &file_bucket_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6310,7 +6366,7 @@ func (x *AnalyzeAccountsEvent) String() string { func (*AnalyzeAccountsEvent) ProtoMessage() {} func (x *AnalyzeAccountsEvent) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[91] + mi := &file_bucket_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6323,7 +6379,7 @@ func (x *AnalyzeAccountsEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeAccountsEvent.ProtoReflect.Descriptor instead. func (*AnalyzeAccountsEvent) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{91} + return file_bucket_proto_rawDescGZIP(), []int{92} } func (x *AnalyzeAccountsEvent) GetType() isAnalyzeAccountsEvent_Type { @@ -6381,7 +6437,7 @@ type AnalyzeTransactionsEvent struct { func (x *AnalyzeTransactionsEvent) Reset() { *x = AnalyzeTransactionsEvent{} - mi := &file_bucket_proto_msgTypes[92] + mi := &file_bucket_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6393,7 +6449,7 @@ func (x *AnalyzeTransactionsEvent) String() string { func (*AnalyzeTransactionsEvent) ProtoMessage() {} func (x *AnalyzeTransactionsEvent) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[92] + mi := &file_bucket_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6406,7 +6462,7 @@ func (x *AnalyzeTransactionsEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeTransactionsEvent.ProtoReflect.Descriptor instead. func (*AnalyzeTransactionsEvent) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{92} + return file_bucket_proto_rawDescGZIP(), []int{93} } func (x *AnalyzeTransactionsEvent) GetType() isAnalyzeTransactionsEvent_Type { @@ -6464,7 +6520,7 @@ type AccountPattern struct { func (x *AccountPattern) Reset() { *x = AccountPattern{} - mi := &file_bucket_proto_msgTypes[93] + mi := &file_bucket_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6476,7 +6532,7 @@ func (x *AccountPattern) String() string { func (*AccountPattern) ProtoMessage() {} func (x *AccountPattern) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[93] + mi := &file_bucket_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6489,7 +6545,7 @@ func (x *AccountPattern) ProtoReflect() protoreflect.Message { // Deprecated: Use AccountPattern.ProtoReflect.Descriptor instead. func (*AccountPattern) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{93} + return file_bucket_proto_rawDescGZIP(), []int{94} } func (x *AccountPattern) GetPattern() string { @@ -6543,7 +6599,7 @@ type PatternSegment struct { func (x *PatternSegment) Reset() { *x = PatternSegment{} - mi := &file_bucket_proto_msgTypes[94] + mi := &file_bucket_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6555,7 +6611,7 @@ func (x *PatternSegment) String() string { func (*PatternSegment) ProtoMessage() {} func (x *PatternSegment) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[94] + mi := &file_bucket_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6568,7 +6624,7 @@ func (x *PatternSegment) ProtoReflect() protoreflect.Message { // Deprecated: Use PatternSegment.ProtoReflect.Descriptor instead. func (*PatternSegment) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{94} + return file_bucket_proto_rawDescGZIP(), []int{95} } func (x *PatternSegment) GetPosition() uint32 { @@ -6632,7 +6688,7 @@ type AnalyzeTransactionsRequest struct { func (x *AnalyzeTransactionsRequest) Reset() { *x = AnalyzeTransactionsRequest{} - mi := &file_bucket_proto_msgTypes[95] + mi := &file_bucket_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6644,7 +6700,7 @@ func (x *AnalyzeTransactionsRequest) String() string { func (*AnalyzeTransactionsRequest) ProtoMessage() {} func (x *AnalyzeTransactionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[95] + mi := &file_bucket_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6657,7 +6713,7 @@ func (x *AnalyzeTransactionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeTransactionsRequest.ProtoReflect.Descriptor instead. func (*AnalyzeTransactionsRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{95} + return file_bucket_proto_rawDescGZIP(), []int{96} } func (x *AnalyzeTransactionsRequest) GetLedger() string { @@ -6685,7 +6741,7 @@ type AnalyzeTransactionsResponse struct { func (x *AnalyzeTransactionsResponse) Reset() { *x = AnalyzeTransactionsResponse{} - mi := &file_bucket_proto_msgTypes[96] + mi := &file_bucket_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6697,7 +6753,7 @@ func (x *AnalyzeTransactionsResponse) String() string { func (*AnalyzeTransactionsResponse) ProtoMessage() {} func (x *AnalyzeTransactionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[96] + mi := &file_bucket_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6710,7 +6766,7 @@ func (x *AnalyzeTransactionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeTransactionsResponse.ProtoReflect.Descriptor instead. func (*AnalyzeTransactionsResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{96} + return file_bucket_proto_rawDescGZIP(), []int{97} } func (x *AnalyzeTransactionsResponse) GetFlowPatterns() []*FlowPattern { @@ -6753,7 +6809,7 @@ type FlowPattern struct { func (x *FlowPattern) Reset() { *x = FlowPattern{} - mi := &file_bucket_proto_msgTypes[97] + mi := &file_bucket_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6765,7 +6821,7 @@ func (x *FlowPattern) String() string { func (*FlowPattern) ProtoMessage() {} func (x *FlowPattern) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[97] + mi := &file_bucket_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6778,7 +6834,7 @@ func (x *FlowPattern) ProtoReflect() protoreflect.Message { // Deprecated: Use FlowPattern.ProtoReflect.Descriptor instead. func (*FlowPattern) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{97} + return file_bucket_proto_rawDescGZIP(), []int{98} } func (x *FlowPattern) GetSignature() string { @@ -6846,7 +6902,7 @@ type NormalizedPosting struct { func (x *NormalizedPosting) Reset() { *x = NormalizedPosting{} - mi := &file_bucket_proto_msgTypes[98] + mi := &file_bucket_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6858,7 +6914,7 @@ func (x *NormalizedPosting) String() string { func (*NormalizedPosting) ProtoMessage() {} func (x *NormalizedPosting) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[98] + mi := &file_bucket_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6871,7 +6927,7 @@ func (x *NormalizedPosting) ProtoReflect() protoreflect.Message { // Deprecated: Use NormalizedPosting.ProtoReflect.Descriptor instead. func (*NormalizedPosting) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{98} + return file_bucket_proto_rawDescGZIP(), []int{99} } func (x *NormalizedPosting) GetSourcePattern() string { @@ -6914,7 +6970,7 @@ type TemporalStats struct { func (x *TemporalStats) Reset() { *x = TemporalStats{} - mi := &file_bucket_proto_msgTypes[99] + mi := &file_bucket_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6926,7 +6982,7 @@ func (x *TemporalStats) String() string { func (*TemporalStats) ProtoMessage() {} func (x *TemporalStats) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[99] + mi := &file_bucket_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6939,7 +6995,7 @@ func (x *TemporalStats) ProtoReflect() protoreflect.Message { // Deprecated: Use TemporalStats.ProtoReflect.Descriptor instead. func (*TemporalStats) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{99} + return file_bucket_proto_rawDescGZIP(), []int{100} } func (x *TemporalStats) GetFirstSeen() *commonpb.Timestamp { @@ -6980,7 +7036,7 @@ type HourBucket struct { func (x *HourBucket) Reset() { *x = HourBucket{} - mi := &file_bucket_proto_msgTypes[100] + mi := &file_bucket_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6992,7 +7048,7 @@ func (x *HourBucket) String() string { func (*HourBucket) ProtoMessage() {} func (x *HourBucket) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[100] + mi := &file_bucket_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7005,7 +7061,7 @@ func (x *HourBucket) ProtoReflect() protoreflect.Message { // Deprecated: Use HourBucket.ProtoReflect.Descriptor instead. func (*HourBucket) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{100} + return file_bucket_proto_rawDescGZIP(), []int{101} } func (x *HourBucket) GetHour() uint32 { @@ -7036,7 +7092,7 @@ type AssetVolumeStats struct { func (x *AssetVolumeStats) Reset() { *x = AssetVolumeStats{} - mi := &file_bucket_proto_msgTypes[101] + mi := &file_bucket_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7048,7 +7104,7 @@ func (x *AssetVolumeStats) String() string { func (*AssetVolumeStats) ProtoMessage() {} func (x *AssetVolumeStats) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[101] + mi := &file_bucket_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7061,7 +7117,7 @@ func (x *AssetVolumeStats) ProtoReflect() protoreflect.Message { // Deprecated: Use AssetVolumeStats.ProtoReflect.Descriptor instead. func (*AssetVolumeStats) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{101} + return file_bucket_proto_rawDescGZIP(), []int{102} } func (x *AssetVolumeStats) GetAsset() string { @@ -7116,7 +7172,7 @@ type CreatePreparedQueryRequest struct { func (x *CreatePreparedQueryRequest) Reset() { *x = CreatePreparedQueryRequest{} - mi := &file_bucket_proto_msgTypes[102] + mi := &file_bucket_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7128,7 +7184,7 @@ func (x *CreatePreparedQueryRequest) String() string { func (*CreatePreparedQueryRequest) ProtoMessage() {} func (x *CreatePreparedQueryRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[102] + mi := &file_bucket_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7141,7 +7197,7 @@ func (x *CreatePreparedQueryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatePreparedQueryRequest.ProtoReflect.Descriptor instead. func (*CreatePreparedQueryRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{102} + return file_bucket_proto_rawDescGZIP(), []int{103} } func (x *CreatePreparedQueryRequest) GetLedger() string { @@ -7166,7 +7222,7 @@ type CreatePreparedQueryResponse struct { func (x *CreatePreparedQueryResponse) Reset() { *x = CreatePreparedQueryResponse{} - mi := &file_bucket_proto_msgTypes[103] + mi := &file_bucket_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7178,7 +7234,7 @@ func (x *CreatePreparedQueryResponse) String() string { func (*CreatePreparedQueryResponse) ProtoMessage() {} func (x *CreatePreparedQueryResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[103] + mi := &file_bucket_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7191,7 +7247,7 @@ func (x *CreatePreparedQueryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatePreparedQueryResponse.ProtoReflect.Descriptor instead. func (*CreatePreparedQueryResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{103} + return file_bucket_proto_rawDescGZIP(), []int{104} } type UpdatePreparedQueryRequest struct { @@ -7205,7 +7261,7 @@ type UpdatePreparedQueryRequest struct { func (x *UpdatePreparedQueryRequest) Reset() { *x = UpdatePreparedQueryRequest{} - mi := &file_bucket_proto_msgTypes[104] + mi := &file_bucket_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7217,7 +7273,7 @@ func (x *UpdatePreparedQueryRequest) String() string { func (*UpdatePreparedQueryRequest) ProtoMessage() {} func (x *UpdatePreparedQueryRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[104] + mi := &file_bucket_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7230,7 +7286,7 @@ func (x *UpdatePreparedQueryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdatePreparedQueryRequest.ProtoReflect.Descriptor instead. func (*UpdatePreparedQueryRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{104} + return file_bucket_proto_rawDescGZIP(), []int{105} } func (x *UpdatePreparedQueryRequest) GetLedger() string { @@ -7262,7 +7318,7 @@ type UpdatePreparedQueryResponse struct { func (x *UpdatePreparedQueryResponse) Reset() { *x = UpdatePreparedQueryResponse{} - mi := &file_bucket_proto_msgTypes[105] + mi := &file_bucket_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7274,7 +7330,7 @@ func (x *UpdatePreparedQueryResponse) String() string { func (*UpdatePreparedQueryResponse) ProtoMessage() {} func (x *UpdatePreparedQueryResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[105] + mi := &file_bucket_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7287,7 +7343,7 @@ func (x *UpdatePreparedQueryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdatePreparedQueryResponse.ProtoReflect.Descriptor instead. func (*UpdatePreparedQueryResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{105} + return file_bucket_proto_rawDescGZIP(), []int{106} } type DeletePreparedQueryRequest struct { @@ -7300,7 +7356,7 @@ type DeletePreparedQueryRequest struct { func (x *DeletePreparedQueryRequest) Reset() { *x = DeletePreparedQueryRequest{} - mi := &file_bucket_proto_msgTypes[106] + mi := &file_bucket_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7312,7 +7368,7 @@ func (x *DeletePreparedQueryRequest) String() string { func (*DeletePreparedQueryRequest) ProtoMessage() {} func (x *DeletePreparedQueryRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[106] + mi := &file_bucket_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7325,7 +7381,7 @@ func (x *DeletePreparedQueryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletePreparedQueryRequest.ProtoReflect.Descriptor instead. func (*DeletePreparedQueryRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{106} + return file_bucket_proto_rawDescGZIP(), []int{107} } func (x *DeletePreparedQueryRequest) GetLedger() string { @@ -7350,7 +7406,7 @@ type DeletePreparedQueryResponse struct { func (x *DeletePreparedQueryResponse) Reset() { *x = DeletePreparedQueryResponse{} - mi := &file_bucket_proto_msgTypes[107] + mi := &file_bucket_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7362,7 +7418,7 @@ func (x *DeletePreparedQueryResponse) String() string { func (*DeletePreparedQueryResponse) ProtoMessage() {} func (x *DeletePreparedQueryResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[107] + mi := &file_bucket_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7375,7 +7431,7 @@ func (x *DeletePreparedQueryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletePreparedQueryResponse.ProtoReflect.Descriptor instead. func (*DeletePreparedQueryResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{107} + return file_bucket_proto_rawDescGZIP(), []int{108} } type ListPreparedQueriesRequest struct { @@ -7387,7 +7443,7 @@ type ListPreparedQueriesRequest struct { func (x *ListPreparedQueriesRequest) Reset() { *x = ListPreparedQueriesRequest{} - mi := &file_bucket_proto_msgTypes[108] + mi := &file_bucket_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7399,7 +7455,7 @@ func (x *ListPreparedQueriesRequest) String() string { func (*ListPreparedQueriesRequest) ProtoMessage() {} func (x *ListPreparedQueriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[108] + mi := &file_bucket_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7412,7 +7468,7 @@ func (x *ListPreparedQueriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListPreparedQueriesRequest.ProtoReflect.Descriptor instead. func (*ListPreparedQueriesRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{108} + return file_bucket_proto_rawDescGZIP(), []int{109} } func (x *ListPreparedQueriesRequest) GetLedger() string { @@ -7431,7 +7487,7 @@ type ListPreparedQueriesResponse struct { func (x *ListPreparedQueriesResponse) Reset() { *x = ListPreparedQueriesResponse{} - mi := &file_bucket_proto_msgTypes[109] + mi := &file_bucket_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7443,7 +7499,7 @@ func (x *ListPreparedQueriesResponse) String() string { func (*ListPreparedQueriesResponse) ProtoMessage() {} func (x *ListPreparedQueriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[109] + mi := &file_bucket_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7456,7 +7512,7 @@ func (x *ListPreparedQueriesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListPreparedQueriesResponse.ProtoReflect.Descriptor instead. func (*ListPreparedQueriesResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{109} + return file_bucket_proto_rawDescGZIP(), []int{110} } func (x *ListPreparedQueriesResponse) GetQueries() []*commonpb.PreparedQuery { @@ -7481,7 +7537,7 @@ type ExecutePreparedQueryRequest struct { func (x *ExecutePreparedQueryRequest) Reset() { *x = ExecutePreparedQueryRequest{} - mi := &file_bucket_proto_msgTypes[110] + mi := &file_bucket_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7493,7 +7549,7 @@ func (x *ExecutePreparedQueryRequest) String() string { func (*ExecutePreparedQueryRequest) ProtoMessage() {} func (x *ExecutePreparedQueryRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[110] + mi := &file_bucket_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7506,7 +7562,7 @@ func (x *ExecutePreparedQueryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutePreparedQueryRequest.ProtoReflect.Descriptor instead. func (*ExecutePreparedQueryRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{110} + return file_bucket_proto_rawDescGZIP(), []int{111} } func (x *ExecutePreparedQueryRequest) GetLedger() string { @@ -7571,7 +7627,7 @@ type ExecutePreparedQueryResponse struct { func (x *ExecutePreparedQueryResponse) Reset() { *x = ExecutePreparedQueryResponse{} - mi := &file_bucket_proto_msgTypes[111] + mi := &file_bucket_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7583,7 +7639,7 @@ func (x *ExecutePreparedQueryResponse) String() string { func (*ExecutePreparedQueryResponse) ProtoMessage() {} func (x *ExecutePreparedQueryResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[111] + mi := &file_bucket_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7596,7 +7652,7 @@ func (x *ExecutePreparedQueryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutePreparedQueryResponse.ProtoReflect.Descriptor instead. func (*ExecutePreparedQueryResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{111} + return file_bucket_proto_rawDescGZIP(), []int{112} } func (x *ExecutePreparedQueryResponse) GetResult() isExecutePreparedQueryResponse_Result { @@ -7654,7 +7710,7 @@ type GetIndexStatusRequest struct { func (x *GetIndexStatusRequest) Reset() { *x = GetIndexStatusRequest{} - mi := &file_bucket_proto_msgTypes[112] + mi := &file_bucket_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7666,7 +7722,7 @@ func (x *GetIndexStatusRequest) String() string { func (*GetIndexStatusRequest) ProtoMessage() {} func (x *GetIndexStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[112] + mi := &file_bucket_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7679,7 +7735,7 @@ func (x *GetIndexStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetIndexStatusRequest.ProtoReflect.Descriptor instead. func (*GetIndexStatusRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{112} + return file_bucket_proto_rawDescGZIP(), []int{113} } func (x *GetIndexStatusRequest) GetLedger() string { @@ -7702,7 +7758,7 @@ type GetIndexStatusResponse struct { func (x *GetIndexStatusResponse) Reset() { *x = GetIndexStatusResponse{} - mi := &file_bucket_proto_msgTypes[113] + mi := &file_bucket_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7714,7 +7770,7 @@ func (x *GetIndexStatusResponse) String() string { func (*GetIndexStatusResponse) ProtoMessage() {} func (x *GetIndexStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[113] + mi := &file_bucket_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7727,7 +7783,7 @@ func (x *GetIndexStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetIndexStatusResponse.ProtoReflect.Descriptor instead. func (*GetIndexStatusResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{113} + return file_bucket_proto_rawDescGZIP(), []int{114} } func (x *GetIndexStatusResponse) GetLastIndexedSequence() uint64 { @@ -7778,7 +7834,7 @@ type GetIndexRequest struct { func (x *GetIndexRequest) Reset() { *x = GetIndexRequest{} - mi := &file_bucket_proto_msgTypes[114] + mi := &file_bucket_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7790,7 +7846,7 @@ func (x *GetIndexRequest) String() string { func (*GetIndexRequest) ProtoMessage() {} func (x *GetIndexRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[114] + mi := &file_bucket_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7803,7 +7859,7 @@ func (x *GetIndexRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetIndexRequest.ProtoReflect.Descriptor instead. func (*GetIndexRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{114} + return file_bucket_proto_rawDescGZIP(), []int{115} } func (x *GetIndexRequest) GetLedger() string { @@ -7833,7 +7889,7 @@ type GetIndexEntryStatusRequest struct { func (x *GetIndexEntryStatusRequest) Reset() { *x = GetIndexEntryStatusRequest{} - mi := &file_bucket_proto_msgTypes[115] + mi := &file_bucket_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7845,7 +7901,7 @@ func (x *GetIndexEntryStatusRequest) String() string { func (*GetIndexEntryStatusRequest) ProtoMessage() {} func (x *GetIndexEntryStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[115] + mi := &file_bucket_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7858,7 +7914,7 @@ func (x *GetIndexEntryStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetIndexEntryStatusRequest.ProtoReflect.Descriptor instead. func (*GetIndexEntryStatusRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{115} + return file_bucket_proto_rawDescGZIP(), []int{116} } func (x *GetIndexEntryStatusRequest) GetLedger() string { @@ -7901,7 +7957,7 @@ type IndexEntry struct { func (x *IndexEntry) Reset() { *x = IndexEntry{} - mi := &file_bucket_proto_msgTypes[116] + mi := &file_bucket_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7913,7 +7969,7 @@ func (x *IndexEntry) String() string { func (*IndexEntry) ProtoMessage() {} func (x *IndexEntry) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[116] + mi := &file_bucket_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7926,7 +7982,7 @@ func (x *IndexEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexEntry.ProtoReflect.Descriptor instead. func (*IndexEntry) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{116} + return file_bucket_proto_rawDescGZIP(), []int{117} } func (x *IndexEntry) GetLedger() string { @@ -7985,7 +8041,7 @@ type ListIndexesRequest struct { func (x *ListIndexesRequest) Reset() { *x = ListIndexesRequest{} - mi := &file_bucket_proto_msgTypes[117] + mi := &file_bucket_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7997,7 +8053,7 @@ func (x *ListIndexesRequest) String() string { func (*ListIndexesRequest) ProtoMessage() {} func (x *ListIndexesRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[117] + mi := &file_bucket_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8010,7 +8066,7 @@ func (x *ListIndexesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListIndexesRequest.ProtoReflect.Descriptor instead. func (*ListIndexesRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{117} + return file_bucket_proto_rawDescGZIP(), []int{118} } func (x *ListIndexesRequest) GetScope() ListIndexesRequest_Scope { @@ -8038,7 +8094,7 @@ type GetLedgerStatsRequest struct { func (x *GetLedgerStatsRequest) Reset() { *x = GetLedgerStatsRequest{} - mi := &file_bucket_proto_msgTypes[118] + mi := &file_bucket_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8050,7 +8106,7 @@ func (x *GetLedgerStatsRequest) String() string { func (*GetLedgerStatsRequest) ProtoMessage() {} func (x *GetLedgerStatsRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[118] + mi := &file_bucket_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8063,7 +8119,7 @@ func (x *GetLedgerStatsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLedgerStatsRequest.ProtoReflect.Descriptor instead. func (*GetLedgerStatsRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{118} + return file_bucket_proto_rawDescGZIP(), []int{119} } func (x *GetLedgerStatsRequest) GetLedger() string { @@ -8103,7 +8159,7 @@ type AggregateVolumesRequest struct { func (x *AggregateVolumesRequest) Reset() { *x = AggregateVolumesRequest{} - mi := &file_bucket_proto_msgTypes[119] + mi := &file_bucket_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8115,7 +8171,7 @@ func (x *AggregateVolumesRequest) String() string { func (*AggregateVolumesRequest) ProtoMessage() {} func (x *AggregateVolumesRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[119] + mi := &file_bucket_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8128,7 +8184,7 @@ func (x *AggregateVolumesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregateVolumesRequest.ProtoReflect.Descriptor instead. func (*AggregateVolumesRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{119} + return file_bucket_proto_rawDescGZIP(), []int{120} } func (x *AggregateVolumesRequest) GetLedger() string { @@ -8197,7 +8253,7 @@ type QueryProfile struct { func (x *QueryProfile) Reset() { *x = QueryProfile{} - mi := &file_bucket_proto_msgTypes[120] + mi := &file_bucket_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8209,7 +8265,7 @@ func (x *QueryProfile) String() string { func (*QueryProfile) ProtoMessage() {} func (x *QueryProfile) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[120] + mi := &file_bucket_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8222,7 +8278,7 @@ func (x *QueryProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryProfile.ProtoReflect.Descriptor instead. func (*QueryProfile) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{120} + return file_bucket_proto_rawDescGZIP(), []int{121} } func (x *QueryProfile) GetIndexDurationUs() int64 { @@ -8299,7 +8355,7 @@ type IteratorProfile struct { func (x *IteratorProfile) Reset() { *x = IteratorProfile{} - mi := &file_bucket_proto_msgTypes[121] + mi := &file_bucket_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8311,7 +8367,7 @@ func (x *IteratorProfile) String() string { func (*IteratorProfile) ProtoMessage() {} func (x *IteratorProfile) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[121] + mi := &file_bucket_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8324,7 +8380,7 @@ func (x *IteratorProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use IteratorProfile.ProtoReflect.Descriptor instead. func (*IteratorProfile) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{121} + return file_bucket_proto_rawDescGZIP(), []int{122} } func (x *IteratorProfile) GetLabel() string { @@ -8419,7 +8475,7 @@ type InspectIndexRequest struct { func (x *InspectIndexRequest) Reset() { *x = InspectIndexRequest{} - mi := &file_bucket_proto_msgTypes[122] + mi := &file_bucket_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8431,7 +8487,7 @@ func (x *InspectIndexRequest) String() string { func (*InspectIndexRequest) ProtoMessage() {} func (x *InspectIndexRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[122] + mi := &file_bucket_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8444,7 +8500,7 @@ func (x *InspectIndexRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use InspectIndexRequest.ProtoReflect.Descriptor instead. func (*InspectIndexRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{122} + return file_bucket_proto_rawDescGZIP(), []int{123} } func (x *InspectIndexRequest) GetLedger() string { @@ -8510,7 +8566,7 @@ type InspectIndexResponse struct { func (x *InspectIndexResponse) Reset() { *x = InspectIndexResponse{} - mi := &file_bucket_proto_msgTypes[123] + mi := &file_bucket_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8522,7 +8578,7 @@ func (x *InspectIndexResponse) String() string { func (*InspectIndexResponse) ProtoMessage() {} func (x *InspectIndexResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[123] + mi := &file_bucket_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8535,7 +8591,7 @@ func (x *InspectIndexResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use InspectIndexResponse.ProtoReflect.Descriptor instead. func (*InspectIndexResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{123} + return file_bucket_proto_rawDescGZIP(), []int{124} } func (x *InspectIndexResponse) GetResult() isInspectIndexResponse_Result { @@ -8605,7 +8661,7 @@ type InspectDistinctValues struct { func (x *InspectDistinctValues) Reset() { *x = InspectDistinctValues{} - mi := &file_bucket_proto_msgTypes[124] + mi := &file_bucket_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8617,7 +8673,7 @@ func (x *InspectDistinctValues) String() string { func (*InspectDistinctValues) ProtoMessage() {} func (x *InspectDistinctValues) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[124] + mi := &file_bucket_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8630,7 +8686,7 @@ func (x *InspectDistinctValues) ProtoReflect() protoreflect.Message { // Deprecated: Use InspectDistinctValues.ProtoReflect.Descriptor instead. func (*InspectDistinctValues) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{124} + return file_bucket_proto_rawDescGZIP(), []int{125} } func (x *InspectDistinctValues) GetValues() []*commonpb.MetadataValue { @@ -8664,7 +8720,7 @@ type InspectFacet struct { func (x *InspectFacet) Reset() { *x = InspectFacet{} - mi := &file_bucket_proto_msgTypes[125] + mi := &file_bucket_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8676,7 +8732,7 @@ func (x *InspectFacet) String() string { func (*InspectFacet) ProtoMessage() {} func (x *InspectFacet) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[125] + mi := &file_bucket_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8689,7 +8745,7 @@ func (x *InspectFacet) ProtoReflect() protoreflect.Message { // Deprecated: Use InspectFacet.ProtoReflect.Descriptor instead. func (*InspectFacet) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{125} + return file_bucket_proto_rawDescGZIP(), []int{126} } func (x *InspectFacet) GetValue() *commonpb.MetadataValue { @@ -8717,7 +8773,7 @@ type InspectFacets struct { func (x *InspectFacets) Reset() { *x = InspectFacets{} - mi := &file_bucket_proto_msgTypes[126] + mi := &file_bucket_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8729,7 +8785,7 @@ func (x *InspectFacets) String() string { func (*InspectFacets) ProtoMessage() {} func (x *InspectFacets) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[126] + mi := &file_bucket_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8742,7 +8798,7 @@ func (x *InspectFacets) ProtoReflect() protoreflect.Message { // Deprecated: Use InspectFacets.ProtoReflect.Descriptor instead. func (*InspectFacets) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{126} + return file_bucket_proto_rawDescGZIP(), []int{127} } func (x *InspectFacets) GetFacets() []*InspectFacet { @@ -8779,7 +8835,7 @@ type InspectSummary struct { func (x *InspectSummary) Reset() { *x = InspectSummary{} - mi := &file_bucket_proto_msgTypes[127] + mi := &file_bucket_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8791,7 +8847,7 @@ func (x *InspectSummary) String() string { func (*InspectSummary) ProtoMessage() {} func (x *InspectSummary) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[127] + mi := &file_bucket_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8804,7 +8860,7 @@ func (x *InspectSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use InspectSummary.ProtoReflect.Descriptor instead. func (*InspectSummary) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{127} + return file_bucket_proto_rawDescGZIP(), []int{128} } func (x *InspectSummary) GetCardinality() uint64 { @@ -8850,7 +8906,7 @@ type BarrierRequest struct { func (x *BarrierRequest) Reset() { *x = BarrierRequest{} - mi := &file_bucket_proto_msgTypes[128] + mi := &file_bucket_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8862,7 +8918,7 @@ func (x *BarrierRequest) String() string { func (*BarrierRequest) ProtoMessage() {} func (x *BarrierRequest) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[128] + mi := &file_bucket_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8875,7 +8931,7 @@ func (x *BarrierRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BarrierRequest.ProtoReflect.Descriptor instead. func (*BarrierRequest) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{128} + return file_bucket_proto_rawDescGZIP(), []int{129} } type BarrierResponse struct { @@ -8891,7 +8947,7 @@ type BarrierResponse struct { func (x *BarrierResponse) Reset() { *x = BarrierResponse{} - mi := &file_bucket_proto_msgTypes[129] + mi := &file_bucket_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8903,7 +8959,7 @@ func (x *BarrierResponse) String() string { func (*BarrierResponse) ProtoMessage() {} func (x *BarrierResponse) ProtoReflect() protoreflect.Message { - mi := &file_bucket_proto_msgTypes[129] + mi := &file_bucket_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8916,7 +8972,7 @@ func (x *BarrierResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BarrierResponse.ProtoReflect.Descriptor instead. func (*BarrierResponse) Descriptor() ([]byte, []int) { - return file_bucket_proto_rawDescGZIP(), []int{129} + return file_bucket_proto_rawDescGZIP(), []int{130} } func (x *BarrierResponse) GetCommitIndex() uint64 { @@ -9115,7 +9171,10 @@ const file_bucket_proto_rawDesc = "" + "\x04read\x18\x04 \x01(\v2\x13.common.ReadOptionsR\x04readR\rcheckpoint_id\"^\n" + "\x15ListNumscriptsRequest\x12\x16\n" + "\x06ledger\x18\x01 \x01(\tR\x06ledger\x12-\n" + - "\aoptions\x18\x02 \x01(\v2\x13.common.ListOptionsR\aoptions\"\xaf\x01\n" + + "\aoptions\x18\x02 \x01(\v2\x13.common.ListOptionsR\aoptions\"E\n" + + "\x17GetTemplateUsageRequest\x12\x16\n" + + "\x06ledger\x18\x01 \x01(\tR\x06ledger\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\"\xaf\x01\n" + "\x0fScriptReference\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + "\aversion\x18\x02 \x01(\tR\aversion\x125\n" + @@ -9593,7 +9652,7 @@ const file_bucket_proto_rawDesc = "" + "\x10InspectIndexMode\x12&\n" + "\"INSPECT_INDEX_MODE_DISTINCT_VALUES\x10\x00\x12\x1d\n" + "\x19INSPECT_INDEX_MODE_FACETS\x10\x01\x12\x1e\n" + - "\x1aINSPECT_INDEX_MODE_SUMMARY\x10\x022\xf7\x15\n" + + "\x1aINSPECT_INDEX_MODE_SUMMARY\x10\x022\xc3\x16\n" + "\rBucketService\x12?\n" + "\vListLedgers\x12\x1a.ledger.ListLedgersRequest\x1a\x12.common.LedgerInfo0\x01\x129\n" + "\tGetLedger\x12\x18.ledger.GetLedgerRequest\x1a\x12.common.LedgerInfo\x128\n" + @@ -9631,7 +9690,8 @@ const file_bucket_proto_rawDesc = "" + "\x0eGetLedgerStats\x12\x1d.ledger.GetLedgerStatsRequest\x1a\x13.common.LedgerStats\x12L\n" + "\x10AggregateVolumes\x12\x1f.ledger.AggregateVolumesRequest\x1a\x17.common.AggregateResult\x12B\n" + "\fGetNumscript\x12\x1b.ledger.GetNumscriptRequest\x1a\x15.common.NumscriptInfo\x12H\n" + - "\x0eListNumscripts\x12\x1d.ledger.ListNumscriptsRequest\x1a\x15.common.NumscriptInfo0\x01\x12I\n" + + "\x0eListNumscripts\x12\x1d.ledger.ListNumscriptsRequest\x1a\x15.common.NumscriptInfo0\x01\x12J\n" + + "\x10GetTemplateUsage\x12\x1f.ledger.GetTemplateUsageRequest\x1a\x15.common.TemplateUsage\x12I\n" + "\fInspectIndex\x12\x1b.ledger.InspectIndexRequest\x1a\x1c.ledger.InspectIndexResponse\x12:\n" + "\aBarrier\x12\x16.ledger.BarrierRequest\x1a\x17.ledger.BarrierResponse:p\n" + "\x19allowed_skippable_reasons\x12\x1d.google.protobuf.FieldOptions\x18٪\x04 \x03(\x0e2\x13.common.ErrorReasonR\x17allowedSkippableReasonsB:Z8github.com/formancehq/ledger/v3/internal/proto/servicepbb\x06proto3" @@ -9649,7 +9709,7 @@ func file_bucket_proto_rawDescGZIP() []byte { } var file_bucket_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_bucket_proto_msgTypes = make([]protoimpl.MessageInfo, 140) +var file_bucket_proto_msgTypes = make([]protoimpl.MessageInfo, 141) var file_bucket_proto_goTypes = []any{ (CheckStoreErrorType)(0), // 0: ledger.CheckStoreErrorType (PatternSegmentType)(0), // 1: ledger.PatternSegmentType @@ -9697,162 +9757,164 @@ var file_bucket_proto_goTypes = []any{ (*DeleteNumscriptRequest)(nil), // 43: ledger.DeleteNumscriptRequest (*GetNumscriptRequest)(nil), // 44: ledger.GetNumscriptRequest (*ListNumscriptsRequest)(nil), // 45: ledger.ListNumscriptsRequest - (*ScriptReference)(nil), // 46: ledger.ScriptReference - (*SetQueryCheckpointScheduleRequest)(nil), // 47: ledger.SetQueryCheckpointScheduleRequest - (*DeleteQueryCheckpointScheduleRequest)(nil), // 48: ledger.DeleteQueryCheckpointScheduleRequest - (*GetChapterScheduleRequest)(nil), // 49: ledger.GetChapterScheduleRequest - (*GetChapterScheduleResponse)(nil), // 50: ledger.GetChapterScheduleResponse - (*DiscoveryRequest)(nil), // 51: ledger.DiscoveryRequest - (*ServerInfo)(nil), // 52: ledger.ServerInfo - (*DiscoveryResponse)(nil), // 53: ledger.DiscoveryResponse - (*ResponseSigningInfo)(nil), // 54: ledger.ResponseSigningInfo - (*CreateTransactionPayload)(nil), // 55: ledger.CreateTransactionPayload - (*RevertTransactionPayload)(nil), // 56: ledger.RevertTransactionPayload - (*LedgerAction)(nil), // 57: ledger.LedgerAction - (*LedgerApplyRequest)(nil), // 58: ledger.LedgerApplyRequest - (*AddAccountTypeRequest)(nil), // 59: ledger.AddAccountTypeRequest - (*RemoveAccountTypeRequest)(nil), // 60: ledger.RemoveAccountTypeRequest - (*SetDefaultEnforcementModeRequest)(nil), // 61: ledger.SetDefaultEnforcementModeRequest - (*SetDefaultEnforcementModeLedgerRequest)(nil), // 62: ledger.SetDefaultEnforcementModeLedgerRequest - (*AddAccountTypeLedgerRequest)(nil), // 63: ledger.AddAccountTypeLedgerRequest - (*RemoveAccountTypeLedgerRequest)(nil), // 64: ledger.RemoveAccountTypeLedgerRequest - (*GetPrimaryMetricsRequest)(nil), // 65: ledger.GetPrimaryMetricsRequest - (*GetPrimaryMetricsResponse)(nil), // 66: ledger.GetPrimaryMetricsResponse - (*GetSecondaryMetricsRequest)(nil), // 67: ledger.GetSecondaryMetricsRequest - (*GetSecondaryMetricsResponse)(nil), // 68: ledger.GetSecondaryMetricsResponse - (*PebbleMetrics)(nil), // 69: ledger.PebbleMetrics - (*BlockCacheMetrics)(nil), // 70: ledger.BlockCacheMetrics - (*CompactMetrics)(nil), // 71: ledger.CompactMetrics - (*FlushMetrics)(nil), // 72: ledger.FlushMetrics - (*MemTableMetrics)(nil), // 73: ledger.MemTableMetrics - (*SnapshotsMetrics)(nil), // 74: ledger.SnapshotsMetrics - (*TableMetrics)(nil), // 75: ledger.TableMetrics - (*TableCacheMetrics)(nil), // 76: ledger.TableCacheMetrics - (*WALMetrics)(nil), // 77: ledger.WALMetrics - (*KeysMetrics)(nil), // 78: ledger.KeysMetrics - (*LevelMetrics)(nil), // 79: ledger.LevelMetrics - (*CheckStoreRequest)(nil), // 80: ledger.CheckStoreRequest - (*CheckStoreEvent)(nil), // 81: ledger.CheckStoreEvent - (*CheckStoreError)(nil), // 82: ledger.CheckStoreError - (*CheckStoreProgress)(nil), // 83: ledger.CheckStoreProgress - (*ListAuditEntriesRequest)(nil), // 84: ledger.ListAuditEntriesRequest - (*GetAuditEntryRequest)(nil), // 85: ledger.GetAuditEntryRequest - (*ListLogsRequest)(nil), // 86: ledger.ListLogsRequest - (*GetLogRequest)(nil), // 87: ledger.GetLogRequest - (*GetEventsSinksRequest)(nil), // 88: ledger.GetEventsSinksRequest - (*GetEventsSinksResponse)(nil), // 89: ledger.GetEventsSinksResponse - (*GetMetadataSchemaStatusRequest)(nil), // 90: ledger.GetMetadataSchemaStatusRequest - (*GetMetadataSchemaStatusResponse)(nil), // 91: ledger.GetMetadataSchemaStatusResponse - (*MetadataFieldStatus)(nil), // 92: ledger.MetadataFieldStatus - (*AnalyzeAccountsRequest)(nil), // 93: ledger.AnalyzeAccountsRequest - (*AnalyzeAccountsResponse)(nil), // 94: ledger.AnalyzeAccountsResponse - (*AnalyzeProgress)(nil), // 95: ledger.AnalyzeProgress - (*AnalyzeAccountsEvent)(nil), // 96: ledger.AnalyzeAccountsEvent - (*AnalyzeTransactionsEvent)(nil), // 97: ledger.AnalyzeTransactionsEvent - (*AccountPattern)(nil), // 98: ledger.AccountPattern - (*PatternSegment)(nil), // 99: ledger.PatternSegment - (*AnalyzeTransactionsRequest)(nil), // 100: ledger.AnalyzeTransactionsRequest - (*AnalyzeTransactionsResponse)(nil), // 101: ledger.AnalyzeTransactionsResponse - (*FlowPattern)(nil), // 102: ledger.FlowPattern - (*NormalizedPosting)(nil), // 103: ledger.NormalizedPosting - (*TemporalStats)(nil), // 104: ledger.TemporalStats - (*HourBucket)(nil), // 105: ledger.HourBucket - (*AssetVolumeStats)(nil), // 106: ledger.AssetVolumeStats - (*CreatePreparedQueryRequest)(nil), // 107: ledger.CreatePreparedQueryRequest - (*CreatePreparedQueryResponse)(nil), // 108: ledger.CreatePreparedQueryResponse - (*UpdatePreparedQueryRequest)(nil), // 109: ledger.UpdatePreparedQueryRequest - (*UpdatePreparedQueryResponse)(nil), // 110: ledger.UpdatePreparedQueryResponse - (*DeletePreparedQueryRequest)(nil), // 111: ledger.DeletePreparedQueryRequest - (*DeletePreparedQueryResponse)(nil), // 112: ledger.DeletePreparedQueryResponse - (*ListPreparedQueriesRequest)(nil), // 113: ledger.ListPreparedQueriesRequest - (*ListPreparedQueriesResponse)(nil), // 114: ledger.ListPreparedQueriesResponse - (*ExecutePreparedQueryRequest)(nil), // 115: ledger.ExecutePreparedQueryRequest - (*ExecutePreparedQueryResponse)(nil), // 116: ledger.ExecutePreparedQueryResponse - (*GetIndexStatusRequest)(nil), // 117: ledger.GetIndexStatusRequest - (*GetIndexStatusResponse)(nil), // 118: ledger.GetIndexStatusResponse - (*GetIndexRequest)(nil), // 119: ledger.GetIndexRequest - (*GetIndexEntryStatusRequest)(nil), // 120: ledger.GetIndexEntryStatusRequest - (*IndexEntry)(nil), // 121: ledger.IndexEntry - (*ListIndexesRequest)(nil), // 122: ledger.ListIndexesRequest - (*GetLedgerStatsRequest)(nil), // 123: ledger.GetLedgerStatsRequest - (*AggregateVolumesRequest)(nil), // 124: ledger.AggregateVolumesRequest - (*QueryProfile)(nil), // 125: ledger.QueryProfile - (*IteratorProfile)(nil), // 126: ledger.IteratorProfile - (*InspectIndexRequest)(nil), // 127: ledger.InspectIndexRequest - (*InspectIndexResponse)(nil), // 128: ledger.InspectIndexResponse - (*InspectDistinctValues)(nil), // 129: ledger.InspectDistinctValues - (*InspectFacet)(nil), // 130: ledger.InspectFacet - (*InspectFacets)(nil), // 131: ledger.InspectFacets - (*InspectSummary)(nil), // 132: ledger.InspectSummary - (*BarrierRequest)(nil), // 133: ledger.BarrierRequest - (*BarrierResponse)(nil), // 134: ledger.BarrierResponse - nil, // 135: ledger.CreateLedgerRequest.AccountTypesEntry - nil, // 136: ledger.SaveLedgerMetadataRequest.MetadataEntry - nil, // 137: ledger.ScriptReference.VarsEntry - nil, // 138: ledger.CreateTransactionPayload.MetadataEntry - nil, // 139: ledger.CreateTransactionPayload.AccountMetadataEntry - nil, // 140: ledger.RevertTransactionPayload.MetadataEntry - nil, // 141: ledger.GetMetadataSchemaStatusResponse.AccountFieldsEntry - nil, // 142: ledger.GetMetadataSchemaStatusResponse.TransactionFieldsEntry - nil, // 143: ledger.GetMetadataSchemaStatusResponse.LedgerFieldsEntry - nil, // 144: ledger.ExecutePreparedQueryRequest.ParametersEntry - (*commonpb.Transaction)(nil), // 145: common.Transaction - (*commonpb.ListOptions)(nil), // 146: common.ListOptions - (*commonpb.SetMetadataFieldTypeCommand)(nil), // 147: common.SetMetadataFieldTypeCommand - (commonpb.LedgerMode)(0), // 148: common.LedgerMode - (*commonpb.MirrorSourceConfig)(nil), // 149: common.MirrorSourceConfig - (commonpb.ChartEnforcementMode)(0), // 150: common.ChartEnforcementMode - (*commonpb.ReadOptions)(nil), // 151: common.ReadOptions - (*signaturepb.SignedApplyBatch)(nil), // 152: signature.SignedApplyBatch - (*commonpb.CallerSnapshot)(nil), // 153: common.CallerSnapshot - (*commonpb.Log)(nil), // 154: common.Log - (*commonpb.SinkConfig)(nil), // 155: common.SinkConfig - (commonpb.TargetType)(0), // 156: common.TargetType - (commonpb.MetadataType)(0), // 157: common.MetadataType - (*commonpb.IndexID)(nil), // 158: common.IndexID - (*commonpb.Posting)(nil), // 159: common.Posting - (*commonpb.Script)(nil), // 160: common.Script - (*commonpb.Timestamp)(nil), // 161: common.Timestamp - (*commonpb.SaveMetadataCommand)(nil), // 162: common.SaveMetadataCommand - (*commonpb.DeleteMetadataCommand)(nil), // 163: common.DeleteMetadataCommand - (commonpb.ErrorReason)(0), // 164: common.ErrorReason - (*commonpb.AccountType)(nil), // 165: common.AccountType - (*commonpb.SinkStatus)(nil), // 166: common.SinkStatus - (*commonpb.PreparedQuery)(nil), // 167: common.PreparedQuery - (*commonpb.QueryFilter)(nil), // 168: common.QueryFilter - (commonpb.QueryMode)(0), // 169: common.QueryMode - (*commonpb.PreparedQueryCursor)(nil), // 170: common.PreparedQueryCursor - (*commonpb.AggregateResult)(nil), // 171: common.AggregateResult - (*commonpb.Index)(nil), // 172: common.Index - (*commonpb.MetadataValue)(nil), // 173: common.MetadataValue - (*commonpb.MetadataMap)(nil), // 174: common.MetadataMap - (*commonpb.ParameterValue)(nil), // 175: common.ParameterValue - (*descriptorpb.FieldOptions)(nil), // 176: google.protobuf.FieldOptions - (*commonpb.LedgerInfo)(nil), // 177: common.LedgerInfo - (*commonpb.Account)(nil), // 178: common.Account - (*auditpb.AuditEntry)(nil), // 179: audit.AuditEntry - (*commonpb.Chapter)(nil), // 180: common.Chapter - (*commonpb.SigningKey)(nil), // 181: common.SigningKey - (*commonpb.LedgerStats)(nil), // 182: common.LedgerStats - (*commonpb.NumscriptInfo)(nil), // 183: common.NumscriptInfo + (*GetTemplateUsageRequest)(nil), // 46: ledger.GetTemplateUsageRequest + (*ScriptReference)(nil), // 47: ledger.ScriptReference + (*SetQueryCheckpointScheduleRequest)(nil), // 48: ledger.SetQueryCheckpointScheduleRequest + (*DeleteQueryCheckpointScheduleRequest)(nil), // 49: ledger.DeleteQueryCheckpointScheduleRequest + (*GetChapterScheduleRequest)(nil), // 50: ledger.GetChapterScheduleRequest + (*GetChapterScheduleResponse)(nil), // 51: ledger.GetChapterScheduleResponse + (*DiscoveryRequest)(nil), // 52: ledger.DiscoveryRequest + (*ServerInfo)(nil), // 53: ledger.ServerInfo + (*DiscoveryResponse)(nil), // 54: ledger.DiscoveryResponse + (*ResponseSigningInfo)(nil), // 55: ledger.ResponseSigningInfo + (*CreateTransactionPayload)(nil), // 56: ledger.CreateTransactionPayload + (*RevertTransactionPayload)(nil), // 57: ledger.RevertTransactionPayload + (*LedgerAction)(nil), // 58: ledger.LedgerAction + (*LedgerApplyRequest)(nil), // 59: ledger.LedgerApplyRequest + (*AddAccountTypeRequest)(nil), // 60: ledger.AddAccountTypeRequest + (*RemoveAccountTypeRequest)(nil), // 61: ledger.RemoveAccountTypeRequest + (*SetDefaultEnforcementModeRequest)(nil), // 62: ledger.SetDefaultEnforcementModeRequest + (*SetDefaultEnforcementModeLedgerRequest)(nil), // 63: ledger.SetDefaultEnforcementModeLedgerRequest + (*AddAccountTypeLedgerRequest)(nil), // 64: ledger.AddAccountTypeLedgerRequest + (*RemoveAccountTypeLedgerRequest)(nil), // 65: ledger.RemoveAccountTypeLedgerRequest + (*GetPrimaryMetricsRequest)(nil), // 66: ledger.GetPrimaryMetricsRequest + (*GetPrimaryMetricsResponse)(nil), // 67: ledger.GetPrimaryMetricsResponse + (*GetSecondaryMetricsRequest)(nil), // 68: ledger.GetSecondaryMetricsRequest + (*GetSecondaryMetricsResponse)(nil), // 69: ledger.GetSecondaryMetricsResponse + (*PebbleMetrics)(nil), // 70: ledger.PebbleMetrics + (*BlockCacheMetrics)(nil), // 71: ledger.BlockCacheMetrics + (*CompactMetrics)(nil), // 72: ledger.CompactMetrics + (*FlushMetrics)(nil), // 73: ledger.FlushMetrics + (*MemTableMetrics)(nil), // 74: ledger.MemTableMetrics + (*SnapshotsMetrics)(nil), // 75: ledger.SnapshotsMetrics + (*TableMetrics)(nil), // 76: ledger.TableMetrics + (*TableCacheMetrics)(nil), // 77: ledger.TableCacheMetrics + (*WALMetrics)(nil), // 78: ledger.WALMetrics + (*KeysMetrics)(nil), // 79: ledger.KeysMetrics + (*LevelMetrics)(nil), // 80: ledger.LevelMetrics + (*CheckStoreRequest)(nil), // 81: ledger.CheckStoreRequest + (*CheckStoreEvent)(nil), // 82: ledger.CheckStoreEvent + (*CheckStoreError)(nil), // 83: ledger.CheckStoreError + (*CheckStoreProgress)(nil), // 84: ledger.CheckStoreProgress + (*ListAuditEntriesRequest)(nil), // 85: ledger.ListAuditEntriesRequest + (*GetAuditEntryRequest)(nil), // 86: ledger.GetAuditEntryRequest + (*ListLogsRequest)(nil), // 87: ledger.ListLogsRequest + (*GetLogRequest)(nil), // 88: ledger.GetLogRequest + (*GetEventsSinksRequest)(nil), // 89: ledger.GetEventsSinksRequest + (*GetEventsSinksResponse)(nil), // 90: ledger.GetEventsSinksResponse + (*GetMetadataSchemaStatusRequest)(nil), // 91: ledger.GetMetadataSchemaStatusRequest + (*GetMetadataSchemaStatusResponse)(nil), // 92: ledger.GetMetadataSchemaStatusResponse + (*MetadataFieldStatus)(nil), // 93: ledger.MetadataFieldStatus + (*AnalyzeAccountsRequest)(nil), // 94: ledger.AnalyzeAccountsRequest + (*AnalyzeAccountsResponse)(nil), // 95: ledger.AnalyzeAccountsResponse + (*AnalyzeProgress)(nil), // 96: ledger.AnalyzeProgress + (*AnalyzeAccountsEvent)(nil), // 97: ledger.AnalyzeAccountsEvent + (*AnalyzeTransactionsEvent)(nil), // 98: ledger.AnalyzeTransactionsEvent + (*AccountPattern)(nil), // 99: ledger.AccountPattern + (*PatternSegment)(nil), // 100: ledger.PatternSegment + (*AnalyzeTransactionsRequest)(nil), // 101: ledger.AnalyzeTransactionsRequest + (*AnalyzeTransactionsResponse)(nil), // 102: ledger.AnalyzeTransactionsResponse + (*FlowPattern)(nil), // 103: ledger.FlowPattern + (*NormalizedPosting)(nil), // 104: ledger.NormalizedPosting + (*TemporalStats)(nil), // 105: ledger.TemporalStats + (*HourBucket)(nil), // 106: ledger.HourBucket + (*AssetVolumeStats)(nil), // 107: ledger.AssetVolumeStats + (*CreatePreparedQueryRequest)(nil), // 108: ledger.CreatePreparedQueryRequest + (*CreatePreparedQueryResponse)(nil), // 109: ledger.CreatePreparedQueryResponse + (*UpdatePreparedQueryRequest)(nil), // 110: ledger.UpdatePreparedQueryRequest + (*UpdatePreparedQueryResponse)(nil), // 111: ledger.UpdatePreparedQueryResponse + (*DeletePreparedQueryRequest)(nil), // 112: ledger.DeletePreparedQueryRequest + (*DeletePreparedQueryResponse)(nil), // 113: ledger.DeletePreparedQueryResponse + (*ListPreparedQueriesRequest)(nil), // 114: ledger.ListPreparedQueriesRequest + (*ListPreparedQueriesResponse)(nil), // 115: ledger.ListPreparedQueriesResponse + (*ExecutePreparedQueryRequest)(nil), // 116: ledger.ExecutePreparedQueryRequest + (*ExecutePreparedQueryResponse)(nil), // 117: ledger.ExecutePreparedQueryResponse + (*GetIndexStatusRequest)(nil), // 118: ledger.GetIndexStatusRequest + (*GetIndexStatusResponse)(nil), // 119: ledger.GetIndexStatusResponse + (*GetIndexRequest)(nil), // 120: ledger.GetIndexRequest + (*GetIndexEntryStatusRequest)(nil), // 121: ledger.GetIndexEntryStatusRequest + (*IndexEntry)(nil), // 122: ledger.IndexEntry + (*ListIndexesRequest)(nil), // 123: ledger.ListIndexesRequest + (*GetLedgerStatsRequest)(nil), // 124: ledger.GetLedgerStatsRequest + (*AggregateVolumesRequest)(nil), // 125: ledger.AggregateVolumesRequest + (*QueryProfile)(nil), // 126: ledger.QueryProfile + (*IteratorProfile)(nil), // 127: ledger.IteratorProfile + (*InspectIndexRequest)(nil), // 128: ledger.InspectIndexRequest + (*InspectIndexResponse)(nil), // 129: ledger.InspectIndexResponse + (*InspectDistinctValues)(nil), // 130: ledger.InspectDistinctValues + (*InspectFacet)(nil), // 131: ledger.InspectFacet + (*InspectFacets)(nil), // 132: ledger.InspectFacets + (*InspectSummary)(nil), // 133: ledger.InspectSummary + (*BarrierRequest)(nil), // 134: ledger.BarrierRequest + (*BarrierResponse)(nil), // 135: ledger.BarrierResponse + nil, // 136: ledger.CreateLedgerRequest.AccountTypesEntry + nil, // 137: ledger.SaveLedgerMetadataRequest.MetadataEntry + nil, // 138: ledger.ScriptReference.VarsEntry + nil, // 139: ledger.CreateTransactionPayload.MetadataEntry + nil, // 140: ledger.CreateTransactionPayload.AccountMetadataEntry + nil, // 141: ledger.RevertTransactionPayload.MetadataEntry + nil, // 142: ledger.GetMetadataSchemaStatusResponse.AccountFieldsEntry + nil, // 143: ledger.GetMetadataSchemaStatusResponse.TransactionFieldsEntry + nil, // 144: ledger.GetMetadataSchemaStatusResponse.LedgerFieldsEntry + nil, // 145: ledger.ExecutePreparedQueryRequest.ParametersEntry + (*commonpb.Transaction)(nil), // 146: common.Transaction + (*commonpb.ListOptions)(nil), // 147: common.ListOptions + (*commonpb.SetMetadataFieldTypeCommand)(nil), // 148: common.SetMetadataFieldTypeCommand + (commonpb.LedgerMode)(0), // 149: common.LedgerMode + (*commonpb.MirrorSourceConfig)(nil), // 150: common.MirrorSourceConfig + (commonpb.ChartEnforcementMode)(0), // 151: common.ChartEnforcementMode + (*commonpb.ReadOptions)(nil), // 152: common.ReadOptions + (*signaturepb.SignedApplyBatch)(nil), // 153: signature.SignedApplyBatch + (*commonpb.CallerSnapshot)(nil), // 154: common.CallerSnapshot + (*commonpb.Log)(nil), // 155: common.Log + (*commonpb.SinkConfig)(nil), // 156: common.SinkConfig + (commonpb.TargetType)(0), // 157: common.TargetType + (commonpb.MetadataType)(0), // 158: common.MetadataType + (*commonpb.IndexID)(nil), // 159: common.IndexID + (*commonpb.Posting)(nil), // 160: common.Posting + (*commonpb.Script)(nil), // 161: common.Script + (*commonpb.Timestamp)(nil), // 162: common.Timestamp + (*commonpb.SaveMetadataCommand)(nil), // 163: common.SaveMetadataCommand + (*commonpb.DeleteMetadataCommand)(nil), // 164: common.DeleteMetadataCommand + (commonpb.ErrorReason)(0), // 165: common.ErrorReason + (*commonpb.AccountType)(nil), // 166: common.AccountType + (*commonpb.SinkStatus)(nil), // 167: common.SinkStatus + (*commonpb.PreparedQuery)(nil), // 168: common.PreparedQuery + (*commonpb.QueryFilter)(nil), // 169: common.QueryFilter + (commonpb.QueryMode)(0), // 170: common.QueryMode + (*commonpb.PreparedQueryCursor)(nil), // 171: common.PreparedQueryCursor + (*commonpb.AggregateResult)(nil), // 172: common.AggregateResult + (*commonpb.Index)(nil), // 173: common.Index + (*commonpb.MetadataValue)(nil), // 174: common.MetadataValue + (*commonpb.MetadataMap)(nil), // 175: common.MetadataMap + (*commonpb.ParameterValue)(nil), // 176: common.ParameterValue + (*descriptorpb.FieldOptions)(nil), // 177: google.protobuf.FieldOptions + (*commonpb.LedgerInfo)(nil), // 178: common.LedgerInfo + (*commonpb.Account)(nil), // 179: common.Account + (*auditpb.AuditEntry)(nil), // 180: audit.AuditEntry + (*commonpb.Chapter)(nil), // 181: common.Chapter + (*commonpb.SigningKey)(nil), // 182: common.SigningKey + (*commonpb.LedgerStats)(nil), // 183: common.LedgerStats + (*commonpb.NumscriptInfo)(nil), // 184: common.NumscriptInfo + (*commonpb.TemplateUsage)(nil), // 185: common.TemplateUsage } var file_bucket_proto_depIdxs = []int32{ - 145, // 0: ledger.GetTransactionResponse.transaction:type_name -> common.Transaction - 146, // 1: ledger.ListTransactionsRequest.options:type_name -> common.ListOptions - 146, // 2: ledger.ListAccountsRequest.options:type_name -> common.ListOptions - 147, // 3: ledger.CreateLedgerRequest.initial_schema:type_name -> common.SetMetadataFieldTypeCommand - 148, // 4: ledger.CreateLedgerRequest.mode:type_name -> common.LedgerMode - 149, // 5: ledger.CreateLedgerRequest.mirror_source:type_name -> common.MirrorSourceConfig - 135, // 6: ledger.CreateLedgerRequest.account_types:type_name -> ledger.CreateLedgerRequest.AccountTypesEntry - 150, // 7: ledger.CreateLedgerRequest.default_enforcement_mode:type_name -> common.ChartEnforcementMode - 146, // 8: ledger.ListLedgersRequest.options:type_name -> common.ListOptions - 151, // 9: ledger.GetLedgerRequest.read:type_name -> common.ReadOptions + 146, // 0: ledger.GetTransactionResponse.transaction:type_name -> common.Transaction + 147, // 1: ledger.ListTransactionsRequest.options:type_name -> common.ListOptions + 147, // 2: ledger.ListAccountsRequest.options:type_name -> common.ListOptions + 148, // 3: ledger.CreateLedgerRequest.initial_schema:type_name -> common.SetMetadataFieldTypeCommand + 149, // 4: ledger.CreateLedgerRequest.mode:type_name -> common.LedgerMode + 150, // 5: ledger.CreateLedgerRequest.mirror_source:type_name -> common.MirrorSourceConfig + 136, // 6: ledger.CreateLedgerRequest.account_types:type_name -> ledger.CreateLedgerRequest.AccountTypesEntry + 151, // 7: ledger.CreateLedgerRequest.default_enforcement_mode:type_name -> common.ChartEnforcementMode + 147, // 8: ledger.ListLedgersRequest.options:type_name -> common.ListOptions + 152, // 9: ledger.GetLedgerRequest.read:type_name -> common.ReadOptions 16, // 10: ledger.ApplyRequest.unsigned:type_name -> ledger.ApplyBatch - 152, // 11: ledger.ApplyRequest.signed:type_name -> signature.SignedApplyBatch - 153, // 12: ledger.ApplyRequest.forwarded_caller_snapshot:type_name -> common.CallerSnapshot + 153, // 11: ledger.ApplyRequest.signed:type_name -> signature.SignedApplyBatch + 154, // 12: ledger.ApplyRequest.forwarded_caller_snapshot:type_name -> common.CallerSnapshot 18, // 13: ledger.ApplyBatch.requests:type_name -> ledger.Request - 154, // 14: ledger.ApplyResponse.logs:type_name -> common.Log - 58, // 15: ledger.Request.apply:type_name -> ledger.LedgerApplyRequest + 155, // 14: ledger.ApplyResponse.logs:type_name -> common.Log + 59, // 15: ledger.Request.apply:type_name -> ledger.LedgerApplyRequest 10, // 16: ledger.Request.create_ledger:type_name -> ledger.CreateLedgerRequest 11, // 17: ledger.Request.delete_ledger:type_name -> ledger.DeleteLedgerRequest 26, // 18: ledger.Request.register_signing_key:type_name -> ledger.RegisterSigningKeyRequest @@ -9870,130 +9932,130 @@ var file_bucket_proto_depIdxs = []int32{ 38, // 30: ledger.Request.set_metadata_field_type:type_name -> ledger.SetMetadataFieldTypeRequest 39, // 31: ledger.Request.remove_metadata_field_type:type_name -> ledger.RemoveMetadataFieldTypeRequest 21, // 32: ledger.Request.promote_ledger:type_name -> ledger.PromoteLedgerRequest - 107, // 33: ledger.Request.create_prepared_query:type_name -> ledger.CreatePreparedQueryRequest - 109, // 34: ledger.Request.update_prepared_query:type_name -> ledger.UpdatePreparedQueryRequest - 111, // 35: ledger.Request.delete_prepared_query:type_name -> ledger.DeletePreparedQueryRequest + 108, // 33: ledger.Request.create_prepared_query:type_name -> ledger.CreatePreparedQueryRequest + 110, // 34: ledger.Request.update_prepared_query:type_name -> ledger.UpdatePreparedQueryRequest + 112, // 35: ledger.Request.delete_prepared_query:type_name -> ledger.DeletePreparedQueryRequest 40, // 36: ledger.Request.create_index:type_name -> ledger.CreateIndexRequest 41, // 37: ledger.Request.drop_index:type_name -> ledger.DropIndexRequest 42, // 38: ledger.Request.save_numscript:type_name -> ledger.SaveNumscriptRequest 43, // 39: ledger.Request.delete_numscript:type_name -> ledger.DeleteNumscriptRequest - 63, // 40: ledger.Request.add_account_type:type_name -> ledger.AddAccountTypeLedgerRequest - 64, // 41: ledger.Request.remove_account_type:type_name -> ledger.RemoveAccountTypeLedgerRequest - 62, // 42: ledger.Request.set_default_enforcement_mode:type_name -> ledger.SetDefaultEnforcementModeLedgerRequest + 64, // 40: ledger.Request.add_account_type:type_name -> ledger.AddAccountTypeLedgerRequest + 65, // 41: ledger.Request.remove_account_type:type_name -> ledger.RemoveAccountTypeLedgerRequest + 63, // 42: ledger.Request.set_default_enforcement_mode:type_name -> ledger.SetDefaultEnforcementModeLedgerRequest 19, // 43: ledger.Request.create_query_checkpoint:type_name -> ledger.CreateQueryCheckpointRequest 20, // 44: ledger.Request.delete_query_checkpoint:type_name -> ledger.DeleteQueryCheckpointRequest - 47, // 45: ledger.Request.set_query_checkpoint_schedule:type_name -> ledger.SetQueryCheckpointScheduleRequest - 48, // 46: ledger.Request.delete_query_checkpoint_schedule:type_name -> ledger.DeleteQueryCheckpointScheduleRequest + 48, // 45: ledger.Request.set_query_checkpoint_schedule:type_name -> ledger.SetQueryCheckpointScheduleRequest + 49, // 46: ledger.Request.delete_query_checkpoint_schedule:type_name -> ledger.DeleteQueryCheckpointScheduleRequest 22, // 47: ledger.Request.save_ledger_metadata:type_name -> ledger.SaveLedgerMetadataRequest 23, // 48: ledger.Request.delete_ledger_metadata:type_name -> ledger.DeleteLedgerMetadataRequest - 136, // 49: ledger.SaveLedgerMetadataRequest.metadata:type_name -> ledger.SaveLedgerMetadataRequest.MetadataEntry - 155, // 50: ledger.AddEventsSinkRequest.config:type_name -> common.SinkConfig - 146, // 51: ledger.ListSigningKeysRequest.options:type_name -> common.ListOptions - 146, // 52: ledger.ListChaptersRequest.options:type_name -> common.ListOptions - 156, // 53: ledger.SetMetadataFieldTypeRequest.target_type:type_name -> common.TargetType - 157, // 54: ledger.SetMetadataFieldTypeRequest.type:type_name -> common.MetadataType - 156, // 55: ledger.RemoveMetadataFieldTypeRequest.target_type:type_name -> common.TargetType - 158, // 56: ledger.CreateIndexRequest.id:type_name -> common.IndexID - 158, // 57: ledger.DropIndexRequest.id:type_name -> common.IndexID - 151, // 58: ledger.GetNumscriptRequest.read:type_name -> common.ReadOptions - 146, // 59: ledger.ListNumscriptsRequest.options:type_name -> common.ListOptions - 137, // 60: ledger.ScriptReference.vars:type_name -> ledger.ScriptReference.VarsEntry - 54, // 61: ledger.DiscoveryResponse.response_signing:type_name -> ledger.ResponseSigningInfo - 52, // 62: ledger.DiscoveryResponse.server_info:type_name -> ledger.ServerInfo - 159, // 63: ledger.CreateTransactionPayload.postings:type_name -> common.Posting - 160, // 64: ledger.CreateTransactionPayload.script:type_name -> common.Script - 161, // 65: ledger.CreateTransactionPayload.timestamp:type_name -> common.Timestamp - 138, // 66: ledger.CreateTransactionPayload.metadata:type_name -> ledger.CreateTransactionPayload.MetadataEntry - 139, // 67: ledger.CreateTransactionPayload.account_metadata:type_name -> ledger.CreateTransactionPayload.AccountMetadataEntry - 46, // 68: ledger.CreateTransactionPayload.script_reference:type_name -> ledger.ScriptReference - 140, // 69: ledger.RevertTransactionPayload.metadata:type_name -> ledger.RevertTransactionPayload.MetadataEntry - 55, // 70: ledger.LedgerAction.create_transaction:type_name -> ledger.CreateTransactionPayload - 162, // 71: ledger.LedgerAction.add_metadata:type_name -> common.SaveMetadataCommand - 56, // 72: ledger.LedgerAction.revert_transaction:type_name -> ledger.RevertTransactionPayload - 163, // 73: ledger.LedgerAction.delete_metadata:type_name -> common.DeleteMetadataCommand - 59, // 74: ledger.LedgerAction.add_account_type:type_name -> ledger.AddAccountTypeRequest - 60, // 75: ledger.LedgerAction.remove_account_type:type_name -> ledger.RemoveAccountTypeRequest - 61, // 76: ledger.LedgerAction.set_default_enforcement_mode:type_name -> ledger.SetDefaultEnforcementModeRequest - 57, // 77: ledger.LedgerApplyRequest.action:type_name -> ledger.LedgerAction - 164, // 78: ledger.LedgerApplyRequest.skippable_reasons:type_name -> common.ErrorReason - 165, // 79: ledger.AddAccountTypeRequest.account_type:type_name -> common.AccountType - 150, // 80: ledger.SetDefaultEnforcementModeRequest.enforcement_mode:type_name -> common.ChartEnforcementMode - 150, // 81: ledger.SetDefaultEnforcementModeLedgerRequest.enforcement_mode:type_name -> common.ChartEnforcementMode - 165, // 82: ledger.AddAccountTypeLedgerRequest.account_type:type_name -> common.AccountType - 69, // 83: ledger.GetPrimaryMetricsResponse.metrics:type_name -> ledger.PebbleMetrics - 69, // 84: ledger.GetSecondaryMetricsResponse.metrics:type_name -> ledger.PebbleMetrics - 70, // 85: ledger.PebbleMetrics.block_cache:type_name -> ledger.BlockCacheMetrics - 71, // 86: ledger.PebbleMetrics.compact:type_name -> ledger.CompactMetrics - 72, // 87: ledger.PebbleMetrics.flush:type_name -> ledger.FlushMetrics - 73, // 88: ledger.PebbleMetrics.mem_table:type_name -> ledger.MemTableMetrics - 74, // 89: ledger.PebbleMetrics.snapshots:type_name -> ledger.SnapshotsMetrics - 75, // 90: ledger.PebbleMetrics.table:type_name -> ledger.TableMetrics - 76, // 91: ledger.PebbleMetrics.table_cache:type_name -> ledger.TableCacheMetrics - 77, // 92: ledger.PebbleMetrics.wal:type_name -> ledger.WALMetrics - 78, // 93: ledger.PebbleMetrics.keys:type_name -> ledger.KeysMetrics - 79, // 94: ledger.PebbleMetrics.levels:type_name -> ledger.LevelMetrics - 82, // 95: ledger.CheckStoreEvent.error:type_name -> ledger.CheckStoreError - 83, // 96: ledger.CheckStoreEvent.progress:type_name -> ledger.CheckStoreProgress + 137, // 49: ledger.SaveLedgerMetadataRequest.metadata:type_name -> ledger.SaveLedgerMetadataRequest.MetadataEntry + 156, // 50: ledger.AddEventsSinkRequest.config:type_name -> common.SinkConfig + 147, // 51: ledger.ListSigningKeysRequest.options:type_name -> common.ListOptions + 147, // 52: ledger.ListChaptersRequest.options:type_name -> common.ListOptions + 157, // 53: ledger.SetMetadataFieldTypeRequest.target_type:type_name -> common.TargetType + 158, // 54: ledger.SetMetadataFieldTypeRequest.type:type_name -> common.MetadataType + 157, // 55: ledger.RemoveMetadataFieldTypeRequest.target_type:type_name -> common.TargetType + 159, // 56: ledger.CreateIndexRequest.id:type_name -> common.IndexID + 159, // 57: ledger.DropIndexRequest.id:type_name -> common.IndexID + 152, // 58: ledger.GetNumscriptRequest.read:type_name -> common.ReadOptions + 147, // 59: ledger.ListNumscriptsRequest.options:type_name -> common.ListOptions + 138, // 60: ledger.ScriptReference.vars:type_name -> ledger.ScriptReference.VarsEntry + 55, // 61: ledger.DiscoveryResponse.response_signing:type_name -> ledger.ResponseSigningInfo + 53, // 62: ledger.DiscoveryResponse.server_info:type_name -> ledger.ServerInfo + 160, // 63: ledger.CreateTransactionPayload.postings:type_name -> common.Posting + 161, // 64: ledger.CreateTransactionPayload.script:type_name -> common.Script + 162, // 65: ledger.CreateTransactionPayload.timestamp:type_name -> common.Timestamp + 139, // 66: ledger.CreateTransactionPayload.metadata:type_name -> ledger.CreateTransactionPayload.MetadataEntry + 140, // 67: ledger.CreateTransactionPayload.account_metadata:type_name -> ledger.CreateTransactionPayload.AccountMetadataEntry + 47, // 68: ledger.CreateTransactionPayload.script_reference:type_name -> ledger.ScriptReference + 141, // 69: ledger.RevertTransactionPayload.metadata:type_name -> ledger.RevertTransactionPayload.MetadataEntry + 56, // 70: ledger.LedgerAction.create_transaction:type_name -> ledger.CreateTransactionPayload + 163, // 71: ledger.LedgerAction.add_metadata:type_name -> common.SaveMetadataCommand + 57, // 72: ledger.LedgerAction.revert_transaction:type_name -> ledger.RevertTransactionPayload + 164, // 73: ledger.LedgerAction.delete_metadata:type_name -> common.DeleteMetadataCommand + 60, // 74: ledger.LedgerAction.add_account_type:type_name -> ledger.AddAccountTypeRequest + 61, // 75: ledger.LedgerAction.remove_account_type:type_name -> ledger.RemoveAccountTypeRequest + 62, // 76: ledger.LedgerAction.set_default_enforcement_mode:type_name -> ledger.SetDefaultEnforcementModeRequest + 58, // 77: ledger.LedgerApplyRequest.action:type_name -> ledger.LedgerAction + 165, // 78: ledger.LedgerApplyRequest.skippable_reasons:type_name -> common.ErrorReason + 166, // 79: ledger.AddAccountTypeRequest.account_type:type_name -> common.AccountType + 151, // 80: ledger.SetDefaultEnforcementModeRequest.enforcement_mode:type_name -> common.ChartEnforcementMode + 151, // 81: ledger.SetDefaultEnforcementModeLedgerRequest.enforcement_mode:type_name -> common.ChartEnforcementMode + 166, // 82: ledger.AddAccountTypeLedgerRequest.account_type:type_name -> common.AccountType + 70, // 83: ledger.GetPrimaryMetricsResponse.metrics:type_name -> ledger.PebbleMetrics + 70, // 84: ledger.GetSecondaryMetricsResponse.metrics:type_name -> ledger.PebbleMetrics + 71, // 85: ledger.PebbleMetrics.block_cache:type_name -> ledger.BlockCacheMetrics + 72, // 86: ledger.PebbleMetrics.compact:type_name -> ledger.CompactMetrics + 73, // 87: ledger.PebbleMetrics.flush:type_name -> ledger.FlushMetrics + 74, // 88: ledger.PebbleMetrics.mem_table:type_name -> ledger.MemTableMetrics + 75, // 89: ledger.PebbleMetrics.snapshots:type_name -> ledger.SnapshotsMetrics + 76, // 90: ledger.PebbleMetrics.table:type_name -> ledger.TableMetrics + 77, // 91: ledger.PebbleMetrics.table_cache:type_name -> ledger.TableCacheMetrics + 78, // 92: ledger.PebbleMetrics.wal:type_name -> ledger.WALMetrics + 79, // 93: ledger.PebbleMetrics.keys:type_name -> ledger.KeysMetrics + 80, // 94: ledger.PebbleMetrics.levels:type_name -> ledger.LevelMetrics + 83, // 95: ledger.CheckStoreEvent.error:type_name -> ledger.CheckStoreError + 84, // 96: ledger.CheckStoreEvent.progress:type_name -> ledger.CheckStoreProgress 0, // 97: ledger.CheckStoreError.error_type:type_name -> ledger.CheckStoreErrorType - 146, // 98: ledger.ListAuditEntriesRequest.options:type_name -> common.ListOptions - 146, // 99: ledger.ListLogsRequest.options:type_name -> common.ListOptions - 155, // 100: ledger.GetEventsSinksResponse.sinks:type_name -> common.SinkConfig - 166, // 101: ledger.GetEventsSinksResponse.sink_statuses:type_name -> common.SinkStatus - 141, // 102: ledger.GetMetadataSchemaStatusResponse.account_fields:type_name -> ledger.GetMetadataSchemaStatusResponse.AccountFieldsEntry - 142, // 103: ledger.GetMetadataSchemaStatusResponse.transaction_fields:type_name -> ledger.GetMetadataSchemaStatusResponse.TransactionFieldsEntry - 143, // 104: ledger.GetMetadataSchemaStatusResponse.ledger_fields:type_name -> ledger.GetMetadataSchemaStatusResponse.LedgerFieldsEntry - 157, // 105: ledger.MetadataFieldStatus.declared_type:type_name -> common.MetadataType - 98, // 106: ledger.AnalyzeAccountsResponse.patterns:type_name -> ledger.AccountPattern - 95, // 107: ledger.AnalyzeAccountsEvent.progress:type_name -> ledger.AnalyzeProgress - 94, // 108: ledger.AnalyzeAccountsEvent.result:type_name -> ledger.AnalyzeAccountsResponse - 95, // 109: ledger.AnalyzeTransactionsEvent.progress:type_name -> ledger.AnalyzeProgress - 101, // 110: ledger.AnalyzeTransactionsEvent.result:type_name -> ledger.AnalyzeTransactionsResponse - 99, // 111: ledger.AccountPattern.segments:type_name -> ledger.PatternSegment + 147, // 98: ledger.ListAuditEntriesRequest.options:type_name -> common.ListOptions + 147, // 99: ledger.ListLogsRequest.options:type_name -> common.ListOptions + 156, // 100: ledger.GetEventsSinksResponse.sinks:type_name -> common.SinkConfig + 167, // 101: ledger.GetEventsSinksResponse.sink_statuses:type_name -> common.SinkStatus + 142, // 102: ledger.GetMetadataSchemaStatusResponse.account_fields:type_name -> ledger.GetMetadataSchemaStatusResponse.AccountFieldsEntry + 143, // 103: ledger.GetMetadataSchemaStatusResponse.transaction_fields:type_name -> ledger.GetMetadataSchemaStatusResponse.TransactionFieldsEntry + 144, // 104: ledger.GetMetadataSchemaStatusResponse.ledger_fields:type_name -> ledger.GetMetadataSchemaStatusResponse.LedgerFieldsEntry + 158, // 105: ledger.MetadataFieldStatus.declared_type:type_name -> common.MetadataType + 99, // 106: ledger.AnalyzeAccountsResponse.patterns:type_name -> ledger.AccountPattern + 96, // 107: ledger.AnalyzeAccountsEvent.progress:type_name -> ledger.AnalyzeProgress + 95, // 108: ledger.AnalyzeAccountsEvent.result:type_name -> ledger.AnalyzeAccountsResponse + 96, // 109: ledger.AnalyzeTransactionsEvent.progress:type_name -> ledger.AnalyzeProgress + 102, // 110: ledger.AnalyzeTransactionsEvent.result:type_name -> ledger.AnalyzeTransactionsResponse + 100, // 111: ledger.AccountPattern.segments:type_name -> ledger.PatternSegment 1, // 112: ledger.PatternSegment.type:type_name -> ledger.PatternSegmentType - 102, // 113: ledger.AnalyzeTransactionsResponse.flow_patterns:type_name -> ledger.FlowPattern + 103, // 113: ledger.AnalyzeTransactionsResponse.flow_patterns:type_name -> ledger.FlowPattern 2, // 114: ledger.FlowPattern.structure:type_name -> ledger.PostingStructure - 103, // 115: ledger.FlowPattern.postings:type_name -> ledger.NormalizedPosting - 104, // 116: ledger.FlowPattern.temporal:type_name -> ledger.TemporalStats - 106, // 117: ledger.FlowPattern.volume_stats:type_name -> ledger.AssetVolumeStats - 161, // 118: ledger.TemporalStats.first_seen:type_name -> common.Timestamp - 161, // 119: ledger.TemporalStats.last_seen:type_name -> common.Timestamp - 105, // 120: ledger.TemporalStats.peak_hours:type_name -> ledger.HourBucket - 167, // 121: ledger.CreatePreparedQueryRequest.query:type_name -> common.PreparedQuery - 168, // 122: ledger.UpdatePreparedQueryRequest.filter:type_name -> common.QueryFilter - 167, // 123: ledger.ListPreparedQueriesResponse.queries:type_name -> common.PreparedQuery - 144, // 124: ledger.ExecutePreparedQueryRequest.parameters:type_name -> ledger.ExecutePreparedQueryRequest.ParametersEntry - 169, // 125: ledger.ExecutePreparedQueryRequest.mode:type_name -> common.QueryMode - 170, // 126: ledger.ExecutePreparedQueryResponse.cursor:type_name -> common.PreparedQueryCursor - 171, // 127: ledger.ExecutePreparedQueryResponse.aggregate:type_name -> common.AggregateResult - 121, // 128: ledger.GetIndexStatusResponse.indexes:type_name -> ledger.IndexEntry - 158, // 129: ledger.GetIndexRequest.id:type_name -> common.IndexID - 158, // 130: ledger.GetIndexEntryStatusRequest.id:type_name -> common.IndexID - 172, // 131: ledger.IndexEntry.index:type_name -> common.Index + 104, // 115: ledger.FlowPattern.postings:type_name -> ledger.NormalizedPosting + 105, // 116: ledger.FlowPattern.temporal:type_name -> ledger.TemporalStats + 107, // 117: ledger.FlowPattern.volume_stats:type_name -> ledger.AssetVolumeStats + 162, // 118: ledger.TemporalStats.first_seen:type_name -> common.Timestamp + 162, // 119: ledger.TemporalStats.last_seen:type_name -> common.Timestamp + 106, // 120: ledger.TemporalStats.peak_hours:type_name -> ledger.HourBucket + 168, // 121: ledger.CreatePreparedQueryRequest.query:type_name -> common.PreparedQuery + 169, // 122: ledger.UpdatePreparedQueryRequest.filter:type_name -> common.QueryFilter + 168, // 123: ledger.ListPreparedQueriesResponse.queries:type_name -> common.PreparedQuery + 145, // 124: ledger.ExecutePreparedQueryRequest.parameters:type_name -> ledger.ExecutePreparedQueryRequest.ParametersEntry + 170, // 125: ledger.ExecutePreparedQueryRequest.mode:type_name -> common.QueryMode + 171, // 126: ledger.ExecutePreparedQueryResponse.cursor:type_name -> common.PreparedQueryCursor + 172, // 127: ledger.ExecutePreparedQueryResponse.aggregate:type_name -> common.AggregateResult + 122, // 128: ledger.GetIndexStatusResponse.indexes:type_name -> ledger.IndexEntry + 159, // 129: ledger.GetIndexRequest.id:type_name -> common.IndexID + 159, // 130: ledger.GetIndexEntryStatusRequest.id:type_name -> common.IndexID + 173, // 131: ledger.IndexEntry.index:type_name -> common.Index 4, // 132: ledger.ListIndexesRequest.scope:type_name -> ledger.ListIndexesRequest.Scope - 168, // 133: ledger.AggregateVolumesRequest.filter:type_name -> common.QueryFilter - 126, // 134: ledger.QueryProfile.root_iterator:type_name -> ledger.IteratorProfile - 126, // 135: ledger.IteratorProfile.children:type_name -> ledger.IteratorProfile - 156, // 136: ledger.InspectIndexRequest.target_type:type_name -> common.TargetType + 169, // 133: ledger.AggregateVolumesRequest.filter:type_name -> common.QueryFilter + 127, // 134: ledger.QueryProfile.root_iterator:type_name -> ledger.IteratorProfile + 127, // 135: ledger.IteratorProfile.children:type_name -> ledger.IteratorProfile + 157, // 136: ledger.InspectIndexRequest.target_type:type_name -> common.TargetType 3, // 137: ledger.InspectIndexRequest.mode:type_name -> ledger.InspectIndexMode - 129, // 138: ledger.InspectIndexResponse.distinct_values:type_name -> ledger.InspectDistinctValues - 131, // 139: ledger.InspectIndexResponse.facets:type_name -> ledger.InspectFacets - 132, // 140: ledger.InspectIndexResponse.summary:type_name -> ledger.InspectSummary - 173, // 141: ledger.InspectDistinctValues.values:type_name -> common.MetadataValue - 173, // 142: ledger.InspectFacet.value:type_name -> common.MetadataValue - 130, // 143: ledger.InspectFacets.facets:type_name -> ledger.InspectFacet - 173, // 144: ledger.InspectSummary.min:type_name -> common.MetadataValue - 173, // 145: ledger.InspectSummary.max:type_name -> common.MetadataValue - 165, // 146: ledger.CreateLedgerRequest.AccountTypesEntry.value:type_name -> common.AccountType - 173, // 147: ledger.SaveLedgerMetadataRequest.MetadataEntry.value:type_name -> common.MetadataValue - 173, // 148: ledger.CreateTransactionPayload.MetadataEntry.value:type_name -> common.MetadataValue - 174, // 149: ledger.CreateTransactionPayload.AccountMetadataEntry.value:type_name -> common.MetadataMap - 173, // 150: ledger.RevertTransactionPayload.MetadataEntry.value:type_name -> common.MetadataValue - 92, // 151: ledger.GetMetadataSchemaStatusResponse.AccountFieldsEntry.value:type_name -> ledger.MetadataFieldStatus - 92, // 152: ledger.GetMetadataSchemaStatusResponse.TransactionFieldsEntry.value:type_name -> ledger.MetadataFieldStatus - 92, // 153: ledger.GetMetadataSchemaStatusResponse.LedgerFieldsEntry.value:type_name -> ledger.MetadataFieldStatus - 175, // 154: ledger.ExecutePreparedQueryRequest.ParametersEntry.value:type_name -> common.ParameterValue - 176, // 155: ledger.allowed_skippable_reasons:extendee -> google.protobuf.FieldOptions - 164, // 156: ledger.allowed_skippable_reasons:type_name -> common.ErrorReason + 130, // 138: ledger.InspectIndexResponse.distinct_values:type_name -> ledger.InspectDistinctValues + 132, // 139: ledger.InspectIndexResponse.facets:type_name -> ledger.InspectFacets + 133, // 140: ledger.InspectIndexResponse.summary:type_name -> ledger.InspectSummary + 174, // 141: ledger.InspectDistinctValues.values:type_name -> common.MetadataValue + 174, // 142: ledger.InspectFacet.value:type_name -> common.MetadataValue + 131, // 143: ledger.InspectFacets.facets:type_name -> ledger.InspectFacet + 174, // 144: ledger.InspectSummary.min:type_name -> common.MetadataValue + 174, // 145: ledger.InspectSummary.max:type_name -> common.MetadataValue + 166, // 146: ledger.CreateLedgerRequest.AccountTypesEntry.value:type_name -> common.AccountType + 174, // 147: ledger.SaveLedgerMetadataRequest.MetadataEntry.value:type_name -> common.MetadataValue + 174, // 148: ledger.CreateTransactionPayload.MetadataEntry.value:type_name -> common.MetadataValue + 175, // 149: ledger.CreateTransactionPayload.AccountMetadataEntry.value:type_name -> common.MetadataMap + 174, // 150: ledger.RevertTransactionPayload.MetadataEntry.value:type_name -> common.MetadataValue + 93, // 151: ledger.GetMetadataSchemaStatusResponse.AccountFieldsEntry.value:type_name -> ledger.MetadataFieldStatus + 93, // 152: ledger.GetMetadataSchemaStatusResponse.TransactionFieldsEntry.value:type_name -> ledger.MetadataFieldStatus + 93, // 153: ledger.GetMetadataSchemaStatusResponse.LedgerFieldsEntry.value:type_name -> ledger.MetadataFieldStatus + 176, // 154: ledger.ExecutePreparedQueryRequest.ParametersEntry.value:type_name -> common.ParameterValue + 177, // 155: ledger.allowed_skippable_reasons:extendee -> google.protobuf.FieldOptions + 165, // 156: ledger.allowed_skippable_reasons:type_name -> common.ErrorReason 13, // 157: ledger.BucketService.ListLedgers:input_type -> ledger.ListLedgersRequest 14, // 158: ledger.BucketService.GetLedger:input_type -> ledger.GetLedgerRequest 5, // 159: ledger.BucketService.GetAccount:input_type -> ledger.GetAccountRequest @@ -10001,75 +10063,77 @@ var file_bucket_proto_depIdxs = []int32{ 8, // 161: ledger.BucketService.ListTransactions:input_type -> ledger.ListTransactionsRequest 9, // 162: ledger.BucketService.ListAccounts:input_type -> ledger.ListAccountsRequest 15, // 163: ledger.BucketService.Apply:input_type -> ledger.ApplyRequest - 65, // 164: ledger.BucketService.GetPrimaryMetrics:input_type -> ledger.GetPrimaryMetricsRequest - 67, // 165: ledger.BucketService.GetSecondaryMetrics:input_type -> ledger.GetSecondaryMetricsRequest - 80, // 166: ledger.BucketService.CheckStore:input_type -> ledger.CheckStoreRequest - 84, // 167: ledger.BucketService.ListAuditEntries:input_type -> ledger.ListAuditEntriesRequest - 85, // 168: ledger.BucketService.GetAuditEntry:input_type -> ledger.GetAuditEntryRequest - 88, // 169: ledger.BucketService.GetEventsSinks:input_type -> ledger.GetEventsSinksRequest + 66, // 164: ledger.BucketService.GetPrimaryMetrics:input_type -> ledger.GetPrimaryMetricsRequest + 68, // 165: ledger.BucketService.GetSecondaryMetrics:input_type -> ledger.GetSecondaryMetricsRequest + 81, // 166: ledger.BucketService.CheckStore:input_type -> ledger.CheckStoreRequest + 85, // 167: ledger.BucketService.ListAuditEntries:input_type -> ledger.ListAuditEntriesRequest + 86, // 168: ledger.BucketService.GetAuditEntry:input_type -> ledger.GetAuditEntryRequest + 89, // 169: ledger.BucketService.GetEventsSinks:input_type -> ledger.GetEventsSinksRequest 34, // 170: ledger.BucketService.ListChapters:input_type -> ledger.ListChaptersRequest - 86, // 171: ledger.BucketService.ListLogs:input_type -> ledger.ListLogsRequest - 87, // 172: ledger.BucketService.GetLog:input_type -> ledger.GetLogRequest - 49, // 173: ledger.BucketService.GetChapterSchedule:input_type -> ledger.GetChapterScheduleRequest + 87, // 171: ledger.BucketService.ListLogs:input_type -> ledger.ListLogsRequest + 88, // 172: ledger.BucketService.GetLog:input_type -> ledger.GetLogRequest + 50, // 173: ledger.BucketService.GetChapterSchedule:input_type -> ledger.GetChapterScheduleRequest 29, // 174: ledger.BucketService.ListSigningKeys:input_type -> ledger.ListSigningKeysRequest - 51, // 175: ledger.BucketService.Discovery:input_type -> ledger.DiscoveryRequest - 90, // 176: ledger.BucketService.GetMetadataSchemaStatus:input_type -> ledger.GetMetadataSchemaStatusRequest - 93, // 177: ledger.BucketService.AnalyzeAccounts:input_type -> ledger.AnalyzeAccountsRequest - 100, // 178: ledger.BucketService.AnalyzeTransactions:input_type -> ledger.AnalyzeTransactionsRequest - 107, // 179: ledger.BucketService.CreatePreparedQuery:input_type -> ledger.CreatePreparedQueryRequest - 109, // 180: ledger.BucketService.UpdatePreparedQuery:input_type -> ledger.UpdatePreparedQueryRequest - 111, // 181: ledger.BucketService.DeletePreparedQuery:input_type -> ledger.DeletePreparedQueryRequest - 113, // 182: ledger.BucketService.ListPreparedQueries:input_type -> ledger.ListPreparedQueriesRequest - 115, // 183: ledger.BucketService.ExecutePreparedQuery:input_type -> ledger.ExecutePreparedQueryRequest - 117, // 184: ledger.BucketService.GetIndexStatus:input_type -> ledger.GetIndexStatusRequest - 119, // 185: ledger.BucketService.GetIndex:input_type -> ledger.GetIndexRequest - 120, // 186: ledger.BucketService.GetIndexEntryStatus:input_type -> ledger.GetIndexEntryStatusRequest - 122, // 187: ledger.BucketService.ListIndexes:input_type -> ledger.ListIndexesRequest - 123, // 188: ledger.BucketService.GetLedgerStats:input_type -> ledger.GetLedgerStatsRequest - 124, // 189: ledger.BucketService.AggregateVolumes:input_type -> ledger.AggregateVolumesRequest + 52, // 175: ledger.BucketService.Discovery:input_type -> ledger.DiscoveryRequest + 91, // 176: ledger.BucketService.GetMetadataSchemaStatus:input_type -> ledger.GetMetadataSchemaStatusRequest + 94, // 177: ledger.BucketService.AnalyzeAccounts:input_type -> ledger.AnalyzeAccountsRequest + 101, // 178: ledger.BucketService.AnalyzeTransactions:input_type -> ledger.AnalyzeTransactionsRequest + 108, // 179: ledger.BucketService.CreatePreparedQuery:input_type -> ledger.CreatePreparedQueryRequest + 110, // 180: ledger.BucketService.UpdatePreparedQuery:input_type -> ledger.UpdatePreparedQueryRequest + 112, // 181: ledger.BucketService.DeletePreparedQuery:input_type -> ledger.DeletePreparedQueryRequest + 114, // 182: ledger.BucketService.ListPreparedQueries:input_type -> ledger.ListPreparedQueriesRequest + 116, // 183: ledger.BucketService.ExecutePreparedQuery:input_type -> ledger.ExecutePreparedQueryRequest + 118, // 184: ledger.BucketService.GetIndexStatus:input_type -> ledger.GetIndexStatusRequest + 120, // 185: ledger.BucketService.GetIndex:input_type -> ledger.GetIndexRequest + 121, // 186: ledger.BucketService.GetIndexEntryStatus:input_type -> ledger.GetIndexEntryStatusRequest + 123, // 187: ledger.BucketService.ListIndexes:input_type -> ledger.ListIndexesRequest + 124, // 188: ledger.BucketService.GetLedgerStats:input_type -> ledger.GetLedgerStatsRequest + 125, // 189: ledger.BucketService.AggregateVolumes:input_type -> ledger.AggregateVolumesRequest 44, // 190: ledger.BucketService.GetNumscript:input_type -> ledger.GetNumscriptRequest 45, // 191: ledger.BucketService.ListNumscripts:input_type -> ledger.ListNumscriptsRequest - 127, // 192: ledger.BucketService.InspectIndex:input_type -> ledger.InspectIndexRequest - 133, // 193: ledger.BucketService.Barrier:input_type -> ledger.BarrierRequest - 177, // 194: ledger.BucketService.ListLedgers:output_type -> common.LedgerInfo - 177, // 195: ledger.BucketService.GetLedger:output_type -> common.LedgerInfo - 178, // 196: ledger.BucketService.GetAccount:output_type -> common.Account - 7, // 197: ledger.BucketService.GetTransaction:output_type -> ledger.GetTransactionResponse - 145, // 198: ledger.BucketService.ListTransactions:output_type -> common.Transaction - 178, // 199: ledger.BucketService.ListAccounts:output_type -> common.Account - 17, // 200: ledger.BucketService.Apply:output_type -> ledger.ApplyResponse - 66, // 201: ledger.BucketService.GetPrimaryMetrics:output_type -> ledger.GetPrimaryMetricsResponse - 68, // 202: ledger.BucketService.GetSecondaryMetrics:output_type -> ledger.GetSecondaryMetricsResponse - 81, // 203: ledger.BucketService.CheckStore:output_type -> ledger.CheckStoreEvent - 179, // 204: ledger.BucketService.ListAuditEntries:output_type -> audit.AuditEntry - 179, // 205: ledger.BucketService.GetAuditEntry:output_type -> audit.AuditEntry - 89, // 206: ledger.BucketService.GetEventsSinks:output_type -> ledger.GetEventsSinksResponse - 180, // 207: ledger.BucketService.ListChapters:output_type -> common.Chapter - 154, // 208: ledger.BucketService.ListLogs:output_type -> common.Log - 154, // 209: ledger.BucketService.GetLog:output_type -> common.Log - 50, // 210: ledger.BucketService.GetChapterSchedule:output_type -> ledger.GetChapterScheduleResponse - 181, // 211: ledger.BucketService.ListSigningKeys:output_type -> common.SigningKey - 53, // 212: ledger.BucketService.Discovery:output_type -> ledger.DiscoveryResponse - 91, // 213: ledger.BucketService.GetMetadataSchemaStatus:output_type -> ledger.GetMetadataSchemaStatusResponse - 96, // 214: ledger.BucketService.AnalyzeAccounts:output_type -> ledger.AnalyzeAccountsEvent - 97, // 215: ledger.BucketService.AnalyzeTransactions:output_type -> ledger.AnalyzeTransactionsEvent - 108, // 216: ledger.BucketService.CreatePreparedQuery:output_type -> ledger.CreatePreparedQueryResponse - 110, // 217: ledger.BucketService.UpdatePreparedQuery:output_type -> ledger.UpdatePreparedQueryResponse - 112, // 218: ledger.BucketService.DeletePreparedQuery:output_type -> ledger.DeletePreparedQueryResponse - 114, // 219: ledger.BucketService.ListPreparedQueries:output_type -> ledger.ListPreparedQueriesResponse - 116, // 220: ledger.BucketService.ExecutePreparedQuery:output_type -> ledger.ExecutePreparedQueryResponse - 118, // 221: ledger.BucketService.GetIndexStatus:output_type -> ledger.GetIndexStatusResponse - 172, // 222: ledger.BucketService.GetIndex:output_type -> common.Index - 121, // 223: ledger.BucketService.GetIndexEntryStatus:output_type -> ledger.IndexEntry - 172, // 224: ledger.BucketService.ListIndexes:output_type -> common.Index - 182, // 225: ledger.BucketService.GetLedgerStats:output_type -> common.LedgerStats - 171, // 226: ledger.BucketService.AggregateVolumes:output_type -> common.AggregateResult - 183, // 227: ledger.BucketService.GetNumscript:output_type -> common.NumscriptInfo - 183, // 228: ledger.BucketService.ListNumscripts:output_type -> common.NumscriptInfo - 128, // 229: ledger.BucketService.InspectIndex:output_type -> ledger.InspectIndexResponse - 134, // 230: ledger.BucketService.Barrier:output_type -> ledger.BarrierResponse - 194, // [194:231] is the sub-list for method output_type - 157, // [157:194] is the sub-list for method input_type + 46, // 192: ledger.BucketService.GetTemplateUsage:input_type -> ledger.GetTemplateUsageRequest + 128, // 193: ledger.BucketService.InspectIndex:input_type -> ledger.InspectIndexRequest + 134, // 194: ledger.BucketService.Barrier:input_type -> ledger.BarrierRequest + 178, // 195: ledger.BucketService.ListLedgers:output_type -> common.LedgerInfo + 178, // 196: ledger.BucketService.GetLedger:output_type -> common.LedgerInfo + 179, // 197: ledger.BucketService.GetAccount:output_type -> common.Account + 7, // 198: ledger.BucketService.GetTransaction:output_type -> ledger.GetTransactionResponse + 146, // 199: ledger.BucketService.ListTransactions:output_type -> common.Transaction + 179, // 200: ledger.BucketService.ListAccounts:output_type -> common.Account + 17, // 201: ledger.BucketService.Apply:output_type -> ledger.ApplyResponse + 67, // 202: ledger.BucketService.GetPrimaryMetrics:output_type -> ledger.GetPrimaryMetricsResponse + 69, // 203: ledger.BucketService.GetSecondaryMetrics:output_type -> ledger.GetSecondaryMetricsResponse + 82, // 204: ledger.BucketService.CheckStore:output_type -> ledger.CheckStoreEvent + 180, // 205: ledger.BucketService.ListAuditEntries:output_type -> audit.AuditEntry + 180, // 206: ledger.BucketService.GetAuditEntry:output_type -> audit.AuditEntry + 90, // 207: ledger.BucketService.GetEventsSinks:output_type -> ledger.GetEventsSinksResponse + 181, // 208: ledger.BucketService.ListChapters:output_type -> common.Chapter + 155, // 209: ledger.BucketService.ListLogs:output_type -> common.Log + 155, // 210: ledger.BucketService.GetLog:output_type -> common.Log + 51, // 211: ledger.BucketService.GetChapterSchedule:output_type -> ledger.GetChapterScheduleResponse + 182, // 212: ledger.BucketService.ListSigningKeys:output_type -> common.SigningKey + 54, // 213: ledger.BucketService.Discovery:output_type -> ledger.DiscoveryResponse + 92, // 214: ledger.BucketService.GetMetadataSchemaStatus:output_type -> ledger.GetMetadataSchemaStatusResponse + 97, // 215: ledger.BucketService.AnalyzeAccounts:output_type -> ledger.AnalyzeAccountsEvent + 98, // 216: ledger.BucketService.AnalyzeTransactions:output_type -> ledger.AnalyzeTransactionsEvent + 109, // 217: ledger.BucketService.CreatePreparedQuery:output_type -> ledger.CreatePreparedQueryResponse + 111, // 218: ledger.BucketService.UpdatePreparedQuery:output_type -> ledger.UpdatePreparedQueryResponse + 113, // 219: ledger.BucketService.DeletePreparedQuery:output_type -> ledger.DeletePreparedQueryResponse + 115, // 220: ledger.BucketService.ListPreparedQueries:output_type -> ledger.ListPreparedQueriesResponse + 117, // 221: ledger.BucketService.ExecutePreparedQuery:output_type -> ledger.ExecutePreparedQueryResponse + 119, // 222: ledger.BucketService.GetIndexStatus:output_type -> ledger.GetIndexStatusResponse + 173, // 223: ledger.BucketService.GetIndex:output_type -> common.Index + 122, // 224: ledger.BucketService.GetIndexEntryStatus:output_type -> ledger.IndexEntry + 173, // 225: ledger.BucketService.ListIndexes:output_type -> common.Index + 183, // 226: ledger.BucketService.GetLedgerStats:output_type -> common.LedgerStats + 172, // 227: ledger.BucketService.AggregateVolumes:output_type -> common.AggregateResult + 184, // 228: ledger.BucketService.GetNumscript:output_type -> common.NumscriptInfo + 184, // 229: ledger.BucketService.ListNumscripts:output_type -> common.NumscriptInfo + 185, // 230: ledger.BucketService.GetTemplateUsage:output_type -> common.TemplateUsage + 129, // 231: ledger.BucketService.InspectIndex:output_type -> ledger.InspectIndexResponse + 135, // 232: ledger.BucketService.Barrier:output_type -> ledger.BarrierResponse + 195, // [195:233] is the sub-list for method output_type + 157, // [157:195] is the sub-list for method input_type 156, // [156:157] is the sub-list for extension type_name 155, // [155:156] is the sub-list for extension extendee 0, // [0:155] is the sub-list for field type_name @@ -10120,7 +10184,7 @@ func file_bucket_proto_init() { (*Request_SaveLedgerMetadata)(nil), (*Request_DeleteLedgerMetadata)(nil), } - file_bucket_proto_msgTypes[52].OneofWrappers = []any{ + file_bucket_proto_msgTypes[53].OneofWrappers = []any{ (*LedgerAction_CreateTransaction)(nil), (*LedgerAction_AddMetadata)(nil), (*LedgerAction_RevertTransaction)(nil), @@ -10129,23 +10193,23 @@ func file_bucket_proto_init() { (*LedgerAction_RemoveAccountType)(nil), (*LedgerAction_SetDefaultEnforcementMode)(nil), } - file_bucket_proto_msgTypes[76].OneofWrappers = []any{ + file_bucket_proto_msgTypes[77].OneofWrappers = []any{ (*CheckStoreEvent_Error)(nil), (*CheckStoreEvent_Progress)(nil), } - file_bucket_proto_msgTypes[91].OneofWrappers = []any{ + file_bucket_proto_msgTypes[92].OneofWrappers = []any{ (*AnalyzeAccountsEvent_Progress)(nil), (*AnalyzeAccountsEvent_Result)(nil), } - file_bucket_proto_msgTypes[92].OneofWrappers = []any{ + file_bucket_proto_msgTypes[93].OneofWrappers = []any{ (*AnalyzeTransactionsEvent_Progress)(nil), (*AnalyzeTransactionsEvent_Result)(nil), } - file_bucket_proto_msgTypes[111].OneofWrappers = []any{ + file_bucket_proto_msgTypes[112].OneofWrappers = []any{ (*ExecutePreparedQueryResponse_Cursor)(nil), (*ExecutePreparedQueryResponse_Aggregate)(nil), } - file_bucket_proto_msgTypes[123].OneofWrappers = []any{ + file_bucket_proto_msgTypes[124].OneofWrappers = []any{ (*InspectIndexResponse_DistinctValues)(nil), (*InspectIndexResponse_Facets)(nil), (*InspectIndexResponse_Summary)(nil), @@ -10156,7 +10220,7 @@ func file_bucket_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_bucket_proto_rawDesc), len(file_bucket_proto_rawDesc)), NumEnums: 5, - NumMessages: 140, + NumMessages: 141, NumExtensions: 1, NumServices: 1, }, diff --git a/internal/proto/servicepb/bucket_dethash.pb.go b/internal/proto/servicepb/bucket_dethash.pb.go index a4b4ab8247..b9e4aec0da 100644 --- a/internal/proto/servicepb/bucket_dethash.pb.go +++ b/internal/proto/servicepb/bucket_dethash.pb.go @@ -1036,6 +1036,17 @@ func (m *ListNumscriptsRequest) MarshalDeterministicVT(dAtA []byte) []byte { return append(dAtA, b...) } +func (m *GetTemplateUsageRequest) MarshalDeterministicVT(dAtA []byte) []byte { + if m == nil { + return dAtA + } + b, err := m.MarshalVT() + if err != nil { + panic("MarshalDeterministicVT: " + err.Error()) + } + return append(dAtA, b...) +} + func (m *ScriptReference) MarshalDeterministicVT(dAtA []byte) []byte { if m == nil { return dAtA diff --git a/internal/proto/servicepb/bucket_grpc.pb.go b/internal/proto/servicepb/bucket_grpc.pb.go index da74c5db87..f78240c3cd 100644 --- a/internal/proto/servicepb/bucket_grpc.pb.go +++ b/internal/proto/servicepb/bucket_grpc.pb.go @@ -56,6 +56,7 @@ const ( BucketService_AggregateVolumes_FullMethodName = "/ledger.BucketService/AggregateVolumes" BucketService_GetNumscript_FullMethodName = "/ledger.BucketService/GetNumscript" BucketService_ListNumscripts_FullMethodName = "/ledger.BucketService/ListNumscripts" + BucketService_GetTemplateUsage_FullMethodName = "/ledger.BucketService/GetTemplateUsage" BucketService_InspectIndex_FullMethodName = "/ledger.BucketService/InspectIndex" BucketService_Barrier_FullMethodName = "/ledger.BucketService/Barrier" ) @@ -138,6 +139,10 @@ type BucketServiceClient interface { GetNumscript(ctx context.Context, in *GetNumscriptRequest, opts ...grpc.CallOption) (*commonpb.NumscriptInfo, error) // ListNumscripts streams all numscripts (latest version of each) ListNumscripts(ctx context.Context, in *ListNumscriptsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[commonpb.NumscriptInfo], error) + // GetTemplateUsage returns per-template invocation usage populated by the + // usagebuilder subsystem. Eventually consistent — may lag the live FSM + // by up to one usagebuilder tick interval. + GetTemplateUsage(ctx context.Context, in *GetTemplateUsageRequest, opts ...grpc.CallOption) (*commonpb.TemplateUsage, error) // InspectIndex scans a metadata index and returns distinct values, facets, or a summary InspectIndex(ctx context.Context, in *InspectIndexRequest, opts ...grpc.CallOption) (*InspectIndexResponse, error) // Barrier proposes a no-op through Raft consensus. When it returns, all @@ -612,6 +617,16 @@ func (c *bucketServiceClient) ListNumscripts(ctx context.Context, in *ListNumscr // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type BucketService_ListNumscriptsClient = grpc.ServerStreamingClient[commonpb.NumscriptInfo] +func (c *bucketServiceClient) GetTemplateUsage(ctx context.Context, in *GetTemplateUsageRequest, opts ...grpc.CallOption) (*commonpb.TemplateUsage, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(commonpb.TemplateUsage) + err := c.cc.Invoke(ctx, BucketService_GetTemplateUsage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *bucketServiceClient) InspectIndex(ctx context.Context, in *InspectIndexRequest, opts ...grpc.CallOption) (*InspectIndexResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(InspectIndexResponse) @@ -710,6 +725,10 @@ type BucketServiceServer interface { GetNumscript(context.Context, *GetNumscriptRequest) (*commonpb.NumscriptInfo, error) // ListNumscripts streams all numscripts (latest version of each) ListNumscripts(*ListNumscriptsRequest, grpc.ServerStreamingServer[commonpb.NumscriptInfo]) error + // GetTemplateUsage returns per-template invocation usage populated by the + // usagebuilder subsystem. Eventually consistent — may lag the live FSM + // by up to one usagebuilder tick interval. + GetTemplateUsage(context.Context, *GetTemplateUsageRequest) (*commonpb.TemplateUsage, error) // InspectIndex scans a metadata index and returns distinct values, facets, or a summary InspectIndex(context.Context, *InspectIndexRequest) (*InspectIndexResponse, error) // Barrier proposes a no-op through Raft consensus. When it returns, all @@ -831,6 +850,9 @@ func (UnimplementedBucketServiceServer) GetNumscript(context.Context, *GetNumscr func (UnimplementedBucketServiceServer) ListNumscripts(*ListNumscriptsRequest, grpc.ServerStreamingServer[commonpb.NumscriptInfo]) error { return status.Error(codes.Unimplemented, "method ListNumscripts not implemented") } +func (UnimplementedBucketServiceServer) GetTemplateUsage(context.Context, *GetTemplateUsageRequest) (*commonpb.TemplateUsage, error) { + return nil, status.Error(codes.Unimplemented, "method GetTemplateUsage not implemented") +} func (UnimplementedBucketServiceServer) InspectIndex(context.Context, *InspectIndexRequest) (*InspectIndexResponse, error) { return nil, status.Error(codes.Unimplemented, "method InspectIndex not implemented") } @@ -1404,6 +1426,24 @@ func _BucketService_ListNumscripts_Handler(srv interface{}, stream grpc.ServerSt // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type BucketService_ListNumscriptsServer = grpc.ServerStreamingServer[commonpb.NumscriptInfo] +func _BucketService_GetTemplateUsage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTemplateUsageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BucketServiceServer).GetTemplateUsage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BucketService_GetTemplateUsage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BucketServiceServer).GetTemplateUsage(ctx, req.(*GetTemplateUsageRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _BucketService_InspectIndex_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(InspectIndexRequest) if err := dec(in); err != nil { @@ -1539,6 +1579,10 @@ var BucketService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetNumscript", Handler: _BucketService_GetNumscript_Handler, }, + { + MethodName: "GetTemplateUsage", + Handler: _BucketService_GetTemplateUsage_Handler, + }, { MethodName: "InspectIndex", Handler: _BucketService_InspectIndex_Handler, diff --git a/internal/proto/servicepb/bucket_reader.pb.go b/internal/proto/servicepb/bucket_reader.pb.go index 72f4df5889..9f88b4174a 100644 --- a/internal/proto/servicepb/bucket_reader.pb.go +++ b/internal/proto/servicepb/bucket_reader.pb.go @@ -3040,6 +3040,78 @@ func NewListNumscriptsRequestListReader(s []*ListNumscriptsRequest) ListNumscrip return listNumscriptsRequestListReadonly(s) } +// GetTemplateUsageRequestReader provides read-only access to GetTemplateUsageRequest. +// Call Mutate() to obtain a mutable clone. +type GetTemplateUsageRequestReader interface { + GetLedger() string + GetName() string + Mutate() *GetTemplateUsageRequest +} + +type getTemplateUsageRequestReadonly GetTemplateUsageRequest + +func (r *getTemplateUsageRequestReadonly) GetLedger() string { + return (*GetTemplateUsageRequest)(r).GetLedger() +} + +func (r *getTemplateUsageRequestReadonly) GetName() string { + return (*GetTemplateUsageRequest)(r).GetName() +} + +func (r *getTemplateUsageRequestReadonly) Mutate() *GetTemplateUsageRequest { + return (*GetTemplateUsageRequest)(r).CloneVT() +} + +// AsReader returns a read-only view of this GetTemplateUsageRequest. +func (m *GetTemplateUsageRequest) AsReader() GetTemplateUsageRequestReader { + if m == nil { + return nil + } + return (*getTemplateUsageRequestReadonly)(m) +} + +// Mutate returns a mutable deep clone of this GetTemplateUsageRequest. +func (m *GetTemplateUsageRequest) Mutate() *GetTemplateUsageRequest { + return m.CloneVT() +} + +// GetTemplateUsageRequestListReader provides read-only iteration over []*GetTemplateUsageRequest. +type GetTemplateUsageRequestListReader interface { + Len() int + Get(i int) GetTemplateUsageRequestReader + Range(yield func(int, GetTemplateUsageRequestReader) bool) +} + +type getTemplateUsageRequestListReadonly []*GetTemplateUsageRequest + +func (l getTemplateUsageRequestListReadonly) Len() int { return len(l) } + +func (l getTemplateUsageRequestListReadonly) Get(i int) GetTemplateUsageRequestReader { + v := l[i] + if v == nil { + return nil + } + return v.AsReader() +} + +func (l getTemplateUsageRequestListReadonly) Range(yield func(int, GetTemplateUsageRequestReader) bool) { + for i, v := range l { + var r GetTemplateUsageRequestReader + if v != nil { + r = v.AsReader() + } + if !yield(i, r) { + return + } + } +} + +// NewGetTemplateUsageRequestListReader wraps s for read-only iteration. The returned +// view aliases the underlying slice; do not mutate s afterwards. +func NewGetTemplateUsageRequestListReader(s []*GetTemplateUsageRequest) GetTemplateUsageRequestListReader { + return getTemplateUsageRequestListReadonly(s) +} + // ScriptReferenceReader provides read-only access to ScriptReference. // Call Mutate() to obtain a mutable clone. type ScriptReferenceReader interface { diff --git a/internal/proto/servicepb/bucket_vtproto.pb.go b/internal/proto/servicepb/bucket_vtproto.pb.go index 2b8d3373c3..edaa4375ee 100644 --- a/internal/proto/servicepb/bucket_vtproto.pb.go +++ b/internal/proto/servicepb/bucket_vtproto.pb.go @@ -1124,6 +1124,24 @@ func (m *ListNumscriptsRequest) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *GetTemplateUsageRequest) CloneVT() *GetTemplateUsageRequest { + if m == nil { + return (*GetTemplateUsageRequest)(nil) + } + r := new(GetTemplateUsageRequest) + r.Ledger = m.Ledger + r.Name = m.Name + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetTemplateUsageRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *ScriptReference) CloneVT() *ScriptReference { if m == nil { return (*ScriptReference)(nil) @@ -5040,6 +5058,28 @@ func (this *ListNumscriptsRequest) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *GetTemplateUsageRequest) EqualVT(that *GetTemplateUsageRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Ledger != that.Ledger { + return false + } + if this.Name != that.Name { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetTemplateUsageRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetTemplateUsageRequest) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *ScriptReference) EqualVT(that *ScriptReference) bool { if this == that { return true @@ -10848,6 +10888,53 @@ func (m *ListNumscriptsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *GetTemplateUsageRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetTemplateUsageRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetTemplateUsageRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if len(m.Ledger) > 0 { + i -= len(m.Ledger) + copy(dAtA[i:], m.Ledger) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ledger))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *ScriptReference) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -17345,6 +17432,24 @@ func (m *ListNumscriptsRequest) SizeVT() (n int) { return n } +func (m *GetTemplateUsageRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Ledger) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + func (m *ScriptReference) SizeVT() (n int) { if m == nil { return 0 @@ -25388,6 +25493,121 @@ func (m *ListNumscriptsRequest) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *GetTemplateUsageRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetTemplateUsageRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetTemplateUsageRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ledger", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ledger = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ScriptReference) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/internal/storage/usagestore/comparer.go b/internal/storage/usagestore/comparer.go new file mode 100644 index 0000000000..ac9e6992ee --- /dev/null +++ b/internal/storage/usagestore/comparer.go @@ -0,0 +1,127 @@ +package usagestore + +import ( + "bytes" + "encoding/binary" + + "github.com/cockroachdb/pebble/v2" + + "github.com/formancehq/ledger/v3/internal/storage/dal" +) + +// usageStoreComparerName is persisted in the Pebble database. Changing it +// requires rebuilding the usage store from the Raft log. +const usageStoreComparerName = "formance.usagestore.v1" + +// ledgerScopedPrefixLen is the split point for ledger-scoped keys: +// 1 byte prefix + LedgerNameFixedSize bytes ledger name (zero-padded). +const ledgerScopedPrefixLen = 1 + dal.LedgerNameFixedSize + +// UsageStoreComparer splits keys at the [prefix_byte][ledger_name padded 64B] +// boundary so that bloom filters are built on the ledger-scoped prefix rather +// than the full key. Mirrors readstore's comparer semantics — see that file +// for the full rationale. +var UsageStoreComparer = &pebble.Comparer{ + Compare: bytes.Compare, + Equal: bytes.Equal, + ComparePointSuffixes: bytes.Compare, + CompareRangeSuffixes: bytes.Compare, + + AbbreviatedKey: func(key []byte) uint64 { + if len(key) >= 8 { + return binary.BigEndian.Uint64(key) + } + + var v uint64 + for _, b := range key { + v <<= 8 + v |= uint64(b) + } + + return v << uint(8*(8-len(key))) + }, + + FormatKey: pebble.DefaultComparer.FormatKey, + + Separator: func(dst, a, b []byte) []byte { + i := commonPrefixLen(a, b) + dst = append(dst, a...) + + if i == len(a) || i == len(b) { + return dst + } + + if a[i] >= b[i] { + return dst + } + + n := len(dst) - len(a) + if c := a[i] + 1; c < b[i] { + dst[n+i] = c + + return dst[:n+i+1] + } + + return dst + }, + + Successor: func(dst, a []byte) []byte { + for i := range a { + if a[i] != 0xff { + dst = append(dst, a[:i+1]...) + dst[len(dst)-1]++ + + return dst + } + } + + return append(dst, a...) + }, + + Split: usageStoreSplit, + + ImmediateSuccessor: func(dst, prefix []byte) []byte { + dst = append(dst[:0], prefix...) + if len(dst) == ledgerScopedPrefixLen { + dst[len(dst)-1]++ + + return dst + } + + return append(dst, 0x00) + }, + + Name: usageStoreComparerName, +} + +// usageStoreSplit returns the split point for bloom filter prefix extraction. +func usageStoreSplit(key []byte) int { + if len(key) <= 1 { + return len(key) + } + + // Internal singleton keys (non-ledger-scoped) — full key is the prefix. + if key[0] == PrefixInternal { + return len(key) + } + + // Ledger-scoped keys: [prefix_byte][ledger_name padded 64B][...]. + if len(key) >= ledgerScopedPrefixLen { + return ledgerScopedPrefixLen + } + + return len(key) +} + +// commonPrefixLen returns the length of the longest common prefix of a and b. +func commonPrefixLen(a, b []byte) int { + n := min(len(a), len(b)) + + for i := range n { + if a[i] != b[i] { + return i + } + } + + return n +} diff --git a/internal/storage/usagestore/delete_ledger.go b/internal/storage/usagestore/delete_ledger.go new file mode 100644 index 0000000000..98be39a8f0 --- /dev/null +++ b/internal/storage/usagestore/delete_ledger.go @@ -0,0 +1,52 @@ +package usagestore + +import ( + "fmt" + + "github.com/formancehq/ledger/v3/internal/storage/dal" +) + +// ledgerScopedPrefixes lists all usage store key prefixes that contain +// ledger-scoped data (keyed by [prefix][ledgerName padded 64B]...). Every +// entry MUST be wiped by DeleteLedger — missing one leaks rows past a +// ledger drop. +var ledgerScopedPrefixes = [][]byte{ + {PrefixTemplate}, + {PrefixCounter}, +} + +// DeleteLedger removes all usage data for the given ledger. Performs range +// deletes on every ledger-scoped prefix: [prefix][ledgerName padded 64B] -> +// successor of that padded block. +// +// Validation guarantees ledger names are printable ASCII only, so the last +// padding byte is never 0xFF — incrementing it cannot carry past the +// fixed-width name block and yields a clean exclusive upper bound. +func DeleteLedger(batch *dal.WriteSession, ledgerName string) error { + for _, prefix := range ledgerScopedPrefixes { + start := make([]byte, 0, len(prefix)+dal.LedgerNameFixedSize) + start = append(start, prefix...) + start = appendPaddedLedgerName(start, ledgerName) + + end := make([]byte, 0, len(prefix)+dal.LedgerNameFixedSize) + end = append(end, prefix...) + end = appendPaddedLedgerName(end, ledgerName) + end[len(end)-1]++ + + if err := batch.DeleteRangeNoSync(start, end); err != nil { + return fmt.Errorf("deleting usage store prefix %x for ledger %q: %w", prefix, ledgerName, err) + } + } + + return nil +} + +// appendPaddedLedgerName appends the ledger name zero-padded to +// dal.LedgerNameFixedSize bytes. Callers MUST validate the name length +// upstream — copy() truncates silently here. +func appendPaddedLedgerName(dst []byte, name string) []byte { + var pad [dal.LedgerNameFixedSize]byte + copy(pad[:], name) + + return append(dst, pad[:]...) +} diff --git a/internal/storage/usagestore/keys.go b/internal/storage/usagestore/keys.go new file mode 100644 index 0000000000..d1f87d266d --- /dev/null +++ b/internal/storage/usagestore/keys.go @@ -0,0 +1,67 @@ +package usagestore + +import ( + "github.com/formancehq/ledger/v3/internal/storage/dal" +) + +// Pebble key prefixes for the usagebuilder's dedicated secondary store. +// All ledger-scoped keys follow [prefix][ledgerName padded 64B][...] so +// the comparer can build bloom filters on the ledger-scoped prefix — same +// pattern as the readstore. +const ( + // PrefixTemplate — per-template usage record. + // Key: [0x01][ledgerName padded 64B][templateName] → TemplateUsage proto. + PrefixTemplate byte = 0x01 + + // PrefixCounter — per-ledger event counter. + // Key: [0x02][ledgerName padded 64B][counterID] → uint64 BE. + PrefixCounter byte = 0x02 + + // PrefixInternal groups all non-ledger-scoped keys under a single prefix + // so Comparer.Split treats them uniformly (full key = prefix). + PrefixInternal byte = 0xFE + + // SubInternalProgress — [0xFE][0x01] → last consumed log sequence (uint64 BE). + SubInternalProgress byte = 0x01 +) + +// Counter IDs identify each per-ledger event counter mirrored by the +// usagebuilder. Values are stable on-disk identifiers — never renumber. +const ( + CounterPosting byte = 0x01 // posting_count — sum len(Transaction.Postings) per CreatedTransaction / RevertedTransaction log + CounterRevert byte = 0x02 // revert_count — count RevertTransactionOrder + MirrorRevertTransactionOrder + CounterNumscriptExecution byte = 0x03 // numscript_execution_count — count CreateTransactionOrder with Script or NumscriptReference + CounterReference byte = 0x04 // reference_count — count CreateTransactionOrder with non-empty Reference + CounterEphemeralEvicted byte = 0x05 // ephemeral_evicted_count — sum len(LedgerLog.EphemeralVolumes) per log (pure ephemeral: new + purged same log) + CounterTransientUsed byte = 0x06 // transient_used_count — sum len(AppliedProposal.TransientVolumes[ledger].Volumes) per proposal + CounterVolume byte = 0x07 // volume_count — sum len(LedgerLog.NewKeptVolumes) - len(LedgerLog.PurgedVolumes) per log (ephemeral contributes 0) +) + +// ProgressKey returns the full key for the usagebuilder progress entry. +// +// [0xFE][0x01] +func ProgressKey() []byte { + return []byte{PrefixInternal, SubInternalProgress} +} + +// TemplateUsageKey builds the per-ledger, per-template usage entry key. +// +// [0x01][ledgerName padded 64B][templateName] +func TemplateUsageKey(kb *dal.KeyBuilder, ledgerName, templateName string) []byte { + return kb.Reset(). + PutByte(PrefixTemplate). + PutLedgerNameFixed(ledgerName). + PutString(templateName). + Consume() +} + +// CounterKey builds the per-ledger event counter key. +// +// [0x02][ledgerName padded 64B][counterID] +func CounterKey(kb *dal.KeyBuilder, ledgerName string, counterID byte) []byte { + return kb.Reset(). + PutByte(PrefixCounter). + PutLedgerNameFixed(ledgerName). + PutByte(counterID). + Consume() +} diff --git a/internal/storage/usagestore/metrics.go b/internal/storage/usagestore/metrics.go new file mode 100644 index 0000000000..a484f892b5 --- /dev/null +++ b/internal/storage/usagestore/metrics.go @@ -0,0 +1,66 @@ +package usagestore + +import ( + "context" + "fmt" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" +) + +// RegisterMetrics registers Pebble-internal metrics for the usage store. +// Mirrors readstore.Store.RegisterMetrics with a "usagestore." namespace so +// operators can see LSM state, cache hit rates, and memtable pressure per +// secondary store. +func (s *Store) RegisterMetrics(m metric.Meter) (metric.Registration, error) { + levelBytes, err := m.Int64ObservableGauge( + "usagestore.level.bytes", + metric.WithDescription("Total bytes in each Pebble level"), + metric.WithUnit("By"), + ) + if err != nil { + return nil, fmt.Errorf("creating usagestore.level.bytes gauge: %w", err) + } + + memtableBytes, err := m.Int64ObservableGauge( + "usagestore.memtable.bytes", + metric.WithDescription("Current memtable size in bytes"), + metric.WithUnit("By"), + ) + if err != nil { + return nil, fmt.Errorf("creating usagestore.memtable.bytes gauge: %w", err) + } + + cacheHits, err := m.Int64ObservableGauge( + "usagestore.cache.hits", + metric.WithDescription("Block cache hits"), + metric.WithUnit("{hits}"), + ) + if err != nil { + return nil, fmt.Errorf("creating usagestore.cache.hits gauge: %w", err) + } + + cacheMisses, err := m.Int64ObservableGauge( + "usagestore.cache.misses", + metric.WithDescription("Block cache misses"), + metric.WithUnit("{misses}"), + ) + if err != nil { + return nil, fmt.Errorf("creating usagestore.cache.misses gauge: %w", err) + } + + return m.RegisterCallback(func(_ context.Context, o metric.Observer) error { + metrics := s.db.Metrics() + + for i, level := range metrics.Levels { + o.ObserveInt64(levelBytes, level.TablesSize, + metric.WithAttributes(attribute.Int("level", i))) + } + + o.ObserveInt64(memtableBytes, int64(metrics.MemTable.Size)) + o.ObserveInt64(cacheHits, metrics.BlockCache.Hits) + o.ObserveInt64(cacheMisses, metrics.BlockCache.Misses) + + return nil + }, levelBytes, memtableBytes, cacheHits, cacheMisses) +} diff --git a/internal/storage/usagestore/snapshot.go b/internal/storage/usagestore/snapshot.go new file mode 100644 index 0000000000..5962e7bac8 --- /dev/null +++ b/internal/storage/usagestore/snapshot.go @@ -0,0 +1,82 @@ +package usagestore + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/cockroachdb/pebble/v2" + + "github.com/formancehq/ledger/v3/internal/proto/commonpb" + "github.com/formancehq/ledger/v3/internal/storage/dal" +) + +// Snapshot is a point-in-time view of the usage store. Multiple Gets against +// the same Snapshot observe a coherent set of counter values — no +// intervening usagebuilder commit can shift one counter relative to another +// mid-read. +// +// Callers MUST call Close() to release the underlying Pebble snapshot. +type Snapshot struct { + snap *pebble.Snapshot +} + +// NewSnapshot returns a fresh point-in-time snapshot. The caller owns the +// snapshot and is responsible for closing it. +func (s *Store) NewSnapshot() *Snapshot { + return &Snapshot{snap: s.db.NewSnapshot()} +} + +// Close releases the underlying Pebble snapshot. +func (s *Snapshot) Close() error { + return s.snap.Close() +} + +// GetCounter reads the value of a per-ledger event counter from this +// snapshot. Missing keys return 0. +func (s *Snapshot) GetCounter(ledgerName string, counterID byte) (uint64, error) { + kb := dal.NewKeyBuilder() + key := CounterKey(kb, ledgerName, counterID) + + v, closer, err := s.snap.Get(key) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return 0, nil + } + + return 0, fmt.Errorf("reading counter %#x for ledger %q: %w", counterID, ledgerName, err) + } + + defer func() { _ = closer.Close() }() + + if len(v) != 8 { + return 0, fmt.Errorf("corrupt counter value: expected 8 bytes, got %d", len(v)) + } + + return binary.BigEndian.Uint64(v), nil +} + +// GetTemplateUsage reads a template usage record from this snapshot. +// Returns (nil, nil) when the entry does not exist. +func (s *Snapshot) GetTemplateUsage(ledgerName, templateName string) (*commonpb.TemplateUsage, error) { + kb := dal.NewKeyBuilder() + key := TemplateUsageKey(kb, ledgerName, templateName) + + v, closer, err := s.snap.Get(key) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return nil, nil + } + + return nil, fmt.Errorf("reading template usage: %w", err) + } + + defer func() { _ = closer.Close() }() + + usage := &commonpb.TemplateUsage{} + if err := usage.UnmarshalVT(v); err != nil { + return nil, fmt.Errorf("unmarshaling template usage: %w", err) + } + + return usage, nil +} diff --git a/internal/storage/usagestore/store.go b/internal/storage/usagestore/store.go new file mode 100644 index 0000000000..b629e69a38 --- /dev/null +++ b/internal/storage/usagestore/store.go @@ -0,0 +1,292 @@ +package usagestore + +import ( + "encoding/binary" + "errors" + "fmt" + "os" + "path/filepath" + "time" + + "github.com/cockroachdb/pebble/v2" + + logging "github.com/formancehq/go-libs/v5/pkg/observe/log" + + "github.com/formancehq/ledger/v3/internal/proto/commonpb" + "github.com/formancehq/ledger/v3/internal/storage/dal" + "github.com/formancehq/ledger/v3/internal/storage/pebblecfg" +) + +// DefaultConfig returns the default Pebble configuration for the usage store. +// Reuses the same tunables type as the primary store (pebblecfg.Config). +// Sized smaller than the read index: the usage store holds O(ledgers × templates) +// entries plus a handful of per-ledger counters, so it never grows large. +func DefaultConfig() pebblecfg.Config { + return pebblecfg.Config{ + MemTableSize: 16 << 20, // 16MB + MemTableStopWritesThreshold: 4, + L0CompactionThreshold: 4, + L0StopWritesThreshold: 12, + LBaseMaxBytes: 128 << 20, // 128MB + CacheSize: 16 << 20, // 16MB + TargetFileSize: 16 << 20, // 16MB + BytesPerSync: 512 << 10, // 512KB + MaxConcurrentCompactions: 1, + Compression: pebblecfg.DefaultLevelCompression(), + } +} + +// Store wraps a Pebble database for the usagebuilder's projections. +// It is a peer to readstore.Store — a distinct physical secondary store, +// so a corruption of one cannot touch the other and each subsystem's +// rebuild story is decoupled (drop the directory + restart). +type Store struct { + db *pebble.DB + logger logging.Logger + dir string +} + +// New opens or creates a Pebble database at the given directory. +func New(dir string, logger logging.Logger, cfg pebblecfg.Config) (*Store, error) { + if err := os.MkdirAll(dir, 0o750); err != nil { + return nil, fmt.Errorf("creating usage store directory: %w", err) + } + + dbPath := filepath.Join(dir, "usagedb") + + var fileSize int64 + if info, _ := os.Stat(dbPath); info != nil { + fileSize = info.Size() + } + + logger.WithFields(map[string]any{ + "path": dbPath, + "fileSize": fileSize, + }).Infof("Opening Pebble usage store") + + openStart := time.Now() + + cache := pebble.NewCache(cfg.CacheSize) + defer cache.Unref() + + opts := &pebble.Options{ + Logger: dal.NewPebbleLogger(logger), + FormatMajorVersion: pebble.FormatNewest, + Comparer: UsageStoreComparer, + // The usage store is a derived projection rebuilt from the audit log. + // WAL disabled — on crash the usagebuilder simply replays from its + // last progress cursor. + DisableWAL: true, + MemTableSize: cfg.MemTableSize, + MemTableStopWritesThreshold: cfg.MemTableStopWritesThreshold, + L0CompactionThreshold: cfg.L0CompactionThreshold, + L0StopWritesThreshold: cfg.L0StopWritesThreshold, + LBaseMaxBytes: cfg.LBaseMaxBytes, + BytesPerSync: cfg.BytesPerSync, + CompactionConcurrencyRange: func() (int, int) { + n := cfg.MaxConcurrentCompactions + + return n, n + }, + Cache: cache, + TargetFileSizes: cfg.BuildTargetFileSizes(), + Levels: cfg.BuildLevels(), + } + + db, err := pebble.Open(dbPath, opts) + if err != nil { + return nil, fmt.Errorf("opening Pebble usage store: %w", err) + } + + m := db.Metrics() + logger.WithFields(map[string]any{ + "duration": time.Since(openStart).String(), + "l0FileCount": m.Levels[0].TablesCount, + "l0Size": m.Levels[0].TablesSize, + "memTableCount": m.MemTable.Count, + "memTableSize": m.MemTable.Size, + "totalLevelsSize": m.DiskSpaceUsage(), + }).Infof("Pebble usage store opened — LSM state") + + return &Store{ + db: db, + logger: logger.WithFields(map[string]any{"cmp": "usage-store"}), + dir: dir, + }, nil +} + +// OpenReadOnly opens a Pebble usage store at dirPath in read-only mode. +// The caller must call Close() when done. +func OpenReadOnly(dirPath string, logger logging.Logger) (*Store, error) { + db, err := pebble.Open(dirPath, &pebble.Options{ + Logger: dal.NewPebbleLogger(logger), + Comparer: UsageStoreComparer, + ReadOnly: true, + }) + if err != nil { + return nil, fmt.Errorf("opening read-only Pebble usage store at %s: %w", dirPath, err) + } + + return &Store{ + db: db, + logger: logger.WithFields(map[string]any{"cmp": "usage-store-readonly"}), + dir: dirPath, + }, nil +} + +// CreateCheckpoint creates a Pebble checkpoint of the usage store at destDir. +func (s *Store) CreateCheckpoint(destDir string) error { + return s.db.Checkpoint(destDir) +} + +// Close closes the underlying Pebble database. +func (s *Store) Close() error { + return s.db.Close() +} + +// DB returns the underlying Pebble database for creating batches. +func (s *Store) DB() *pebble.DB { + return s.db +} + +// NewBatch creates a dal.WriteSession backed by the usage store's Pebble DB. +func (s *Store) NewBatch() *dal.WriteSession { + return dal.NewWriteSessionFromDB(s.db) +} + +// Path returns the directory of the usage store. +func (s *Store) Path() string { + return s.dir +} + +// ReadProgress returns the last log sequence consumed by the usagebuilder. +// Returns 0 if no progress has been recorded. +func (s *Store) ReadProgress() (uint64, error) { + v, closer, err := s.db.Get(ProgressKey()) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return 0, nil + } + + return 0, fmt.Errorf("reading usage progress: %w", err) + } + + defer func() { _ = closer.Close() }() + + if len(v) != 8 { + return 0, fmt.Errorf("corrupt usage progress value: expected 8 bytes, got %d", len(v)) + } + + return binary.BigEndian.Uint64(v), nil +} + +// WriteProgress stores the last log sequence consumed by the usagebuilder. +func (s *Store) WriteProgress(batch *dal.WriteSession, sequence uint64) error { + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], sequence) + + return batch.SetBytes(ProgressKey(), buf[:]) +} + +// Reset wipes every projection row (all per-template usage records and all +// per-ledger counters) and clears the persisted progress cursor, so the next +// boot replays from audit sequence 0. It is a full-rebuild primitive: the +// projection reconverges by re-folding the audit chain from the start. The +// builder itself never calls this for a rollback — the audit chain is +// append-only so the persisted cursor can never sit ahead of the head; Reset +// exists for an explicit operator-triggered rebuild of the side-store. +// +// The two ledger-scoped prefixes (PrefixTemplate 0x01, PrefixCounter 0x02) are +// contiguous, so one DeleteRange over [0x01, 0x03) covers both; the internal +// progress key ([0xFE][0x01]) is deleted point-wise. Rows and cursor are wiped +// in a single Pebble batch, so a crash applies all of it or none of it — the +// rows can never survive with a stale non-zero cursor. +func (s *Store) Reset() error { + batch := s.NewBatch() + + if err := batch.DeleteRangeNoSync([]byte{PrefixTemplate}, []byte{PrefixCounter + 1}); err != nil { + _ = batch.Cancel() + + return fmt.Errorf("deleting projection rows during reset: %w", err) + } + + if err := batch.DeleteKey(ProgressKey()); err != nil { + _ = batch.Cancel() + + return fmt.Errorf("deleting progress cursor during reset: %w", err) + } + + if err := batch.Commit(); err != nil { + _ = batch.Cancel() + + return fmt.Errorf("committing usage store reset: %w", err) + } + + return nil +} + +// GetTemplateUsage reads the current usage record for (ledger, template). +// Returns (nil, nil) if no entry exists. +func (s *Store) GetTemplateUsage(ledgerName, templateName string) (*commonpb.TemplateUsage, error) { + kb := dal.NewKeyBuilder() + key := TemplateUsageKey(kb, ledgerName, templateName) + + v, closer, err := s.db.Get(key) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return nil, nil + } + + return nil, fmt.Errorf("reading template usage: %w", err) + } + + defer func() { _ = closer.Close() }() + + usage := &commonpb.TemplateUsage{} + if err := usage.UnmarshalVT(v); err != nil { + return nil, fmt.Errorf("unmarshaling template usage: %w", err) + } + + return usage, nil +} + +// PutTemplateUsage persists a template usage record into the pending batch. +func (s *Store) PutTemplateUsage(batch *dal.WriteSession, ledgerName, templateName string, usage *commonpb.TemplateUsage) error { + key := TemplateUsageKey(batch.KeyBuilder, ledgerName, templateName) + + return batch.SetProto(key, usage) +} + +// GetCounter reads the current value of a per-ledger event counter. +// Returns 0 if no entry exists. +func (s *Store) GetCounter(ledgerName string, counterID byte) (uint64, error) { + kb := dal.NewKeyBuilder() + key := CounterKey(kb, ledgerName, counterID) + + v, closer, err := s.db.Get(key) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return 0, nil + } + + return 0, fmt.Errorf("reading counter %#x for ledger %q: %w", counterID, ledgerName, err) + } + + defer func() { _ = closer.Close() }() + + if len(v) != 8 { + return 0, fmt.Errorf("corrupt counter value: expected 8 bytes, got %d", len(v)) + } + + return binary.BigEndian.Uint64(v), nil +} + +// PutCounter persists a per-ledger event counter value into the pending batch. +func (s *Store) PutCounter(batch *dal.WriteSession, ledgerName string, counterID byte, value uint64) error { + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], value) + + key := CounterKey(batch.KeyBuilder, ledgerName, counterID) + + return batch.SetBytes(key, buf[:]) +} diff --git a/internal/storage/usagestore/store_test.go b/internal/storage/usagestore/store_test.go new file mode 100644 index 0000000000..18d611b359 --- /dev/null +++ b/internal/storage/usagestore/store_test.go @@ -0,0 +1,179 @@ +package usagestore_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + logging "github.com/formancehq/go-libs/v5/pkg/observe/log" + + "github.com/formancehq/ledger/v3/internal/proto/commonpb" + "github.com/formancehq/ledger/v3/internal/storage/usagestore" +) + +func newTestStore(t *testing.T) *usagestore.Store { + t.Helper() + + s, err := usagestore.New(t.TempDir(), logging.NopZap(), usagestore.DefaultConfig()) + require.NoError(t, err) + + t.Cleanup(func() { _ = s.Close() }) + + return s +} + +func TestStore_ProgressRoundTrip(t *testing.T) { + t.Parallel() + + s := newTestStore(t) + + seq, err := s.ReadProgress() + require.NoError(t, err) + assert.Equal(t, uint64(0), seq, "fresh store must report cursor 0") + + batch := s.NewBatch() + require.NoError(t, s.WriteProgress(batch, 42)) + require.NoError(t, batch.Commit()) + + seq, err = s.ReadProgress() + require.NoError(t, err) + assert.Equal(t, uint64(42), seq) +} + +func TestStore_CounterRoundTrip(t *testing.T) { + t.Parallel() + + s := newTestStore(t) + + v, err := s.GetCounter("l1", usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(0), v, "missing counter must return 0, not error") + + batch := s.NewBatch() + require.NoError(t, s.PutCounter(batch, "l1", usagestore.CounterPosting, 123)) + require.NoError(t, s.PutCounter(batch, "l1", usagestore.CounterRevert, 4)) + require.NoError(t, s.PutCounter(batch, "l2", usagestore.CounterPosting, 999)) + require.NoError(t, batch.Commit()) + + posting, err := s.GetCounter("l1", usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(123), posting) + + revert, err := s.GetCounter("l1", usagestore.CounterRevert) + require.NoError(t, err) + assert.Equal(t, uint64(4), revert) + + other, err := s.GetCounter("l2", usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(999), other, "counters must be per-ledger scoped") +} + +func TestStore_TemplateUsageRoundTrip(t *testing.T) { + t.Parallel() + + s := newTestStore(t) + + usage, err := s.GetTemplateUsage("l1", "missing") + require.NoError(t, err) + assert.Nil(t, usage, "missing template must return (nil, nil)") + + want := &commonpb.TemplateUsage{ + Count: 7, + LastUsed: &commonpb.Timestamp{Data: 1_700_000_000_000_000_000}, + } + + batch := s.NewBatch() + require.NoError(t, s.PutTemplateUsage(batch, "l1", "payout", want)) + require.NoError(t, batch.Commit()) + + got, err := s.GetTemplateUsage("l1", "payout") + require.NoError(t, err) + require.NotNil(t, got) + assert.Equal(t, want.GetCount(), got.GetCount()) + assert.Equal(t, want.GetLastUsed().GetData(), got.GetLastUsed().GetData()) +} + +func TestStore_DeleteLedgerCascade(t *testing.T) { + t.Parallel() + + s := newTestStore(t) + + // Seed both scopes for two ledgers. + batch := s.NewBatch() + require.NoError(t, s.PutCounter(batch, "l1", usagestore.CounterPosting, 10)) + require.NoError(t, s.PutTemplateUsage(batch, "l1", "t1", &commonpb.TemplateUsage{Count: 3})) + require.NoError(t, s.PutCounter(batch, "l2", usagestore.CounterPosting, 20)) + require.NoError(t, s.PutTemplateUsage(batch, "l2", "t2", &commonpb.TemplateUsage{Count: 5})) + require.NoError(t, batch.Commit()) + + // Drop l1 only. + batch = s.NewBatch() + require.NoError(t, usagestore.DeleteLedger(batch, "l1")) + require.NoError(t, batch.Commit()) + + // l1 is gone. + v, err := s.GetCounter("l1", usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(0), v) + + tu, err := s.GetTemplateUsage("l1", "t1") + require.NoError(t, err) + assert.Nil(t, tu) + + // l2 survives. + v, err = s.GetCounter("l2", usagestore.CounterPosting) + require.NoError(t, err) + assert.Equal(t, uint64(20), v) + + tu, err = s.GetTemplateUsage("l2", "t2") + require.NoError(t, err) + require.NotNil(t, tu) + assert.Equal(t, uint64(5), tu.GetCount()) +} + +// TestStore_Reset guards the primary-store-rollback recovery path: Reset must +// wipe every counter + template row across all ledgers AND clear the progress +// cursor so the builder replays from audit sequence 0. +func TestStore_Reset(t *testing.T) { + t.Parallel() + + s := newTestStore(t) + + // Seed counters + templates for two ledgers, plus a progress cursor + // simulating a projection that had consumed 500 audit entries. + batch := s.NewBatch() + require.NoError(t, s.PutCounter(batch, "l1", usagestore.CounterPosting, 10)) + require.NoError(t, s.PutCounter(batch, "l1", usagestore.CounterVolume, 3)) + require.NoError(t, s.PutTemplateUsage(batch, "l1", "t1", &commonpb.TemplateUsage{Count: 3})) + require.NoError(t, s.PutCounter(batch, "l2", usagestore.CounterPosting, 20)) + require.NoError(t, s.PutTemplateUsage(batch, "l2", "t2", &commonpb.TemplateUsage{Count: 5})) + require.NoError(t, s.WriteProgress(batch, 500)) + require.NoError(t, batch.Commit()) + + require.NoError(t, s.Reset()) + + // Every counter across both ledgers reads 0. + for _, ledger := range []string{"l1", "l2"} { + for _, counter := range []byte{usagestore.CounterPosting, usagestore.CounterVolume} { + v, err := s.GetCounter(ledger, counter) + require.NoError(t, err) + assert.Equal(t, uint64(0), v, "counter %#x for %q must be wiped by Reset", counter, ledger) + } + } + + // Every template row is gone. + for _, tk := range []struct{ ledger, tpl string }{{"l1", "t1"}, {"l2", "t2"}} { + tu, err := s.GetTemplateUsage(tk.ledger, tk.tpl) + require.NoError(t, err) + assert.Nil(t, tu, "template %q/%q must be wiped by Reset", tk.ledger, tk.tpl) + } + + // The cursor is back to 0 so the next boot replays from the start. + seq, err := s.ReadProgress() + require.NoError(t, err) + assert.Equal(t, uint64(0), seq, "Reset must clear the progress cursor") + + // Reset on an already-empty store is a no-op, not an error. + require.NoError(t, s.Reset()) +} diff --git a/misc/devenv/monitoring-dashboards/jsonnet/lib/metrics.libsonnet b/misc/devenv/monitoring-dashboards/jsonnet/lib/metrics.libsonnet index 100f9812ed..7baf2b8374 100644 --- a/misc/devenv/monitoring-dashboards/jsonnet/lib/metrics.libsonnet +++ b/misc/devenv/monitoring-dashboards/jsonnet/lib/metrics.libsonnet @@ -74,6 +74,13 @@ lag: 'audit_index.lag', }, + // usage.builder — internal/application/usagebuilder/builder.go + usage_builder:: { + last_indexed_sequence: 'usage.builder.last_indexed_sequence', + audit_last_sequence: 'usage.builder.audit_last_sequence', + lag: 'usage.builder.lag', + }, + // numscript — internal/domain/processing/numscript/cache.go numscript:: { cache_size: 'numscript.cache.size', @@ -160,6 +167,14 @@ cache_misses: 'readindex.cache.misses', }, + // usagestore — internal/storage/usagestore/metrics.go + usagestore:: { + level_bytes: 'usagestore.level.bytes', + memtable_bytes: 'usagestore.memtable.bytes', + cache_hits: 'usagestore.cache.hits', + cache_misses: 'usagestore.cache.misses', + }, + // health — internal/infra/health/healthcheck.go health:: { disk_poll_failures: 'health.disk.poll.failures', diff --git a/misc/proto/bucket.proto b/misc/proto/bucket.proto index cee686f3dd..276a0b8e0f 100644 --- a/misc/proto/bucket.proto +++ b/misc/proto/bucket.proto @@ -108,6 +108,10 @@ service BucketService { rpc GetNumscript(GetNumscriptRequest) returns (common.NumscriptInfo); // ListNumscripts streams all numscripts (latest version of each) rpc ListNumscripts(ListNumscriptsRequest) returns (stream common.NumscriptInfo); + // GetTemplateUsage returns per-template invocation usage populated by the + // usagebuilder subsystem. Eventually consistent — may lag the live FSM + // by up to one usagebuilder tick interval. + rpc GetTemplateUsage(GetTemplateUsageRequest) returns (common.TemplateUsage); // InspectIndex scans a metadata index and returns distinct values, facets, or a summary rpc InspectIndex(InspectIndexRequest) returns (InspectIndexResponse); // Barrier proposes a no-op through Raft consensus. When it returns, all @@ -463,6 +467,15 @@ message ListNumscriptsRequest { common.ListOptions options = 2; } +// GetTemplateUsageRequest retrieves the invocation counter + last-used +// timestamp for a Numscript template. The counter is materialised +// asynchronously by the usagebuilder from the audit chain — expect up to +// one tick interval of lag behind the live FSM. +message GetTemplateUsageRequest { + string ledger = 1; + string name = 2; +} + // ScriptReference references a numscript from the library by name and optional version. message ScriptReference { string name = 1; diff --git a/misc/proto/common.proto b/misc/proto/common.proto index aa8439c5b4..a8c951022e 100644 --- a/misc/proto/common.proto +++ b/misc/proto/common.proto @@ -534,6 +534,14 @@ message DeletedNumscriptLog { string ledger = 2; } +// TemplateUsage tracks per-template invocation usage. Persisted as a +// projection of the audit log by the usagebuilder subsystem — NOT part of +// the FSM authoritative state. Rebuildable from cursor=0 on demand. +message TemplateUsage { + fixed64 count = 1; + Timestamp last_used = 2; +} + // SetQueryCheckpointScheduleLog records a query checkpoint schedule change. message SetQueryCheckpointScheduleLog { string cron = 1; @@ -659,16 +667,31 @@ message LedgerLog { LedgerLogPayload data = 1; Timestamp date = 2; fixed64 id = 3; - // Volumes (account+asset) whose ephemeral state was purged (zero balance) - // by THIS log specifically. Subset of the proposal's purged universe — - // only volumes touched by the order that produced this log. Empty when - // the order did not contribute to any ephemeral purge. The index builder - // uses this to skip account->transaction mappings for the corresponding - // (account, asset) tuples without reading the audit zone. Carrying the - // asset dimension matters: a multi-asset account may have one asset - // purged while another stays kept; tagging the account as a whole would - // over-skip mappings for transactions that touched the kept asset. + // Volumes (account+asset) DRAINED to zero by THIS log — the entry had a + // pre-existing non-zero balance in Pebble and this log brought it back to + // zero, causing the volume to be evicted from the attribute store at + // commit. Purged is DISJOINT from ephemeral_volumes and new_kept_volumes. + // The index builder skips account->transaction mappings for + // purged ∪ ephemeral (both are evicted from Pebble). The usagebuilder + // subtracts len(purged_volumes) from VolumeCount — a draining eviction + // decreases the live cardinality by one. repeated TouchedVolume purged_volumes = 4; + // Volumes (account+asset) whose PERSISTENT entry was newly created by + // THIS log AND SURVIVED past commit. New + kept — disjoint from + // purged_volumes and ephemeral_volumes. The usagebuilder increments + // VolumeCount by len(new_kept_volumes) — a newly-persisted key raises + // the live cardinality by one. + repeated TouchedVolume new_kept_volumes = 5; + // Volumes (account+asset) that were both newly created AND purged by + // THIS log — pure ephemeral. Written to Pebble briefly then evicted at + // commit. Contributes +0 to VolumeCount (was zero, is zero after commit) + // and is tracked separately so: + // - the index builder can skip acct->tx mappings for them (via + // purged_volumes ∪ ephemeral_volumes); + // - the log payload does not duplicate ephemeral tuples in two lists + // (previous encoding carried them in both purged_volumes AND + // new_volumes, doubling bytes on ephemeral-heavy workloads). + repeated TouchedVolume ephemeral_volumes = 6; } // TouchedVolume identifies a (ledger-local) volume cell — an account paired @@ -1672,7 +1695,6 @@ message PreparedQueryCursor { message LedgerStats { fixed64 transaction_count = 1; fixed64 volume_count = 2; - fixed64 metadata_count = 3; fixed64 reference_count = 4; fixed64 posting_count = 5; fixed64 ephemeral_evicted_count = 6; diff --git a/misc/proto/raft_cmd.proto b/misc/proto/raft_cmd.proto index 2e22b46405..83bda39b78 100644 --- a/misc/proto/raft_cmd.proto +++ b/misc/proto/raft_cmd.proto @@ -730,14 +730,19 @@ message CreatedLogOrReference { message LedgerBoundaries { fixed64 next_transaction_id = 1; fixed64 next_log_id = 2; - fixed64 volume_count = 3; - fixed64 metadata_count = 4; - fixed64 reference_count = 5; - fixed64 posting_count = 6; - fixed64 ephemeral_evicted_count = 7; - fixed64 transient_used_count = 8; - fixed64 revert_count = 9; - fixed64 numscript_execution_count = 10; + + // Fields 3-10 held per-ledger counters (volume_count, metadata_count, + // reference_count, posting_count, ephemeral_evicted_count, + // transient_used_count, revert_count, numscript_execution_count) that + // migrated to the usagestore projection (EN-1420 / EN-1422). They are + // reserved — never reuse these tags: the vtprotobuf unmarshaller retains + // unknown-field bytes and re-emits them on MarshalVT, so an old persisted + // Pebble record carrying e.g. volume_count at tag 3 would be mis-decoded + // as whatever new field claimed tag 3. + reserved 3, 4, 5, 6, 7, 8, 9, 10; + reserved "volume_count", "metadata_count", "reference_count", + "posting_count", "ephemeral_evicted_count", "transient_used_count", + "revert_count", "numscript_execution_count"; // Highest source (v2) log ID already applied to this mirror ledger. Gates // idempotent replay: a MirrorIngest whose v2LogId is <= this value is a // deterministic no-op on the FSM apply path (see processMirrorIngest). diff --git a/openapi.yml b/openapi.yml index 1a9bd47a2b..6c4af6a01d 100644 --- a/openapi.yml +++ b/openapi.yml @@ -288,7 +288,16 @@ paths: /v3/{ledgerName}/stats: get: summary: Get ledger statistics - description: Returns aggregate statistics (account count, transaction count) for a ledger. Requires `ledger:read` scope. + description: >- + Returns aggregate usage statistics (transaction, volume, reference, posting, log, revert + and Numscript-execution counts, plus ephemeral-evicted and transient-used volume tallies) + for a ledger. Requires `ledger:read` scope. + Note: for checkpoint-scoped (historical) reads, only `transactionCount` and `logCount` are + checkpoint-consistent; the usage-derived counters (`postingCount`, `revertCount`, + `numscriptExecutionCount`, `referenceCount`, `ephemeralEvictedCount`, `transientUsedCount`, + `volumeCount`) are sourced from the live usagestore projection, which is not checkpoint-aware, + and are returned as `0` at a checkpoint rather than a live value — treat `0` on a checkpoint + read as "not available at this checkpoint". operationId: getLedgerStats tags: - Ledgers @@ -1689,6 +1698,50 @@ paths: '405': $ref: '#/components/responses/MethodNotAllowed' + /v3/{ledgerName}/numscripts/{name}/usage: + get: + summary: Get template usage + description: | + Returns the invocation counter and last-used timestamp for a Numscript template. Values are + materialised asynchronously by the `usagebuilder` subsystem from the FSM audit chain — expect + up to one usagebuilder tick interval (~100 ms) of lag behind the live FSM. A never-invoked + template returns a zero-valued response (not 404), so clients handle "never used" uniformly. + + On existing ledgers whose audit chain has been partially archived to cold storage, only + invocations still reachable in Pebble are counted. + operationId: getNumscriptUsage + tags: + - Numscript Library + parameters: + - $ref: '#/components/parameters/LedgerName' + - name: name + in: path + required: true + schema: + type: string + description: Name of the numscript template + responses: + '200': + description: Template usage retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/GetTemplateUsageResponse' + '400': + $ref: '#/components/responses/BadRequest' + '404': + $ref: '#/components/responses/NotFound' + '503': + $ref: '#/components/responses/ServiceUnavailable' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '405': + $ref: '#/components/responses/MethodNotAllowed' + /v3/{ledgerName}/bulk: post: summary: Bulk operations @@ -3619,19 +3672,61 @@ components: LedgerStats: type: object required: - - accountCount - transactionCount + - volumeCount + - referenceCount + - postingCount + - logCount + - ephemeralEvictedCount + - transientUsedCount + - revertCount + - numscriptExecutionCount properties: - accountCount: + transactionCount: type: integer format: uint64 minimum: 0 - description: Number of accounts in the ledger - transactionCount: + description: Number of transactions in the ledger + volumeCount: type: integer format: uint64 minimum: 0 - description: Number of transactions in the ledger + description: Number of persisted (account, asset, color) volume rows + referenceCount: + type: integer + format: uint64 + minimum: 0 + description: Number of transaction references registered in the ledger + postingCount: + type: integer + format: uint64 + minimum: 0 + description: Total number of postings across all transactions + logCount: + type: integer + format: uint64 + minimum: 0 + description: Number of log entries in the ledger + ephemeralEvictedCount: + type: integer + format: uint64 + minimum: 0 + description: Number of ephemeral/draining volumes evicted from storage at commit + transientUsedCount: + type: integer + format: uint64 + minimum: 0 + description: Number of transient volumes used across proposals + revertCount: + type: integer + format: uint64 + minimum: 0 + description: Number of reverted transactions in the ledger + numscriptExecutionCount: + type: integer + format: uint64 + minimum: 0 + description: Number of Numscript executions in the ledger Account: type: object @@ -4639,6 +4734,33 @@ components: description: List of all numscripts nullable: true + TemplateUsage: + type: object + required: + - count + properties: + count: + type: integer + format: int64 + minimum: 0 + description: | + Number of times the template has been invoked. `0` means never invoked (or the + usagebuilder has not yet caught up to any invocation on this replica). + lastUsed: + type: string + format: date-time + nullable: true + description: | + Timestamp of the most recent invocation (ISO 8601). Absent when `count` is 0. + + GetTemplateUsageResponse: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/TemplateUsage' + ChartOfAccounts: type: object description: A suggested chart of accounts based on account analysis diff --git a/pkg/actions/read.go b/pkg/actions/read.go index 4ce4f526a9..c2eae90c7d 100644 --- a/pkg/actions/read.go +++ b/pkg/actions/read.go @@ -313,6 +313,17 @@ func GetLedgerStats(ctx context.Context, client servicepb.BucketServiceClient, l }) } +// GetTemplateUsage retrieves the invocation counter and last-used timestamp +// for a Numscript template. The usagebuilder folds the counter asynchronously, +// so callers asserting on a freshly-invoked template must poll (Gomega +// Eventually / require.Eventually) rather than assume immediate visibility. +func GetTemplateUsage(ctx context.Context, client servicepb.BucketServiceClient, ledger, name string) (*commonpb.TemplateUsage, error) { + return client.GetTemplateUsage(ctx, &servicepb.GetTemplateUsageRequest{ + Ledger: ledger, + Name: name, + }) +} + // GetNumscript retrieves a numscript by name and optional version ("" = latest). func GetNumscript(ctx context.Context, client servicepb.BucketServiceClient, ledger, name, version string) (*commonpb.NumscriptInfo, error) { return client.GetNumscript(ctx, &servicepb.GetNumscriptRequest{ diff --git a/tests/e2e/business/numscript_usage_test.go b/tests/e2e/business/numscript_usage_test.go new file mode 100644 index 0000000000..7ab64a75f0 --- /dev/null +++ b/tests/e2e/business/numscript_usage_test.go @@ -0,0 +1,102 @@ +//go:build e2e + +package business + +import ( + "time" + + "github.com/formancehq/ledger/v3/pkg/actions" + + "github.com/formancehq/ledger/v3/internal/proto/servicepb" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var _ = Describe("GetTemplateUsage", Ordered, func() { + + Context("When a template is invoked via a script reference", Ordered, func() { + const ( + ledgerName = "template-usage-ledger" + templateName = "payout" + ) + + const payoutScript = ` +vars { + account $destination + monetary $amount +} + +send $amount ( + source = @world + destination = $destination +) +` + + BeforeAll(func() { + // Create the ledger and register the template in the numscript library. + _, err := sharedClient.Apply(sharedCtx, servicepb.UnsignedApplyRequest("", + actions.CreateLedgerAction(ledgerName, nil), + actions.SaveNumscriptWithVersionAction(ledgerName, templateName, payoutScript, "1.0.0"))) + Expect(err).To(Succeed()) + }) + + It("Should start at zero before any invocation", func() { + usage, err := actions.GetTemplateUsage(sharedCtx, sharedClient, ledgerName, templateName) + Expect(err).To(Succeed()) + Expect(usage.GetCount()).To(BeZero()) + Expect(usage.GetLastUsed()).To(BeNil(), "a never-invoked template has no lastUsed") + }) + + It("Should increment count and set lastUsed after a real invocation", func() { + // Invoke the template twice via script-reference transactions. + for i := 0; i < 2; i++ { + _, err := sharedClient.Apply(sharedCtx, servicepb.UnsignedApplyRequest("", + actions.CreateScriptRefTransactionAction(ledgerName, templateName, "1.0.0", map[string]string{ + "destination": "users:alice", + "amount": "USD/2 100", + }, nil))) + Expect(err).To(Succeed()) + } + + // The usagebuilder folds the counter asynchronously (one background + // tick behind the FSM), so poll rather than assume immediate + // visibility. Never time.Sleep. + Eventually(func(g Gomega) { + usage, err := actions.GetTemplateUsage(sharedCtx, sharedClient, ledgerName, templateName) + g.Expect(err).To(Succeed()) + g.Expect(usage.GetCount()).To(Equal(uint64(2)), "count must reflect both invocations") + g.Expect(usage.GetLastUsed()).NotTo(BeNil(), "lastUsed must be populated after invocation") + g.Expect(usage.GetLastUsed().GetData()).NotTo(BeZero(), "lastUsed timestamp must be a real value") + }).Within(30 * time.Second).WithPolling(200 * time.Millisecond).Should(Succeed()) + }) + }) + + Context("Unknown-template / unknown-ledger contract", func() { + const ledgerName = "template-usage-contract-ledger" + + BeforeAll(func() { + _, err := sharedClient.Apply(sharedCtx, servicepb.UnsignedApplyRequest("", actions.CreateLedgerAction(ledgerName, nil))) + Expect(err).To(Succeed()) + }) + + It("Should return zero (not NotFound) for an unknown template on an existing ledger", func() { + // The endpoint's contract is zero-valued, not 404: clients treat a + // never-seen template uniformly as count 0. Only an unknown ledger 404s. + usage, err := actions.GetTemplateUsage(sharedCtx, sharedClient, ledgerName, "never-registered") + Expect(err).To(Succeed()) + Expect(usage.GetCount()).To(BeZero()) + Expect(usage.GetLastUsed()).To(BeNil()) + }) + + It("Should return NotFound for an unknown ledger", func() { + _, err := actions.GetTemplateUsage(sharedCtx, sharedClient, "non-existent-ledger", "payout") + Expect(err).To(HaveOccurred()) + + st, ok := status.FromError(err) + Expect(ok).To(BeTrue()) + Expect(st.Code()).To(Equal(codes.NotFound)) + }) + }) +}) diff --git a/tests/e2e/business/stats_test.go b/tests/e2e/business/stats_test.go index 758df4d58b..5032c380a7 100644 --- a/tests/e2e/business/stats_test.go +++ b/tests/e2e/business/stats_test.go @@ -32,7 +32,6 @@ var _ = Describe("GetLedgerStats", Ordered, func() { Expect(resp.TransactionCount).To(BeZero()) Expect(resp.PostingCount).To(BeZero()) Expect(resp.VolumeCount).To(BeZero()) - Expect(resp.MetadataCount).To(BeZero()) Expect(resp.ReferenceCount).To(BeZero()) }) }) @@ -69,7 +68,6 @@ var _ = Describe("GetLedgerStats", Ordered, func() { g.Expect(resp.PostingCount).To(Equal(uint64(3))) // world/USD + bank:main/USD + bank:fees/USD + users:alice/USD = 4 g.Expect(resp.VolumeCount).To(Equal(uint64(4))) - g.Expect(resp.MetadataCount).To(BeZero()) g.Expect(resp.ReferenceCount).To(BeZero()) }).Should(Succeed()) }) diff --git a/tests/e2e/business/transient_accounts_test.go b/tests/e2e/business/transient_accounts_test.go index 64e591e219..29774e99b9 100644 --- a/tests/e2e/business/transient_accounts_test.go +++ b/tests/e2e/business/transient_accounts_test.go @@ -153,8 +153,11 @@ var _ = Describe("TransientAccounts", Ordered, func() { g.Expect(logs).NotTo(BeEmpty()) // At least one of the two logs in the batch must carry - // {Account: clearing:ep1, Asset: USD} in its purged_volumes. - // The index builder uses this tuple to skip the matching + // {Account: clearing:ep1, Asset: USD} in its eviction lists. + // Pure ephemeral tuples (was zero, briefly touched, is zero) + // live in LedgerLog.EphemeralVolumes; draining evictions + // (was non-zero, back to zero) live in LedgerLog.PurgedVolumes. + // The index builder unions both to skip the matching // account->transaction mapping while preserving any other // asset's mappings on the same account. var purged []touched @@ -167,10 +170,13 @@ var _ = Describe("TransientAccounts", Ordered, func() { for _, v := range ll.GetPurgedVolumes() { purged = append(purged, touched{Account: v.GetAccount(), Asset: v.GetAsset()}) } + for _, v := range ll.GetEphemeralVolumes() { + purged = append(purged, touched{Account: v.GetAccount(), Asset: v.GetAsset()}) + } } } g.Expect(purged).To(ContainElement(touched{Account: "clearing:ep1", Asset: "USD"}), - "at least one log in the batch should list (clearing:ep1, USD) as purged") + "at least one log in the batch should list (clearing:ep1, USD) as evicted") }).Within(5 * time.Second).ProbeEvery(200 * time.Millisecond).Should(Succeed()) }) }) diff --git a/tests/e2e/cluster/restore_reversion_test.go b/tests/e2e/cluster/restore_reversion_test.go index b72748936a..2f5c04aa95 100644 --- a/tests/e2e/cluster/restore_reversion_test.go +++ b/tests/e2e/cluster/restore_reversion_test.go @@ -79,7 +79,7 @@ var _ = Describe("Restore reversion bitset", Ordered, func() { acct, err := actions.GetAccount(ctx, client, ledgerName, account) Expect(err).To(Succeed()) - vol := acct.GetVolumes()["USD"] + vol := acct.FindVolume("USD", "") Expect(vol).ToNot(BeNil(), "%s: %s USD volumes missing", phase, account) Expect(vol.GetInput()).To(Equal("600"), "%s: %s USD input", phase, account) Expect(vol.GetOutput()).To(Equal("100"), "%s: %s USD output", phase, account) diff --git a/tests/e2e/cluster/restore_test.go b/tests/e2e/cluster/restore_test.go index de19c66227..2b13bd3fc4 100644 --- a/tests/e2e/cluster/restore_test.go +++ b/tests/e2e/cluster/restore_test.go @@ -783,7 +783,6 @@ var _ = Describe("Restore", Ordered, func() { Expect(stats.GetLogCount()).To(Equal(uint64(1))) Expect(stats.GetPostingCount()).To(Equal(uint64(1))) Expect(stats.GetVolumeCount()).To(Equal(uint64(2)), "world + founder") - Expect(stats.GetMetadataCount()).To(Equal(uint64(0))) Expect(stats.GetRevertCount()).To(Equal(uint64(0))) Expect(stats.GetReferenceCount()).To(Equal(uint64(1)), "the funding tx carried a reference") }) @@ -896,7 +895,7 @@ var _ = Describe("Restore", Ordered, func() { Eventually(func(g Gomega) { resp, err := joinerClient.GetAccount(staleCtx, &servicepb.GetAccountRequest{Ledger: ledgerName, Address: "join-fence"}) g.Expect(err).To(Succeed()) - g.Expect(resp.GetVolumes()["USD"].GetInput()).To(Equal("42")) + g.Expect(resp.FindVolume("USD", "").GetInput()).To(Equal("42")) }).Within(60*time.Second).ProbeEvery(500*time.Millisecond).Should(Succeed(), "learner never caught up on the post-restore raft log") @@ -905,15 +904,15 @@ var _ = Describe("Restore", Ordered, func() { // learner iff the restored store itself was transferred. aliceResp, err := joinerClient.GetAccount(staleCtx, &servicepb.GetAccountRequest{Ledger: ledgerName, Address: "alice"}) Expect(err).To(Succeed()) - Expect(aliceResp.GetVolumes()).To(HaveKey("USD"), + Expect(aliceResp.FindVolume("USD", "")).ToNot(BeNil(), "learner caught up by log replay alone: the restored state never reached it") - Expect(aliceResp.GetVolumes()["USD"].GetInput()).To(Equal("3000")) + Expect(aliceResp.FindVolume("USD", "").GetInput()).To(Equal("3000")) treasuryResp, err := joinerClient.GetAccount(staleCtx, &servicepb.GetAccountRequest{Ledger: ledger2, Address: "treasury"}) Expect(err).To(Succeed()) - Expect(treasuryResp.GetVolumes()).To(HaveKey("EUR"), + Expect(treasuryResp.FindVolume("EUR", "")).ToNot(BeNil(), "ledger untouched since the restore must still reach the learner") - Expect(treasuryResp.GetVolumes()["EUR"].GetInput()).To(Equal("50000")) + Expect(treasuryResp.FindVolume("EUR", "").GetInput()).To(Equal("50000")) }) }) })