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

# LaserStream을 통한 슬롯 & 블록 모니터링

> LaserStream을 사용하여 슬롯 타이밍, 블록 메타데이터, 필터링 된 전체 블록으로 Solana 네트워크 합의, 블록 생성 및 네트워크 상태 변경을 모니터링합니다.

슬롯 및 블록 모니터링은 Solana의 네트워크 합의, 블록 생성 시간 및 전반적인 상태를 살펴봅니다. LaserStream을 사용하면 [`helius-laserstream`](/docs/ko/laserstream/clients) SDK를 통해 슬롯 진행, 블록 완료 및 네트워크 성능 지표를 실시간으로 추적할 수 있습니다.

<Info>
  **사전 준비:** 이 가이드는 [LaserStream gRPC 퀵스타트](/docs/ko/laserstream/grpc)를 완료하고 API 키를 보유하고 있다고 가정합니다.
</Info>

***

## 모니터링 유형

<Tabs>
  <Tab title="슬롯 업데이트">
    **네트워크 합의 진행 추적**

    커밋 수준별로 슬롯 진행 모니터링:

    ```typescript theme={"system"}
    import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';

    const subscriptionRequest: SubscribeRequest = {
      slots: {
        slotSubscribe: {
          filterByCommitment: false // Receive all commitment levels
        }
      },
      commitment: CommitmentLevel.CONFIRMED,
      accounts: {}, transactions: {}, transactionsStatus: {},
      blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
    };
    ```

    **슬롯 데이터에는 다음이 포함됩니다:** 슬롯 번호, 부모 슬롯, 커밋 상태 (`processed` / `confirmed` / `finalized`), 및 리더 정보.

    <Note>
      **최적 용도:** 네트워크 상태 모니터링, 슬롯 타이밍 분석, 합의 추적.
    </Note>
  </Tab>

  <Tab title="블록 데이터">
    **완전한 블록 정보 모니터링**

    거래 및 계정 업데이트가 포함된 전체 블록 스트리밍:

    ```typescript theme={"system"}
    const subscriptionRequest: SubscribeRequest = {
      blocks: {
        blockSubscribe: {
          accountInclude: [], // All accounts
          includeTransactions: true,
          includeAccounts: true,
          includeEntries: false
        }
      },
      commitment: CommitmentLevel.CONFIRMED,
      accounts: {}, transactions: {}, transactionsStatus: {},
      slots: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
    };
    ```

    **블록 데이터에는 다음이 포함됩니다:** 블록 메타데이터, 거래, 계정 업데이트, 블록 타이밍.

    <Warning>
      **대량 데이터:** 전체 블록 스트림은 방대한 데이터를 생성합니다. `accountInclude` 필터를 사용하여 데이터를 줄이세요.
    </Warning>
  </Tab>

  <Tab title="블록 메타데이터">
    **경량 블록 정보**

    거래 세부 정보 없이 블록 메타데이터 가져오기:

    ```typescript theme={"system"}
    const subscriptionRequest: SubscribeRequest = {
      blocksMeta: {
        blockMetaSubscribe: {}
      },
      commitment: CommitmentLevel.CONFIRMED,
      accounts: {}, transactions: {}, transactionsStatus: {},
      slots: {}, blocks: {}, entry: {}, accountsDataSlice: [],
    };
    ```

    **메타데이터에는 다음이 포함됩니다:** 블록 해시, 부모 해시, 슬롯, 높이, 거래 수, 보상.

    <Tip>
      **효율적:** 전체 블록 스트리밍의 낮은 대역폭 대안.
    </Tip>
  </Tab>
</Tabs>

***

## 실용 예시

### 예시 1: 네트워크 상태 모니터

슬롯 진행을 추적하고 네트워크 문제 식별:

