Overview

Slot and block monitoring provides insights into Solana’s network consensus, block production timing, and network health. Track slot progression, block finalization, and network performance metrics in real-time.
Prerequisites: This guide assumes you’ve completed the Yellowstone gRPC Quickstart and have a working stream setup.

Monitoring Types

Track network consensus progressionMonitor slot advancement across different commitment levels:
const subscribeRequest: SubscribeRequest = {
  slots: {
    slotSubscribe: {
      filterByCommitment: false // Receive all commitment levels
    }
  },
  commitment: CommitmentLevel.CONFIRMED
};
Slot data includes:
  • Slot number
  • Parent slot
  • Commitment status (processed, confirmed, finalized)
  • Leader information
Best for: Network health monitoring, slot timing analysis, consensus tracking

Practical Examples

Example 1: Network Health Monitor

Track slot progression and identify network issues:
import { StreamManager } from './stream-manager'; // From quickstart guide

async function monitorNetworkHealth() {
  const streamManager = new StreamManager(
    "your-grpc-endpoint",
    "your-api-key",
    handleNetworkHealth
  );

  const subscribeRequest: SubscribeRequest = {
    slots: {
      slotSubscribe: {
        filterByCommitment: false // Track all commitment levels
      }
    },
    commitment: CommitmentLevel.PROCESSED
  };

  await streamManager.connect(subscribeRequest);
}

let lastSlot = 0;
let lastTimestamp = Date.now();
const slotTimes: number[] = [];

function handleNetworkHealth(data: any): void {
  if (data.slot) {
    const slot = data.slot;
    const currentTime = Date.now();
    
    console.log(`\n📊 Slot Update:`);
    console.log(`  Slot: ${slot.slot}`);
    console.log(`  Parent: ${slot.parentSlot}`);
    console.log(`  Status: ${slot.status}`);
    
    // Calculate slot timing
    if (lastSlot > 0) {
      const slotDiff = slot.slot - lastSlot;
      const timeDiff = currentTime - lastTimestamp;
      
      if (slotDiff === 1) {
        // Normal slot progression
        const slotTime = timeDiff;
        slotTimes.push(slotTime);
        
        // Keep last 100 slot times for analysis
        if (slotTimes.length > 100) {
          slotTimes.shift();
        }
        
        const avgSlotTime = slotTimes.reduce((a, b) => a + b, 0) / slotTimes.length;
        
        console.log(`  Slot Time: ${slotTime}ms`);
        console.log(`  Avg Slot Time: ${avgSlotTime.toFixed(1)}ms`);
        
        // Alert on slow slots
        if (slotTime > 800) {
          console.log(`  ⚠️  SLOW SLOT: ${slotTime}ms (normal ~400ms)`);
        }
      } else if (slotDiff > 1) {
        console.log(`  ⚠️  SKIPPED ${slotDiff - 1} SLOTS`);
      }
    }
    
    lastSlot = slot.slot;
    lastTimestamp = currentTime;
  }
}

Example 2: Block Production Monitor

Track block production and transaction volume:
async function monitorBlockProduction() {
  const streamManager = new StreamManager(
    "your-grpc-endpoint",
    "your-api-key",
    handleBlockProduction
  );

  const subscribeRequest: SubscribeRequest = {
    blocksMeta: {
      blockMetaSubscribe: {}
    },
    commitment: CommitmentLevel.CONFIRMED
  };

  await streamManager.connect(subscribeRequest);
}

function handleBlockProduction(data: any): void {
  if (data.blockMeta) {
    const blockMeta = data.blockMeta;
    
    console.log(`\n🧱 Block Produced:`);
    console.log(`  Slot: ${blockMeta.slot}`);
    console.log(`  Block Height: ${blockMeta.blockHeight}`);
    console.log(`  Block Hash: ${blockMeta.blockhash}`);
    console.log(`  Parent Hash: ${blockMeta.parentBlockhash}`);
    console.log(`  Transactions: ${blockMeta.transactionCount}`);
    console.log(`  Block Time: ${new Date(blockMeta.blockTime * 1000).toISOString()}`);
    
    if (blockMeta.rewards?.length > 0) {
      console.log(`  Rewards:`);
      blockMeta.rewards.forEach((reward: any) => {
        console.log(`    ${reward.pubkey}: ${reward.lamports} lamports (${reward.rewardType})`);
      });
    }
    
    // Alert on high transaction count
    if (blockMeta.transactionCount > 3000) {
      console.log(`  🔥 HIGH ACTIVITY: ${blockMeta.transactionCount} transactions`);
    }
  }
}

Example 3: Filtered Block Monitor

Monitor blocks containing specific program activity:
async function monitorDEXBlocks() {
  const streamManager = new StreamManager(
    "your-grpc-endpoint",
    "your-api-key",
    handleDEXBlock
  );

  const subscribeRequest: SubscribeRequest = {
    blocks: {
      blockSubscribe: {
        accountInclude: [
          "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", // Raydium V4
          "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"   // Jupiter
        ],
        includeTransactions: true,
        includeAccounts: false,
        includeEntries: false
      }
    },
    commitment: CommitmentLevel.CONFIRMED
  };

  await streamManager.connect(subscribeRequest);
}

function handleDEXBlock(data: any): void {
  if (data.block) {
    const block = data.block;
    
    console.log(`\n🔄 DEX Activity Block:`);
    console.log(`  Slot: ${block.slot}`);
    console.log(`  Block Hash: ${block.blockhash}`);
    console.log(`  Total Transactions: ${block.transactions?.length || 0}`);
    
    if (block.transactions) {
      let dexTxCount = 0;
      let totalFees = 0;
      
      block.transactions.forEach((tx: any) => {
        if (tx.meta && !tx.meta.err) {
          dexTxCount++;
          totalFees += tx.meta.fee || 0;
        }
      });
      
      console.log(`  DEX Transactions: ${dexTxCount}`);
      console.log(`  Total Fees: ${(totalFees / 1e9).toFixed(4)} SOL`);
      console.log(`  Avg Fee: ${(totalFees / dexTxCount / 1e9).toFixed(6)} SOL`);
    }
  }
}

Data Structures

Understanding slot and block data formats:

Performance Considerations

Slot Monitoring

Lightweight and efficient
  • Very low bandwidth usage
  • Real-time network health insights
  • Minimal processing overhead
  • Good for monitoring dashboards

Block Metadata

Balanced approach
  • Moderate bandwidth usage
  • Block-level insights without full data
  • Transaction counts and timing
  • Suitable for analytics

Full Blocks

High volume data
  • High bandwidth requirements
  • Complete transaction data
  • Requires robust processing
  • Use filters to reduce volume

Filtered Blocks

Optimized streaming
  • Use accountInclude filters
  • Disable unnecessary data (entries, accounts)
  • Focus on specific programs
  • Balance detail with performance

Use Cases

Track network health and performance
  • Slot timing analysis
  • Network congestion detection
  • Consensus monitoring
  • Validator performance
// Monitor slot timing deviations
const targetSlotTime = 400; // ms
const tolerance = 200; // ms

if (Math.abs(slotTime - targetSlotTime) > tolerance) {
  console.log(`Network performance issue detected`);
}

Error Handling

Common issues and solutions:

Best Practices

Production Guidelines:
  • Start with metadata - Use block metadata before full blocks
  • Apply filters - Use accountInclude to reduce irrelevant data
  • Monitor timing - Track slot progression for network health
  • Handle gaps - Implement logic for missing slots/blocks
  • Process async - Don’t block stream processing with heavy computations
  • Use appropriate commitment - Match commitment level to your needs

Next Steps