Skip to content

feat: sync operator app skeleton - #16

Open
sadiq1971 wants to merge 3 commits into
feat/dedicated-syncfrom
feat/sync-operator-node
Open

feat: sync operator app skeleton#16
sadiq1971 wants to merge 3 commits into
feat/dedicated-syncfrom
feat/sync-operator-node

Conversation

@sadiq1971

@sadiq1971 sadiq1971 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

What this does

  • New apps/syncoperator module, modelled on apps/splitwell: config, store, automation host, metrics, bootstrap, health.
  • SyncOperatorStore ingests MemberTraffic where this operator is the observer, and exposes getTotalPurchasedMemberTraffic(member) off an indexed column. The query itself is now shared with DbSvDsoStore via MemberTrafficQueries.
  • SyncOperatorApp connects to Scan and its own sequencer, and takes its synchronizer id from that sequencer rather than from config, so there is nothing to keep in sync at bootstrap.
  • New sync_operator_acs_store table and two SpliceDbLockCounters.

How it's verified

compile, Test/compile and scalafmtCheckAll pass across the tree.

SyncOperatorStoreTest covers the filter: sums across purchases, keeps members apart, and ignores purchases for another synchronizer, another operator, no operator, and a non-zero migration id. 7/7 pass locally against Postgres, and it is now listed in test-full-class-names-non-integration.log so CI runs it.

Not covered: that the store survives a decentralized-synchronizer migration without dropping records. That is part of the acceptance for canton-network#35 and needs a fixture that changes the migration id mid-test.

Tracked in

Implements P2-E5.2. Unblocks P2-E5.3, which also needs P2-E5.1 (#15 here). Relies on the migration-id policy in P2-E1.5.

@sadiq1971 sadiq1971 changed the title feat: sync operator app skeleton (Scala) feat: sync operator app skeleton Aug 19, 2026
@sadiq1971
sadiq1971 force-pushed the feat/sync-operator-node branch from dea0d60 to bf74782 Compare August 19, 2026 22:46
@sadiq1971 sadiq1971 self-assigned this Aug 20, 2026

@moritzkiefer-da moritzkiefer-da left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, this looks mostly reasonable. I left a few comments. I would also suggest adding an integration test directly in this PR that tests that you can at least start and stop the app successfully.

Adds the apps/syncoperator module: config, store, automation host and
health, ingesting the MemberTraffic purchases the operator observes for
its own synchronizer and holding the sequencer admin connection the
reconciliation will grant on.

Ingestion is deliberately not filtered by the node's own migration id,
since a registered synchronizer is pinned to migration id 0.

Signed-off-by: sadiq1971 <sadiqurr8@gmail.com>
Drop the synchronizer id and sequencer list from the config and take the
synchronizer id from the sequencer instead. Share the MemberTraffic sum query
with the DSO store.

Also fixes the store test, which never ran: the operator was missing as an
observer on the ingested contracts, and the suite was absent from the
non-integration test list.

Signed-off-by: sadiq1971 <sadiqurr8@gmail.com>
@sadiq1971
sadiq1971 force-pushed the feat/sync-operator-node branch from 681ff2f to 75cbcb9 Compare August 25, 2026 19:48
Add package_name to the sync_operator_acs_store index, matching the shape V049
rebuilt the dso and scan indexes into; the shared MemberTraffic query filters
on it.

Drop trafficBalanceReconciliationDelay, which nothing reads, and the scalapb
runtime deps, which the module has no generated code for. Add the module to
clean-splice.

Signed-off-by: sadiq1971 <sadiqurr8@gmail.com>
@sadiq1971

Copy link
Copy Markdown
Collaborator Author

thanks, this looks mostly reasonable. I left a few comments. I would also suggest adding an integration test directly in this PR that tests that you can at least start and stop the app successfully.

I have addressed the comments. For integration test I have added it on PR #17 to keep this PR clean and less changes.

@moritzkiefer-da moritzkiefer-da left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

) extends SpliceAppAutomationService(
automationConfig,
clock,
// Nothing registered here depends on domain time yet.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Nothing registered here depends on domain time yet.
// Nothing registered here depends on domain time.

}
// Only used to partition the store's ingestion offsets; purchases are ingested regardless
// of it, see SyncOperatorStore.contractFilter.
domainMigrationId <- appInitStep(s"Resolving domain migration id") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why you need this here, there is no migration id for dedicated synchronizers/it's always zero?

config.automation.ingestion,
config.parameters.defaultLimit,
)
globalSynchronizerId <- appInitStep("Get the decentralized synchronizer id") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
globalSynchronizerId <- appInitStep("Get the decentralized synchronizer id") {
globalSynchronizerId <- appInitStep("Get the global synchronizer id") {

metrics.grpcClientMetrics,
retryProvider,
)
synchronizerId <- appInitStep("Get the synchronizer id from the sequencer") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably a good idea to log the synchronizer id. If you use retryProvider.getValue it does that for you and you get retries for this

Comment thread build.sbt
),
)

lazy val `apps-syncoperator` =

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add it to the list of things that cleaned out by splice-clean

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants