ChainSafe / ChainSafe/canton-extending-mainnet

[P2-E5.7] SyncOperatorStore pins its partition to migration 0 with no test at a non-zero generation

Open
#115 0 comments 0 reactions 0 assignees View on GitHub
area:scala-sv phase-2 ws1
Dominant language
Shell
Stars
0
Forks
0
Avg merge
22h 58m
Merged PRs (30d)
1

Description

`SyncOperatorApp` constructs the store with a hardcoded partition id rather than the resolved network value (`SyncOperatorApp.scala:119-127`):

```scala
store = SyncOperatorStore(
storeKey, storage, loggerFactory, retryProvider,
// MIGRATION_ID is frozen network-wide and logical synchronizer upgrades carry a serial id
// instead, so the store's partition never has to move.
0L,
...
)
```

The reasoning is sound for a dedicated synchronizer, which upgrades via LSU and never hard-migrates. It is also self-consistent: rows are tagged 0 and queries filter on 0.

What is untested is the interaction with the ledger the store actually reads. `MemberTraffic` lives on the global synchronizer, so the operator app ingests from a ledger whose generation can advance independently of this hardcoded 0. #60 named that risk directly when it rejected the same approach for other stores: "The store would claim generation 0 while reading a generation-3 ledger", specifically calling out `store_last_ingested_offsets` and backfilling, since ledger offsets reset at a hard migration.

`SyncOperatorStoreTest` defaults `migrationId = 0L` (`:43`) and never varies it, so nothing exercises this. That is precisely the hole #60's fourth acceptance criterion closed for `ScanStore` and `SvDsoStore`, both of which now test at `nextDomainMigrationId`.

Not a live bug. Every network today is at generation 0, and the ingestion filter is immune to the #60 mechanism because it pins `payload.migrationId == 0L` directly rather than comparing against `domainMigrationId` (`SyncOperatorStore.scala:100`).

**Acceptance criteria:**
- [ ] A `SyncOperatorStoreTest` case runs at a non-zero network generation and still ingests registered-sync purchases
- [ ] Decide and record whether the store partition should track the global synchronizer's generation or stay pinned, and why
- [ ] If it stays pinned, confirm what happens to `store_last_ingested_offsets` when the global synchronizer hard-migrates

**Key files:** `apps/syncoperator/src/main/scala/.../SyncOperatorApp.scala:119-127`, `apps/syncoperator/src/main/scala/.../store/SyncOperatorStore.scala:100`, `apps/syncoperator/src/test/scala/.../SyncOperatorStoreTest.scala:43`

**Related:** found while verifying #60 and #83 were complete. Both are; this is the residue neither covered.

**Epic:** ChainSafe/canton-extending-mainnet#68

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with SyncOperatorApp.scala:119-127 and SyncOperatorStore.scala:100, then run SyncOperatorStoreTest.scala with its migrationId varied from 0L. Compare the non-zero-generation coverage in ScanStoreTest and SvDsoStoreTest. Done means the test covers registered-sync purchases at a non-zero generation and the partition and store_last_ingested_offsets behavior is documented and justified.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.