Keeping the device in sync
Why the device's copy of the private balance needs syncing, what a sync does, and when to run one.
A wallet app reads a token balance straight from an RPC node. A private balance cannot be read that way. Only your user's keys can find their notes, so the device finds them and keeps a copy.
A sync brings that copy up to date.
What a sync does
syncNoteStore runs in rounds until it has read everything new:
sequenceDiagram participant App as Your app participant SDK participant Nimbus as Nimbus indexer and Solana participant Store as This device App->>SDK: syncNoteStore loop until caught up SDK->>Nimbus: the next page: a sealed file, or the newest rows SDK->>SDK: try your user's keys on each new note SDK->>Store: save their notes and spends end SDK->>Store: release payments a closed tab left SDK-->>App: ingested
In each round, the SDK reads one page of new notes, spends and records for each pool. It keeps the notes your user's keys open. It marks their notes as spent once Solana shows them spent.
Last, it frees the notes of any payment whose tab closed before sending it.
A sync downloads every new note, not just your user's. So it never tells the indexer which notes are theirs.
Where the pages come from
The indexer seals older pool activity into files of 1000 rows each. A sealed file never changes, so a CDN serves it from the edge.
The SDK reads each stream from those files first. It reads only the newest rows, past the last sealed file, from the indexer's data API. A file is the same for every user, so fetching it shows nothing about yours.
The SDK checks each file against the indexer's manifest before it takes a row. It reads a missing or faulty file from the data API instead. Either way, the device ends up with the same copy.
When the SDK syncs for you
Every deposit, Private Send and withdrawal syncs first, by default. A followed Private Send or
withdrawal syncs again once it lands. Pass sync: false to a payment only if you synced just before.
When your app should sync
- On load, once the session is open, before you show a balance.
- When the tab regains focus, since your user may have been paid meanwhile.
- On an interval while the page is visible, to pick up incoming payments.
Every tab shares one copy. A sync in one tab updates the balance for all of them.
Long syncs
A device that has been away a while, or a new device, has a lot to read. Most of it comes from sealed files on the CDN, which is the fast part. Three options keep a sync in hand:
maxRoundsstops after that many rounds. The result'scaughtUpsays whether it finished.signalstops it between rounds when anAbortSignalfires.onProgresshears about each round, with the slot reached.
The next sync picks up where the last one stopped.
What this means for your app
- Show "updating" while a sync runs. Show the last balance meanwhile, not a spinner in its place.
- Expect
unregisteredbefore registration. Until your user registers, there is nothing to read.
Last updated