```typescript [expandable] theme={"system"}
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';

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

// CommitmentLevel only ships the forward (name → number) mapping, so we keep
// a small reverse lookup for the numeric status the SDK returns on slot updates.
const STATUS_NAMES = ['PROCESSED', 'CONFIRMED', 'FINALIZED'] as const;

async function monitorNetworkHealth() {
  const subscriptionRequest: SubscribeRequest = {
    slots: {
      slotSubscribe: {
        filterByCommitment: true // Track processed commitment levels
      }
    },
    commitment: CommitmentLevel.PROCESSED,
    accounts: {}, transactions: {}, transactionsStatus: {},
    blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
  };

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY',
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
  };

  await subscribe(config, subscriptionRequest, async (data) => {
    if (!data.slot) return;
    const slot = data.slot;
    // The SDK returns u64 fields as strings to preserve precision.
    const currentSlot = Number(slot.slot);
    const currentTime = Date.now();

    console.log(`\n📊 Slot Update:`);
    console.log(`  Slot: ${currentSlot}`);
    console.log(`  Parent: ${slot.parent}`);
    // slot.status is a numeric enum (0=processed, 1=confirmed, 2=finalized).
    console.log(`  Status: ${STATUS_NAMES[slot.status] ?? slot.status}`);

    if (lastSlot > 0) {
      const slotDiff = currentSlot - lastSlot;
      const timeDiff = currentTime - lastTimestamp;

      if (slotDiff === 1) {
        slotTimes.push(timeDiff);
        if (slotTimes.length > 100) slotTimes.shift();

        const avg = slotTimes.reduce((a, b) => a + b, 0) / slotTimes.length;
        console.log(`  Slot Time: ${timeDiff}ms`);
        console.log(`  Avg Slot Time: ${avg.toFixed(1)}ms`);

        if (timeDiff > 800) {
          console.log(`  ⚠️  SLOW SLOT: ${timeDiff}ms (normal ~400ms)`);
        }
      } else if (slotDiff > 1) {
        console.log(`  ⚠️  SKIPPED ${slotDiff - 1} SLOTS`);
      }
    }

    lastSlot = currentSlot;
    lastTimestamp = currentTime;
  }, async (error) => {
    console.error('Stream error:', error);
  });
}

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

### 예시 2: 블록 생성 모니터

블록 생성 및 거래량 추적:

```typescript [expandable] theme={"system"}
async function monitorBlockProduction() {
  const subscriptionRequest: SubscribeRequest = {
    blocksMeta: {
      blockMetaSubscribe: {}
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {}, transactions: {}, transactionsStatus: {},
    slots: {}, blocks: {}, entry: {}, accountsDataSlice: [],
  };

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY',
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
  };

  await subscribe(config, subscriptionRequest, async (data) => {
    if (!data.blockMeta) return;
    const blockMeta = data.blockMeta;

    console.log(`\n🧱 Block Produced:`);
    console.log(`  Slot: ${blockMeta.slot}`);
    // blockHeight is a wrapper object: { blockHeight: '397657352' }
    console.log(`  Block Height: ${blockMeta.blockHeight?.blockHeight}`);
    console.log(`  Block Hash: ${blockMeta.blockhash}`);
    console.log(`  Parent Slot: ${blockMeta.parentSlot}`);
    console.log(`  Parent Hash: ${blockMeta.parentBlockhash}`);
    console.log(`  Transactions: ${blockMeta.executedTransactionCount}`);
    console.log(`  Entries: ${blockMeta.entriesCount}`);
    if (blockMeta.blockTime?.timestamp) {
      // blockTime.timestamp is a u64 as a string (Unix seconds).
      console.log(`  Block Time: ${new Date(Number(blockMeta.blockTime.timestamp) * 1000).toISOString()}`);
    }

    // rewards is a wrapper object: { rewards: [...], numPartitions: number | null }
    if (blockMeta.rewards?.rewards?.length > 0) {
      console.log(`  Rewards:`);
      blockMeta.rewards.rewards.forEach((r: any) => {
        console.log(`    ${r.pubkey}: ${r.lamports} lamports (${r.rewardType})`);
      });
    }

    if (Number(blockMeta.executedTransactionCount) > 3000) {
      console.log(`  🔥 HIGH ACTIVITY: ${blockMeta.executedTransactionCount} transactions`);
    }
  }, async (error) => {
    console.error('Stream error:', error);
  });
}
```

### 예시 3: 필터링 된 블록 모니터

특정 프로그램 활동이 포함된 블록 모니터링:

```typescript [expandable] theme={"system"}
async function monitorDEXBlocks() {
  const subscriptionRequest: SubscribeRequest = {
    blocks: {
      blockSubscribe: {
        accountInclude: [
          "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", // Raydium
          "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK", // Raydium CLMM
          "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"   // Jupiter
        ],
        includeTransactions: true,
        includeAccounts: false,
        includeEntries: false
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {}, transactions: {}, transactionsStatus: {},
    slots: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
  };

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY',
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
  };

  await subscribe(config, subscriptionRequest, async (data) => {
    if (!data.block) return;
    const block = data.block;

    let successfulDexTx = 0;
    let totalFees = 0; // lamports
    block.transactions?.forEach((tx: any) => {
      if (tx.meta && !tx.meta.err) {
        successfulDexTx++;
        // tx.meta.fee is a u64 string — coerce before adding.
        totalFees += Number(tx.meta.fee ?? 0);
      }
    });

    console.log(`\n🔄 DEX Activity Block:`);
    console.log(`  Slot: ${block.slot}`);
    console.log(`  Block Height: ${block.blockHeight?.blockHeight}`);
    console.log(`  Block Hash: ${block.blockhash}`);
    console.log(`  Total transactions in block: ${block.executedTransactionCount}`);
    console.log(`  Matched DEX transactions: ${block.transactions?.length ?? 0}`);
    console.log(`  Successful DEX transactions: ${successfulDexTx}`);
    if (successfulDexTx > 0) {
      console.log(`  Total Fees: ${(totalFees / 1e9).toFixed(4)} SOL`);
      console.log(`  Avg Fee: ${(totalFees / successfulDexTx / 1e9).toFixed(6)} SOL`);
    }
  }, async (error) => {
    console.error('Stream error:', error);
  });
}
```

***

## 데이터 구조

<Accordion title="슬롯 데이터 구조">
  ```typescript theme={"system"}
  {
    slot: string;     // Current slot number (u64 as string)
    parent: string;   // Parent slot number (u64 as string)
    status: number;   // CommitmentLevel enum: 0 = processed, 1 = confirmed, 2 = finalized
  }
  ```

  각 슬롯은 약 400ms의 네트워크 시간을 나타냅니다. 세 가지 커밋 수준은 점점 강력한 보증을 반영합니다: `processed` (초기), `confirmed` (초다수 투표), `finalized` (불가역).

  <Tip>
    u64 필드 (슬롯, 부모)는 `Number.MAX_SAFE_INTEGER` 이상의 정밀도를 유지하기 위해 문자열로 도착합니다. 수학적 작업이 필요할 때 `Number(slot.slot)`로 변환하세요. `status`는 숫자 열거형입니다 — 인간이 읽을 수 있는 이름을 위해 `CommitmentLevel[slot.status]`를 사용하세요.
  </Tip>
</Accordion>

<Accordion title="블록 메타데이터 구조">
  ```typescript theme={"system"}
  {
    slot: string;                                  // u64 as string
    blockhash: string;
    rewards: {
      rewards: Array<{
        pubkey: string;
        lamports: string;                          // u64 as string
        rewardType: string;                        // "fee" | "rent" | "voting" | "staking"
      }>;
      numPartitions: number | null;
    };
    blockTime: { timestamp: string };              // Unix seconds as a u64 string
    blockHeight: { blockHeight: string };          // u64 as string, wrapped
    parentSlot: string;                            // u64 as string
    parentBlockhash: string;
    executedTransactionCount: string;              // u64 as string
    entriesCount: string;                          // u64 as string
  }
  ```

  <Tip>
    숫자 필드 (슬롯, parentSlot, executedTransactionCount, entriesCount, `blockHeight` 및 `blockTime` 내의 값)는 기본 proto에서 u64이기 때문에 문자열로 방출됩니다. 산술 또는 비교를 위해 `Number(...)`로 감싸세요.
  </Tip>
</Accordion>

<Accordion title="전체 블록 구조">
  ```typescript theme={"system"}
  {
    slot: string;                                  // u64 as string
    blockhash: string;
    rewards: {
      rewards: Array<{
        pubkey: string;
        lamports: string;                          // u64 as string
        rewardType: string;
      }>;
      numPartitions: number | null;
    };
    blockTime: { timestamp: string };              // Unix seconds (u64 string)
    blockHeight: { blockHeight: string };          // u64 as string, wrapped
    parentSlot: string;                            // u64 as string
    parentBlockhash: string;
    executedTransactionCount: string;              // total executed tx in the block (u64 as string)
    updatedAccountCount: string;                   // total account updates in the block (u64 as string)
    entriesCount: string;                          // u64 as string
    transactions: Array<{
      signature: Buffer;                           // base58-encode for display
      isVote: boolean;
      transaction: TransactionMessage;             // full transaction payload
      meta: TransactionMeta;                       // execution metadata (fee, err, balances, …)
      index: string;                               // u64 as string
    }>;
    accounts: AccountUpdate[];                     // populated when includeAccounts: true
    entries: Entry[];                              // populated when includeEntries: true
  }
  ```

  전체 블록은 모든 거래 및 계정과 함께 여러 MB가 될 수 있습니다. 동일한 u64-as-string 관례가 적용됩니다 — 숫자 필드를 산술을 위해 `Number(...)`로 감싸세요. 각 거래 내에서 `meta.fee`, `meta.preBalances`, `meta.postBalances` 등도 문자열입니다.
</Accordion>

***

## 성능 고려사항

<CardGroup cols={2}>
  <Card title="슬롯 모니터링" icon="clock">
    경량: 매우 낮은 대역폭, 최소 처리 오버헤드. 모니터링 대시보드에 적합합니다.
  </Card>

  <Card title="블록 메타데이터" icon="info">
    균형: 중간 대역폭, 전체 데이터 없이 블록 수준 통찰력. 분석에 적합합니다.
  </Card>

  <Card title="전체 블록" icon="database">
    대량: 전체 거래 데이터, 강력한 처리 필요. 항상 필터와 함께 사용하세요.
  </Card>

  <Card title="필터링 된 블록" icon="filter">
    최적화: `accountInclude` 사용, 필요하지 않은 `includeAccounts`/`includeEntries` 비활성화.
  </Card>
</CardGroup>

***

## 사용 사례

<Tabs>
  <Tab title="네트워크 모니터링">
    네트워크 상태 및 성능 추적 — 슬롯 타이밍, 혼잡, 합의.

    ```typescript theme={"system"}
    const targetSlotTime = 400; // ms
    const tolerance = 200; // ms
    if (Math.abs(slotTime - targetSlotTime) > tolerance) {
      console.log(`Network performance issue detected`);
    }
    ```
  </Tab>

  <Tab title="분석 및 메트릭">
    블록체인 분석 데이터 수집 — 거래량, 수수료 분석, 블록 크기, 활동 패턴.

    ```typescript theme={"system"}
    const dailyStats = {
      date: new Date().toDateString(),
      totalTransactions: 0,
      totalFees: 0,
      blockCount: 0
    };
    ```
  </Tab>

  <Tab title="응용 프로그램 동기화">
    네트워크와 응용 프로그램 동기화 유지 — 슬롯 기반 업데이트, 블록 확인.

    ```typescript theme={"system"}
    if (data.slot && data.slot.status === 'finalized') {
      updateApplicationState(data.slot.slot);
    }
    ```
  </Tab>
</Tabs>

***

## 오류 처리

<Accordion title="누락된 슬롯">
  **증상:** 슬롯 진행 중 간격.

  **원인:** 네트워크 연결 문제, 검증자 다운타임, 클라이언트 처리 지연.

  **해결책:** 슬롯 간격 추적 및 경보 설정; [이전 재생](/docs/ko/laserstream/historical-replay)을 통해 복구 논리 구현; 연결 상태 모니터링.
</Accordion>

<Accordion title="대량 데이터">
  **증상:** 너무 많은 블록 데이터.

  **해결책:** 전체 블록 대신 블록 메타데이터 사용; 계정 필터 적용; 불필요한 포함 비활성화 (엔트리, 계정); 비동기 처리.
</Accordion>

<Accordion title="타이밍 문제">
  **증상:** 일관되지 않은 슬롯 타이밍.

  **분석:** 이동 평균 계산; 편차 추적; 네트워크 상태 지표 모니터링; 검증자 성능과의 상관관계.
</Accordion>

***

## 모범 사례

<Note>
  **프로덕션 지침:**

  * **메타데이터로 시작하세요** — 전체 블록 구독 전에 블록 메타데이터 사용
  * **필터 적용** — `accountInclude`을 사용하여 관련 없는 데이터 드롭
  * **타이밍 모니터링** — 슬롯 진행을 네트워크 상태 경계로 추적
  * **간격 처리** — [이전 재생](/docs/ko/laserstream/historical-replay)과 결합하여 누락된 슬롯이 자동으로 다시 채워지도록 함
  * **비동기 처리** — 무거운 연산으로 스트림 처리를 차단하지 않음
  * **필요에 맞는 커밋 사용** — 낮은 지연 UI에는 `processed`, 상태 쓰기에는 `confirmed`/`finalized` 사용
</Note>

***

## 다음 단계

<CardGroup cols={2}>
  <Card title="거래 모니터링" icon="receipt" href="/docs/ko/laserstream/guides/transaction-monitoring">
    프로그램, 계정, 투표 또는 실패 상태로 거래 필터링.
  </Card>

  <Card title="스트림 펌프 AMM 데이터" icon="chart-line" href="/docs/ko/laserstream/guides/stream-pump-amm-data">
    실제 사례: 펌프 AMM 거래 모니터링.
  </Card>

  <Card title="거래 데이터 디코딩" icon="binary" href="/docs/ko/laserstream/guides/decoding-transaction-data">
    바이너리 `transactionUpdate` 페이로드를 읽을 수 있는 Solana 거래로 구문 분석.
  </Card>

  <Card title="옐로스톤 프로토콜 참고서" icon="book" href="/docs/ko/grpc/slot-and-block-monitoring">
    원시 Yellowstone gRPC 프로토콜에 대한 동일한 워크플로.
  </Card>
</CardGroup>
