Skip to main content

GetCheckpoint

Access Finalized Blockchain State#

The GetCheckpoint method retrieves checkpoint data from Sui's blockchain, providing access to finalized state snapshots that represent guaranteed points of consistency. Checkpoints bundle transactions into atomic units with validator signatures, making them essential for applications requiring verified finality and historical state reconstruction.

Overview#

Checkpoints are fundamental to Sui's consensus mechanism. Every ~0.5 seconds, the network creates a new checkpoint containing a batch of executed transactions. Once a checkpoint receives validator signatures exceeding the quorum threshold, it becomes immutable and represents an irrevocable point of finality. Applications use checkpoints to verify transaction inclusion, reconstruct historical state, and monitor network progression.

Why Checkpoints Matter#

  • Guaranteed Finality: Checkpoints mark irreversible blockchain state
  • Audit Trail: Complete record of all network state transitions
  • State Snapshots: Point-in-time views of the entire network
  • Validator Proof: Cryptographic signatures from consensus participants
  • Synchronization: Reference points for syncing blockchain state

Method Signature#

Service: sui.rpc.v2beta2.LedgerService Method: GetCheckpoint Type: Unary RPC (single request, single response)

Parameters#

ParameterTypeRequiredDescription
sequence_numberstringConditional*Checkpoint identifier by sequence number
digeststringConditional*Checkpoint identifier by digest hash
read_maskFieldMaskNoFields to include in response

*Either sequence_number OR digest must be provided (mutually exclusive).

Field Mask Options#

PathDescription
sequence_numberMonotonically increasing checkpoint identifier
digestCryptographic hash of checkpoint contents
network_total_transactionsCumulative transaction count
previous_digestPrevious checkpoint's digest (chain linking)
timestamp_msCheckpoint finalization timestamp
transactionsArray of transaction digests in checkpoint
end_of_epoch_dataEpoch transition data (epoch boundaries only)
epoch_rolling_gas_cost_summaryCumulative gas metrics

Response Structure#

message Checkpoint {
uint64 sequence_number = 1;
string digest = 2;
uint64 network_total_transactions = 3;
string previous_digest = 4;
uint64 timestamp_ms = 5;
repeated string transactions = 6;
EpochData end_of_epoch_data = 7;
GasCostSummary epoch_rolling_gas_cost_summary = 8;
}

Code Examples#

import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@groto/proto-loader';

const ENDPOINT = 'api-sui-mainnet-full.n.dwellir.com';
const API_TOKEN = 'your_api_token_here';

const packageDefinition = protoLoader.loadSync(
'./protos/ledger.proto',
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs: ['./protos']
}
);

const protoDescriptor = grpc.loadPackageDefinition(packageDefinition) as any;
const credentials = grpc.credentials.createSsl();
const client = new protoDescriptor.sui.rpc.v2beta2.LedgerService(
ENDPOINT,
credentials
);

const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_TOKEN);

// Get checkpoint by sequence number
async function getCheckpointBySequence(sequence: string): Promise<any> {
return new Promise((resolve, reject) => {
const request = {
sequence_number: sequence,
read_mask: {
paths: [
'sequence_number',
'digest',
'timestamp_ms',
'network_total_transactions',
'transactions',
'previous_digest'
]
}
};

client.GetCheckpoint(request, metadata, (error: any, response: any) => {
if (error) {
console.error('GetCheckpoint error:', error.message);
reject(error);
return;
}

resolve(response);
});
});
}

// Get checkpoint by digest
async function getCheckpointByDigest(digest: string): Promise<any> {
return new Promise((resolve, reject) => {
const request = {
digest: digest,
read_mask: {
paths: [
'sequence_number',
'digest',
'timestamp_ms',
'transactions'
]
}
};

client.GetCheckpoint(request, metadata, (error: any, response: any) => {
if (error) reject(error);
else resolve(response);
});
});
}

// Example: Verify transaction finality
async function verifyTransactionFinalized(
txDigest: string,
startSequence: string
): Promise<{ finalized: boolean; checkpoint?: string }> {
// Search forward from start sequence
for (let i = parseInt(startSequence); i < parseInt(startSequence) + 100; i++) {
try {
const checkpoint = await getCheckpointBySequence(i.toString());

if (checkpoint.transactions.includes(txDigest)) {
console.log(`✓ Transaction finalized in checkpoint ${checkpoint.sequence_number}`);
return {
finalized: true,
checkpoint: checkpoint.sequence_number
};
}
} catch (error) {
break;
}
}

return { finalized: false };
}

// Example: Calculate network throughput
async function calculateNetworkTPS(
startSequence: string,
endSequence: string
): Promise<number> {
const start = await getCheckpointBySequence(startSequence);
const end = await getCheckpointBySequence(endSequence);

const txCount = parseInt(end.network_total_transactions) -
parseInt(start.network_total_transactions);
const timeSpan = (parseInt(end.timestamp_ms) - parseInt(start.timestamp_ms)) / 1000;

const tps = txCount / timeSpan;

console.log(`Network TPS over ${timeSpan}s: ${tps.toFixed(2)}`);

return tps;
}

// Usage
const latestCheckpoint = await getCheckpointBySequence('193161953');
console.log('Checkpoint:', latestCheckpoint.sequence_number);
console.log('Transactions:', latestCheckpoint.transactions.length);
console.log('Total Network TXs:', latestCheckpoint.network_total_transactions);

Use Cases#

1. Transaction Finality Verification#

