SyncStateManager
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:
App starts
Get last processed ID:
getLastProcessedTransactionId(address)Subscribe from that ID:
subscribeToUnshieldedTransactions(address, lastId)Process updates
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)
}
}Functions
Clear all sync state (for all addresses).
Clear sync state for an address.
Get last processed transaction ID for an address.
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.
Observe last processed transaction ID for an address.
Save last processed transaction ID for an address.
Pin checkpoint as the chain-instance identity the caches for address were built against.