Sync Round Management
Description
Section titled “Description”This example demonstrates how to manage the sync round using:
- syncRound() - Get the minimum sync round the ledger will cache
- setSyncRound(round) - Set the minimum sync round
- unsetSyncRound() - Unset/reset the sync round What is the sync round? The sync round is a configuration that controls the minimum round the node will keep data for. When set, the node will:
- Only keep block data from this round onwards
- Allow old block data to be deleted/pruned
- Reduce storage requirements for archival data This is useful for:
- Nodes that only need recent data (not full archival history)
- Indexers that only need data from a specific point forward
- Applications that don’t need ancient historical data Key concepts:
- syncRound() returns GetSyncRoundResponse with { round: bigint }
- setSyncRound(round) sets the minimum round to keep
- unsetSyncRound() removes the sync round restriction
- Historical data below the sync round may be unavailable
Prerequisites
Section titled “Prerequisites”- LocalNet running (via
algokit localnet start) - Note: On some nodes, these endpoints may require admin privileges or return errors if the feature is not supported.
Run This Example
Section titled “Run This Example”From the repository root:
cd examplesnpm run example algod_client/19-sync-round.ts/** * Example: Sync Round Management * * This example demonstrates how to manage the sync round using: * - syncRound() - Get the minimum sync round the ledger will cache * - setSyncRound(round) - Set the minimum sync round * - unsetSyncRound() - Unset/reset the sync round * * What is the sync round? * The sync round is a configuration that controls the minimum round the node * will keep data for. When set, the node will: * - Only keep block data from this round onwards * - Allow old block data to be deleted/pruned * - Reduce storage requirements for archival data * * This is useful for: * - Nodes that only need recent data (not full archival history) * - Indexers that only need data from a specific point forward * - Applications that don't need ancient historical data * * Key concepts: * - syncRound() returns GetSyncRoundResponse with { round: bigint } * - setSyncRound(round) sets the minimum round to keep * - unsetSyncRound() removes the sync round restriction * - Historical data below the sync round may be unavailable * * Prerequisites: * - LocalNet running (via `algokit localnet start`) * * Note: On some nodes, these endpoints may require admin privileges * or return errors if the feature is not supported. */
import type { GetSyncRoundResponse } from '@algorandfoundation/algokit-utils/algod-client'import { createAlgodClient, printError, printHeader, printInfo, printStep, printSuccess,} from '../shared/utils.js'
async function main() { printHeader('Sync Round Management Example')
// Create algod client const algod = createAlgodClient()
// ========================================================================= // Step 1: Get the current node status to understand the blockchain state // ========================================================================= printStep(1, 'Getting current node status')
const status = await algod.status() const currentRound = status.lastRound printSuccess(`Connected to node`) printInfo(` Current round: ${currentRound}`) printInfo(` Catchup time: ${status.catchupTime} ns`) printInfo('')
// ========================================================================= // Step 2: Get the current sync round (if any) // ========================================================================= printStep(2, 'Getting current sync round')
printInfo('Calling syncRound() to get the minimum sync round...')
try { const syncRoundResponse = await algod.syncRound() displaySyncRoundResponse(syncRoundResponse)
printInfo(`The node will keep data from round ${syncRoundResponse.round} onwards`) printInfo('Data below this round may be pruned or unavailable') } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error)
// Check for various error scenarios if (errorMessage.includes('404') || errorMessage.includes('not found') || errorMessage.includes('Not Found')) { printInfo('Sync round is not set - node will keep all historical data') printInfo('This is the default behavior for archival nodes') } else if (errorMessage.includes('501') || errorMessage.includes('not implemented')) { printError('Sync round endpoints are not supported on this node') printInfo('These endpoints may require specific node configuration') } else if (errorMessage.includes('403') || errorMessage.includes('forbidden') || errorMessage.includes('Forbidden')) { printError('Access denied - admin privileges may be required') printInfo('Some nodes restrict sync round management to admin tokens') } else { // Display error but continue with the example printError(`Error getting sync round: ${errorMessage}`) } } printInfo('')
// ========================================================================= // Step 3: Set a sync round // ========================================================================= printStep(3, 'Setting a sync round')
// We'll set the sync round to a recent round to demonstrate the API // In practice, you'd set this to the oldest round you need data for const targetSyncRound = currentRound - 10n > 0n ? currentRound - 10n : 1n printInfo(`Attempting to set sync round to ${targetSyncRound}...`) printInfo('This tells the node to keep data from this round onwards')
try { await algod.setSyncRound(targetSyncRound) printSuccess(`Sync round set to ${targetSyncRound}`)
// Verify the sync round was set try { const verifyResponse = await algod.syncRound() printInfo(`Verified: sync round is now ${verifyResponse.round}`) } catch { printInfo('Could not verify - syncRound() may not be available') } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error)
if (errorMessage.includes('404') || errorMessage.includes('not found')) { printError('setSyncRound endpoint not found') printInfo('This endpoint may not be available on this node configuration') } else if (errorMessage.includes('501') || errorMessage.includes('not implemented')) { printError('setSyncRound is not implemented on this node') printInfo('Sync round management may require specific node features to be enabled') } else if (errorMessage.includes('403') || errorMessage.includes('forbidden')) { printError('Access denied when setting sync round') printInfo('Admin token may be required to modify sync round') } else if (errorMessage.includes('400') || errorMessage.includes('bad request')) { printError('Invalid sync round value') printInfo('The sync round must be a valid round number') } else { printError(`Failed to set sync round: ${errorMessage}`) } } printInfo('')
// ========================================================================= // Step 4: Explain the impact of sync round on data availability // ========================================================================= printStep(4, 'Understanding sync round impact on data availability')
printInfo('When a sync round is set:') printInfo('') printInfo('1. Block Data Access:') printInfo(' - Blocks at or after the sync round: Available') printInfo(' - Blocks before the sync round: May be unavailable (pruned)') printInfo('') printInfo('2. Account Information:') printInfo(' - Current state: Always available') printInfo(' - Historical state at old rounds: May be unavailable') printInfo('') printInfo('3. Transaction History:') printInfo(' - Transactions in recent blocks: Available') printInfo(' - Transactions in pruned blocks: Not available') printInfo('') printInfo('4. State Proofs & Deltas:') printInfo(' - Only available for rounds at or after sync round') printInfo('')
// Demonstrate that recent data is accessible printInfo('Verifying recent block data is accessible...') try { const block = await algod.block(currentRound) printSuccess(`Block ${currentRound} is accessible (timestamp: ${block.block.header.timestamp})`) } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error) printError(`Could not access block ${currentRound}: ${errorMessage}`) } printInfo('')
// ========================================================================= // Step 5: Demonstrate unsetSyncRound // ========================================================================= printStep(5, 'Unsetting the sync round')
printInfo('Calling unsetSyncRound() to remove the sync round restriction...') printInfo('After unsetting, the node will keep all data (archival mode)')
try { await algod.unsetSyncRound() printSuccess('Sync round has been unset')
// Verify it was unset try { const checkResponse = await algod.syncRound() // If this succeeds, a sync round is still set printInfo(`Note: syncRound still returns ${checkResponse.round}`) printInfo('On some nodes, unset may set a default value rather than fully removing it') } catch (checkError) { const checkMessage = checkError instanceof Error ? checkError.message : String(checkError) if (checkMessage.includes('404') || checkMessage.includes('not found')) { printSuccess('Confirmed: sync round is now unset (404 response)') printInfo('Node is in archival mode - keeping all historical data') } else { printInfo(`Sync round status unclear: ${checkMessage}`) } } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error)
if (errorMessage.includes('404') || errorMessage.includes('not found')) { printInfo('unsetSyncRound returned 404 - sync round may already be unset') } else if (errorMessage.includes('501') || errorMessage.includes('not implemented')) { printError('unsetSyncRound is not implemented on this node') } else if (errorMessage.includes('403') || errorMessage.includes('forbidden')) { printError('Access denied when unsetting sync round') printInfo('Admin privileges may be required') } else { printError(`Failed to unset sync round: ${errorMessage}`) } } printInfo('')
// ========================================================================= // Step 6: Best practices for sync round management // ========================================================================= printStep(6, 'Best practices and use cases')
printInfo('When to use sync round:') printInfo('') printInfo('1. Non-Archival Nodes:') printInfo(' - Set sync round to reduce storage requirements') printInfo(' - Only keep data needed for current operations') printInfo('') printInfo('2. Indexer Deployment:') printInfo(' - Set sync round to the indexer\'s starting point') printInfo(' - Prevents the node from being queried for data it doesn\'t need') printInfo('') printInfo('3. Fresh Sync from Snapshot:') printInfo(' - After restoring from a snapshot, set sync round to snapshot round') printInfo(' - Tells the node not to try fetching older data') printInfo('') printInfo('When NOT to use sync round:') printInfo('') printInfo('1. Archival Nodes:') printInfo(' - Don\'t set sync round if you need full history') printInfo(' - Archival nodes should keep all data') printInfo('') printInfo('2. Block Explorers:') printInfo(' - Need historical data for user queries') printInfo(' - Should maintain full history') printInfo('') printInfo('3. Audit/Compliance:') printInfo(' - Regulatory requirements may mandate full history') printInfo('')
// ========================================================================= // Summary // ========================================================================= printHeader('Summary')
printInfo('Sync Round Management - Key Points:') printInfo('') printInfo('1. What It Does:') printInfo(' - Controls the minimum round the node keeps data for') printInfo(' - Allows pruning of old block data') printInfo(' - Reduces storage requirements for non-archival nodes') printInfo('') printInfo('2. API Methods:') printInfo(' syncRound(): Promise<GetSyncRoundResponse>') printInfo(' - Returns { round: bigint } with the minimum sync round') printInfo(' - Returns 404 if no sync round is set (archival mode)') printInfo('') printInfo(' setSyncRound(round: number | bigint): Promise<void>') printInfo(' - Sets the minimum sync round') printInfo(' - Data below this round may be pruned') printInfo('') printInfo(' unsetSyncRound(): Promise<void>') printInfo(' - Removes the sync round restriction') printInfo(' - Returns node to archival mode') printInfo('') printInfo('3. GetSyncRoundResponse:') printInfo(' {') printInfo(' round: bigint // Minimum sync round') printInfo(' }') printInfo('') printInfo('4. Data Availability Impact:') printInfo(' - Blocks before sync round: May be unavailable') printInfo(' - Account history at old rounds: May be unavailable') printInfo(' - Current state: Always available') printInfo(' - Recent transactions: Available') printInfo('') printInfo('5. Error Scenarios:') printInfo(' - 404: Sync round not set (archival mode)') printInfo(' - 403: Admin privileges required') printInfo(' - 501: Feature not implemented on this node') printInfo('') printInfo('6. Best Practices:') printInfo(' - Only set sync round if you don\'t need full history') printInfo(' - Consider storage vs. data availability tradeoffs') printInfo(' - Archival nodes should not set a sync round') printInfo(' - Document your sync round configuration')}
/** * Display the sync round response information */function displaySyncRoundResponse(response: GetSyncRoundResponse): void { printInfo(' GetSyncRoundResponse:') printInfo(` round: ${response.round}`) printInfo('')}
main().catch((error) => { console.error('Fatal error:', error) process.exit(1)})Other examples in Algod Client
Section titled “Other examples in Algod Client”- Node Health and Status
- Version and Genesis Information
- Ledger Supply Information
- Account Information
- Transaction Parameters
- Send and Confirm Transaction
- Pending Transactions
- Block Data
- Asset Information
- Application Information
- Application Boxes
- TEAL Compile and Disassemble
- Transaction Simulation
- Ledger State Deltas
- Transaction Proof
- Light Block Header Proof
- State Proof
- DevMode Timestamp Offset
- Sync Round Management