> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solanatracker.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Entry Monitoring

> Subscribe to Solana entry updates over Yellowstone gRPC — the smallest building blocks that contain transaction batches inside each block.

## Overview

Entries are the smallest building blocks of the Solana blockchain. Think of them as containers that hold groups of transactions.

<Info>
  **Start here first:** Complete the [Quickstart Guide](/yellowstone-grpc/quickstart) to set up your stream manager.
</Info>

## What are Entries?

<Tabs>
  <Tab title="The Basics">
    **Entries are transaction containers**

    Here's what they do:

    * **Bundle transactions:** They group transactions together
    * **Set the order:** Transactions run in a specific order
    * **Link together:** Each entry connects to the next one
    * **Track time:** They record when things happen

    ```typescript theme={null}
        const subscribeRequest: SubscribeRequest = {
          entry: {
            entrySubscribe: {}
          },
          commitment: CommitmentLevel.CONFIRMED
        };
    ```
  </Tab>

  <Tab title="What's Inside">
    **Each entry has:**

    * **Slot:** Which time slot it belongs to (slots are 400ms long)
    * **Index:** Its position in that slot
    * **Hash:** A unique ID
    * **Transactions:** The list of transactions inside
    * **Num Hashes:** A proof-of-history number

    **Why this matters:**

    * See how transactions are grouped
    * Understand validator behavior
    * Get more detail than just watching transactions
  </Tab>

  <Tab title="When to Use This">
    **Use entry monitoring for:**

    * **Performance research:** How fast are transactions being processed?
    * **Validator studies:** How do validators work?
    * **Network problems:** Debugging consensus issues
    * **Research projects:** Academic blockchain studies
    * **Deep analysis:** Investigating transaction order

    <Note>
      **Skip this if:** You're building a regular app or need user-facing features
    </Note>
  </Tab>
</Tabs>

## Real Examples

### Example 1: Basic Entry Monitor

Watch entries as they come in:

```typescript theme={null}
import Client, { CommitmentLevel, SubscribeRequest } from "@triton-one/yellowstone-grpc";

class StreamManager {
  private client: Client;

  constructor(
    endpoint: string,
    token: string,
    private onData: (data: any) => void
  ) {
    this.client = new Client(endpoint, token, {
      "grpc.max_receive_message_length": 100 * 1024 * 1024
    });
  }

  async connect(request: SubscribeRequest) {
    const stream = await this.client.subscribe();

    stream.on("data", this.onData);
    stream.on("error", (error) => {
      console.error("Stream error:", error);
    });

    await new Promise<void>((resolve, reject) => {
      stream.write(request, (err) => {
        if (err === null || err === undefined) resolve();
        else reject(err);
      });
    });

    return stream;
  }
}

async function monitorEntries() {
  const streamManager = new StreamManager(
    "https://grpc.solanatracker.io",
    process.env.GRPC_API_TOKEN || "your-api-key",
    handleEntry
  );

  const subscribeRequest: SubscribeRequest = {
    entry: {
      entrySubscribe: {}
    },
    commitment: CommitmentLevel.CONFIRMED
  };

  console.log('Starting entry monitoring...');
  console.log('Note: This is a high-volume stream\n');
  
  await streamManager.connect(subscribeRequest);
}

const entryStats = {
  totalEntries: 0,
  totalTransactions: 0,
  emptyEntries: 0,
  lastReportTime: Date.now()
};

function handleEntry(data: any): void {
  if (data.entry) {
    const entry = data.entry;
    entryStats.totalEntries++;
    
    const txCount = entry.transactions?.length || 0;
    entryStats.totalTransactions += txCount;
    
    if (txCount === 0) {
      entryStats.emptyEntries++;
    }
    
    console.log(`\n[Entry #${entryStats.totalEntries}]`);
    console.log(`  Slot: ${entry.slot}`);
    console.log(`  Index: ${entry.index || 'N/A'}`);
    console.log(`  Hash: ${entry.hash?.slice(0, 16) || 'N/A'}...`);
    console.log(`  Num Hashes: ${entry.numHashes || 'N/A'}`);
    console.log(`  Transactions: ${txCount}`);
    
    if (txCount === 0) {
      console.log(`  [Empty Entry]`);
    } else {
      // Count transaction types
      let successCount = 0;
      let failedCount = 0;
      let voteCount = 0;
      
      entry.transactions.forEach((tx: any) => {
        if (tx.isVote) {
          voteCount++;
        }
        if (tx.meta) {
          if (tx.meta.err) {
            failedCount++;
          } else {
            successCount++;
          }
        }
      });
      
      console.log(`  Transaction Breakdown:`);
      console.log(`    Votes: ${voteCount}`);
      console.log(`    Successful: ${successCount}`);
      console.log(`    Failed: ${failedCount}`);
      
      // Show first few signatures
      if (entry.transactions.length > 0) {
        console.log(`  First Transactions:`);
        entry.transactions.slice(0, 3).forEach((tx: any, idx: number) => {
          const sig = tx.signature?.slice(0, 16) || 'unknown';
          const type = tx.isVote ? '[VOTE]' : '[TX]';
          console.log(`    ${idx + 1}. ${sig}... ${type}`);
        });
      }
    }
    
    // Report stats every 100 entries
    if (entryStats.totalEntries % 100 === 0) {
      printEntrySummary();
    }
  }
}

