SyncStateManager

class SyncStateManager(context: Context)

Manages subscription sync state for resuming after app restarts.

Purpose:

  • Persist last processed transaction ID per address

  • Enable subscription resumption (don't replay all history on restart)

  • Track sync progress

Storage:

  • Uses DataStore (shared preferences alternative)

  • Key format: "last_tx_id_{address}"

  • Value: Last processed transaction ID (Int)

Resume Flow:

  1. App starts

  2. Get last processed ID: getLastProcessedTransactionId(address)

  3. Subscribe from that ID: subscribeToUnshieldedTransactions(address, lastId)

  4. Process updates

  5. Save progress: saveLastProcessedTransactionId(address, newId)

Example:

// On app start
val lastId = syncStateManager.getLastProcessedTransactionId(address)
// lastId = 42 (from previous session)

// Subscribe from last ID (skip already processed txs)
indexerClient.subscribeToUnshieldedTransactions(address, fromTransactionId = lastId)
.collect { update ->
utxoManager.processUpdate(update)

if (update is Progress) {
syncStateManager.saveLastProcessedTransactionId(address, update.highestTransactionId)
}
}

Constructors

Link copied to clipboard
constructor(context: Context)

Types

Link copied to clipboard
object Companion

Functions

Link copied to clipboard
suspend fun clearAllSyncState()

Clear all sync state (for all addresses).

Link copied to clipboard
suspend fun clearSyncState(address: String)

Clear sync state for an address.

Link copied to clipboard
suspend fun getLastProcessedTransactionId(address: String): Int?

Get last processed transaction ID for an address.

Link copied to clipboard

The CHECKPOINT block the persisted caches were built against — a per-chain-instance identity for detecting a chain RESET. It is a block ABOVE genesis (height + hash): a localnet booting from a fixed chain spec reproduces the same GENESIS hash across a reset, so genesis can't be the discriminator, but any higher block carries a per-instance timestamp and so a per-instance hash. com.midnight.kuira.core.indexer.sync.ChainResetGuard re-looks-up this height on each sync; a missing block (shorter fresh chain) or a changed hash means a reset.

Link copied to clipboard

Observe last processed transaction ID for an address.

Link copied to clipboard
suspend fun saveLastProcessedTransactionId(address: String, transactionId: Int)

Save last processed transaction ID for an address.

Link copied to clipboard
suspend fun setPinnedChainCheckpoint(address: String, checkpoint: ChainCheckpoint)

Pin checkpoint as the chain-instance identity the caches for address were built against.