Confirm a transaction reached immutable finality:

interface FinalityStatus {
isFinalized: boolean;
checkpointSequence?: string;
confirmations?: number;
}

async function checkTransactionFinality(
txDigest: string,
expectedCheckpoint: string
): Promise<FinalityStatus> {
const checkpoint = await getCheckpointBySequence(expectedCheckpoint);

const isIncluded = checkpoint.transactions.includes(txDigest);

if (isIncluded) {
// Get latest checkpoint to calculate confirmations
// (In production, you'd track the latest known checkpoint)
const latestSequence = parseInt(expectedCheckpoint) + 1000;
const confirmations = latestSequence - parseInt(checkpoint.sequence_number);

return {
isFinalized: true,
checkpointSequence: checkpoint.sequence_number,
confirmations: confirmations
};
}

return { isFinalized: false };
}

2. Historical State Reconstruction#

Reconstruct blockchain state at specific checkpoint:

interface StateSnapshot {
sequence: string;
timestamp: Date;
totalTransactions: number;
includedTransactions: string[];
}

async function captureStateSnapshot(
checkpointSequence: string
): Promise<StateSnapshot> {
const checkpoint = await getCheckpointBySequence(checkpointSequence);

return {
sequence: checkpoint.sequence_number,
timestamp: new Date(parseInt(checkpoint.timestamp_ms)),
totalTransactions: parseInt(checkpoint.network_total_transactions),
includedTransactions: checkpoint.transactions
};
}

// Create timeline of snapshots
async function createStateTimeline(
startSequence: string,
endSequence: string,
interval: number
): Promise<StateSnapshot[]> {
const timeline: StateSnapshot[] = [];
const start = parseInt(startSequence);
const end = parseInt(endSequence);

for (let seq = start; seq <= end; seq += interval) {
const snapshot = await captureStateSnapshot(seq.toString());
timeline.push(snapshot);
}

return timeline;
}

3. Network Performance Monitoring#

Track network throughput metrics:

interface NetworkMetrics {
periodStart: Date;
periodEnd: Date;
totalTransactions: number;
avgTPS: number;
peakTPS: number;
checkpointsAnalyzed: number;
}

async function analyzeNetworkPerformance(
startSequence: string,
count: number
): Promise<NetworkMetrics> {
const checkpoints = [];

for (let i = 0; i < count; i++) {
const seq = (parseInt(startSequence) + i).toString();
const checkpoint = await getCheckpointBySequence(seq);
checkpoints.push(checkpoint);
}

const first = checkpoints[0];
const last = checkpoints[checkpoints.length - 1];

const totalTxs = parseInt(last.network_total_transactions) -
parseInt(first.network_total_transactions);
const timeSpan = (parseInt(last.timestamp_ms) - parseInt(first.timestamp_ms)) / 1000;
const avgTPS = totalTxs / timeSpan;

// Calculate peak TPS from individual checkpoints
let peakTPS = 0;
for (let i = 1; i < checkpoints.length; i++) {
const txCount = checkpoints[i].transactions.length;
const timeDiff = (parseInt(checkpoints[i].timestamp_ms) -
parseInt(checkpoints[i-1].timestamp_ms)) / 1000;
const tps = txCount / timeDiff;
peakTPS = Math.max(peakTPS, tps);
}

return {
periodStart: new Date(parseInt(first.timestamp_ms)),
periodEnd: new Date(parseInt(last.timestamp_ms)),
totalTransactions: totalTxs,
avgTPS: avgTPS,
peakTPS: peakTPS,
checkpointsAnalyzed: count
};
}

4. Checkpoint Chain Validation#

Verify checkpoint chain integrity:

async function validateCheckpointChain(
startSequence: string,
count: number
): Promise<boolean> {
let previousDigest: string | null = null;

for (let i = 0; i < count; i++) {
const seq = (parseInt(startSequence) + i).toString();
const checkpoint = await getCheckpointBySequence(seq);

if (i > 0 && checkpoint.previous_digest !== previousDigest) {
console.error(`Chain break at sequence ${seq}`);
console.error(`Expected previous: ${previousDigest}`);
console.error(`Got previous: ${checkpoint.previous_digest}`);
return false;
}

previousDigest = checkpoint.digest;
}

console.log(`✓ Validated ${count} checkpoints in chain`);
return true;
}

Best Practices#

1. Cache Checkpoint Data#

Checkpoints are immutable once finalized:

const checkpointCache = new Map<string, any>();

async function getCachedCheckpoint(sequence: string): Promise<any> {
if (checkpointCache.has(sequence)) {
return checkpointCache.get(sequence);
}

const checkpoint = await getCheckpointBySequence(sequence);
checkpointCache.set(sequence, checkpoint);

return checkpoint;
}

2. Use Field Masking#

Request only required data:

// ✅ Good: Minimal fields
const request = {
sequence_number: seq,
read_mask: {
paths: ['sequence_number', 'transactions']
}
};

// ❌ Bad: All fields
const request = { sequence_number: seq };

3. Handle Missing Checkpoints#

Not all sequence numbers may exist:

async function safeGetCheckpoint(sequence: string): Promise<any | null> {
try {
return await getCheckpointBySequence(sequence);
} catch (error: any) {
if (error.code === grpc.status.NOT_FOUND) {
console.log(`Checkpoint ${sequence} not found`);
return null;
}
throw error;
}
}

Need help with checkpoints? Contact support@dwellir.com or check the gRPC overview.