function printEntrySummary(): void {
  const now = Date.now();
  const elapsed = (now - entryStats.lastReportTime) / 1000;
  const entriesPerSec = 100 / elapsed;
  const avgTxPerEntry = entryStats.totalTransactions / entryStats.totalEntries;
  const emptyRate = (entryStats.emptyEntries / entryStats.totalEntries * 100).toFixed(1);
  
  console.log(`\n=== Entry Summary ===`);
  console.log(`  Total Entries: ${entryStats.totalEntries}`);
  console.log(`  Total Transactions: ${entryStats.totalTransactions}`);
  console.log(`  Empty Entries: ${entryStats.emptyEntries} (${emptyRate}%)`);
  console.log(`  Entries/sec: ${entriesPerSec.toFixed(1)}`);
  console.log(`  Avg Tx/Entry: ${avgTxPerEntry.toFixed(2)}`);
  
  entryStats.lastReportTime = now;
}

monitorEntries().catch(console.error);
```

### Example 2: Filter Entries

Only process entries you care about:

```typescript theme={null}
async function monitorFilteredEntries() {
  const streamManager = new StreamManager(
    "https://grpc.solanatracker.io",
    process.env.GRPC_API_TOKEN || "your-api-key",
    handleFilteredEntry
  );

  const subscribeRequest: SubscribeRequest = {
    entry: {
      entrySubscribe: {}
    },
    commitment: CommitmentLevel.CONFIRMED
  };

  console.log('Monitoring filtered entries (non-vote transactions only)...\n');
  await streamManager.connect(subscribeRequest);
}

const filteredStats = {
  totalEntriesProcessed: 0,
  totalEntriesSkipped: 0,
  nonVoteTransactions: 0,
  voteTransactions: 0
};

function handleFilteredEntry(data: any): void {
  if (data.entry) {
    const entry = data.entry;
    
    // Skip empty entries
    if (!entry.transactions || entry.transactions.length === 0) {
      filteredStats.totalEntriesSkipped++;
      return;
    }
    
    // Count transaction types
    let nonVoteCount = 0;
    let voteCount = 0;
    
    entry.transactions.forEach((tx: any) => {
      if (tx.isVote) {
        voteCount++;
      } else {
        nonVoteCount++;
      }
    });
    
    // Skip entries with only vote transactions
    if (nonVoteCount === 0) {
      filteredStats.totalEntriesSkipped++;
      filteredStats.voteTransactions += voteCount;
      return;
    }
    
    // Process this entry
    filteredStats.totalEntriesProcessed++;
    filteredStats.nonVoteTransactions += nonVoteCount;
    filteredStats.voteTransactions += voteCount;
    
    console.log(`\n[Filtered Entry #${filteredStats.totalEntriesProcessed}]`);
    console.log(`  Slot: ${entry.slot}`);
    console.log(`  Total Transactions: ${entry.transactions.length}`);
    console.log(`  Non-Vote Txs: ${nonVoteCount}`);
    console.log(`  Vote Txs: ${voteCount}`);
    
    // Show non-vote transaction signatures
    const nonVoteTxs = entry.transactions.filter((tx: any) => !tx.isVote);
    console.log(`  Non-Vote Signatures:`);
    nonVoteTxs.slice(0, 3).forEach((tx: any, idx: number) => {
      const sig = tx.signature?.slice(0, 16) || 'unknown';
      const status = tx.meta?.err ? '❌' : '✅';
      console.log(`    ${idx + 1}. ${sig}... ${status}`);
    });
    
    // Report stats every 100 processed entries
    if (filteredStats.totalEntriesProcessed % 100 === 0) {
      printFilterStats();
    }
  }
}

function printFilterStats(): void {
  const totalEntries = filteredStats.totalEntriesProcessed + filteredStats.totalEntriesSkipped;
  const processRate = (filteredStats.totalEntriesProcessed / totalEntries * 100).toFixed(1);
  const skipRate = (filteredStats.totalEntriesSkipped / totalEntries * 100).toFixed(1);
  
  console.log(`\n=== Filtering Statistics ===`);
  console.log(`  Total Entries Seen: ${totalEntries}`);
  console.log(`  Processed: ${filteredStats.totalEntriesProcessed} (${processRate}%)`);
  console.log(`  Skipped: ${filteredStats.totalEntriesSkipped} (${skipRate}%)`);
  console.log(`  Non-Vote Txs Found: ${filteredStats.nonVoteTransactions}`);
  console.log(`  Vote Txs Found: ${filteredStats.voteTransactions}`);
}

monitorFilteredEntries().catch(console.error);
```

## Entry Data Structure

<Accordion title="Entry Fields">
  ```typescript theme={null}
    {
      slot: number;              // Which time slot
      index: number;             // Position in that slot
      hash: string;              // Unique ID
      numHashes: number;         // Proof-of-history count
      transactions: Array<{      // List of transactions
        signature: string;
        isVote: boolean;
        meta: {
          err: any;
          fee: number;
        };
      }>;
      tick: boolean;             // Is this a tick entry?
    }
  ```
</Accordion>

<Accordion title="How Entries Compare">
  **Entries vs Transactions:**

  * Entries = groups of transactions
  * Shows you the order things happen
  * Includes timing proof data

  **Entries vs Blocks:**

  * Blocks = many entries combined
  * Entries = smaller pieces inside blocks
  * Blocks show finality

  **Entries vs Slots:**

  * Slots = 400ms time windows
  * One slot = multiple entries
  * Entries = what happened in that time
</Accordion>

## Performance Considerations

<CardGroup cols={2}>
  <Card title="Lots of Data" icon="chart-line">
    **This stream is busy**

    * Many messages per second
    * Never stops during network activity
    * Each entry has multiple transactions
    * You need fast processing
  </Card>

  <Card title="Stay Fast" icon="gauge">
    **Keep your code efficient**

    * Don't wait for each entry (use async)
    * Process multiple entries at once
    * Only look at what you need
    * Sample the data if analyzing a lot
  </Card>
</CardGroup>

## Common Use Cases

<Tabs>
  <Tab title="Performance Research">
    **Study how fast things work**

    Track how the network groups transactions. Find patterns that show problems or ways to make things faster.
  </Tab>

  <Tab title="Validator Research">
    **Study how validators work**

    See how validators build blocks. Look at patterns, ordering, and grouping strategies.
  </Tab>

  <Tab title="Network Debugging">
    **Fix network problems**

    Use entry data to find bugs, investigate weird patterns, and understand what's happening at a low level.
  </Tab>
</Tabs>

## Filtering Tips

Entry monitoring sends you ALL entries. There's no built-in filtering. Here's how to deal with that:

<Note>
  **Ways to handle the data:**

  * **Filter in your code:** Only process what you care about
  * **Sample it:** Look at every 10th or 100th entry for stats
  * **Time windows:** Only look at specific time periods
  * **Slot filtering:** Only process certain slots
  * **Transaction types:** Focus on specific transaction types (see Example 3)
</Note>

## Best Practices

<Accordion title="When to Use This">
  **Use entry monitoring for:**

  * Deep blockchain research
  * Studying validators
  * Debugging network issues
  * Academic projects
  * Understanding Proof of History

  **Don't use it for:**

  * Normal apps
  * User interfaces
  * Business features
  * Trading apps
</Accordion>

<Accordion title="Handle the Data">
  **Tips for processing:**

  * Build fast code
  * Don't wait for each entry (use async)
  * Sample if you're analyzing a lot
  * Watch your memory usage
  * Handle when data comes too fast
</Accordion>

<Accordion title="Analysis Tips">
  **Do good analysis:**

  * Pick specific things to measure
  * Use sampling for large datasets
  * Calculate rolling averages
  * Look at patterns over time
  * Compare with other data sources
</Accordion>

## Troubleshooting

<Accordion title="Too Much Data">
  **Problem:** The entry stream is overwhelming

  **Fix it:**

  * Filter in your code (see Example 3)
  * Sample the data
  * Use async processing
  * Check your system resources
  * Consider transaction monitoring instead
</Accordion>

<Accordion title="Need More Info">
  **Problem:** Entries don't have enough context

  **Fix it:**

  * Also monitor transactions
  * Check account updates
  * Use block monitoring too
  * Keep your own state
</Accordion>

## Common Questions

<Accordion title="Why are there so many entries?">
  Entries are created constantly as validators process transactions. The Solana network is very active, so you'll see many entries per second. Use filtering to manage the volume.
</Accordion>

<Accordion title="What are empty entries?">
  Empty entries are part of Solana's Proof of History mechanism. They help maintain timing even when there are no transactions to process. They're normal and expected.
</Accordion>

<Accordion title="Should I filter out vote transactions?">
  Usually yes. Vote transactions are validator consensus votes and typically aren't relevant for application-level monitoring. See Example 3 for how to filter them.
</Accordion>

<Accordion title="How do I know if I'm processing too slowly?">
  If you're falling behind, you'll see increasing delays between entry creation and processing. Monitor your processing time and queue sizes. Consider sampling or better filtering if you can't keep up.
</Accordion>

## Next Steps

<CardGroup cols={2}>
  <Card title="Pump.fun Example" icon="chart-line" href="/yellowstone-grpc/examples/pumpfun-transactions">
    See a real example
  </Card>

  <Card title="Transaction Monitoring" icon="receipt" href="/yellowstone-grpc/transaction-monitoring">
    Monitor transactions instead
  </Card>

  <Card title="Slot & Block Monitoring" icon="cube" href="/yellowstone-grpc/slot-block-monitoring">
    Higher-level monitoring
  </Card>

  <Card title="Best Practices" icon="star" href="/yellowstone-grpc/best-practices">
    Optimize your setup
  </Card>
</CardGroup>

<Note>
  **Remember:** Entry monitoring is for advanced research. Most apps work better with transaction, account, or block monitoring.
</Note>
