Solana Geyser gRPC - 필터

Solana Stream SDK
Solana Stream SDK는 오픈 소스 소프트웨어로 제공됩니다. 자세한 내용은 아래 GitHub 리포지토리를 참조하세요.

gRPC 필터 개요

Solana Geyser gRPC는 필터를 사용하여 특정 계정, 프로그램, 트랜잭션, 슬롯, 블록 등 관심 있는 데이터만 효율적으로 가져옵니다.
아래에서는 Solana Stream SDK를 사용한 TypeScript 예제를 통해 각 필터의 구체적인 역할을 명확히 설명합니다. Rust를 사용하는 경우에도 필터의 구조와 의미는 동일합니다.

각 필터의 역할과 예제

계정 구독

특정 계정의 실시간 업데이트를 구독합니다. 다음 예제는 Confirmed 커밋먼트 레벨에서 SOL-USDC OpenBook 계정을 구독합니다:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: { slots: {} },
  accounts: {
    'wsol/usdc': {
      account: ['8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'],
    },
  },
  transactions: {},
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.CONFIRMED,
}
  • "wsol/usdc"는 클라이언트가 정의한 레이블입니다.
  • 계정, 프로그램, 블록, 슬롯에 대한 여러 필터를 하나의 JSON 요청으로 조합할 수 있습니다.

account_data_slice로 계정 구독

이 예제는 계정 데이터의 특정 부분만 가져오는 방법을 보여줍니다. USDC 토큰 계정의 전체 데이터(165 바이트)를 가져오는 대신, 오프셋 32부터 40 바이트를 가져옵니다. 이 범위에는 owner와 lamports 잔액 등의 정보가 포함됩니다.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {},
  accounts: {
    usdc: {
      owner: ['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'],
      filters: [
        {
          tokenAccountState: true,
        },
        {
          memcmp: {
            offset: 0,
            data: {
              base58: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
            },
          },
        },
      ],
    },
  },
  transactions: {},
  blocks: {},
  blocksMeta: {},
  entry: {},
  commitment: CommitmentLevel.CONFIRMED,
  accountsDataSlice: [{ offset: 32, length: 40 }],
}

프로그램 구독

이 예제는 특정 프로그램에 연결된 계정 업데이트를 구독하는 방법을 보여줍니다.
아래에서는 Processed 커밋먼트 레벨에서 Solend 프로그램이 소유한 계정의 업데이트를 구독합니다.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {
    slots: {},
  },
  accounts: {
    solend: {
      owner: ['So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo'],
    },
  },
  transactions: {},
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}
  • "solend"는 클라이언트가 자유롭게 설정할 수 있는 커스텀 레이블입니다.
  • 여러 프로그램을 구독하려면 다음 섹션 "여러 프로그램 구독"을 참조하세요.

여러 프로그램 구독

이 예제는 여러 프로그램에 연결된 계정 업데이트를 한 번에 구독하는 방법을 보여줍니다.
아래 예제는 Solend와 Serum 두 프로그램이 소유한 계정의 업데이트를 구독합니다.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {
    slots: {},
  },
  accounts: {
    programs: {
      owner: [
        'So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo',
        '9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin',
      ],
    },
  },
  transactions: {},
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}
각 프로그램에 개별 레이블을 지정하려면 다음 방법을 사용하세요:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {
    slots: {},
  },
  accounts: {
    solend: {
      owner: ['So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo'],
    },
    serum: {
      owner: ['9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin'],
    },
  },
  transactions: {},
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

vote 및 실패한 트랜잭션을 제외한 모든 finalized 트랜잭션 구독

이 예제는 Finalized 커밋먼트 레벨에서 vote 트랜잭션과 실패한 트랜잭션을 제외한 모든 트랜잭션을 구독하는 방법을 보여줍니다.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {
    slots: {},
  },
  accounts: {},
  transactions: {
    alltxs: {
      vote: false,
      failed: false,
    },
  },
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.FINALIZED,
}
  • vote: false는 vote 트랜잭션을 제외합니다.
  • failed: false는 실패한 트랜잭션을 제외합니다.
  • 필드를 비워 두면 모든 트랜잭션을 가져옵니다.
  • 여러 필드를 지정하면 AND 조건으로 동작합니다.

계정을 언급하는 vote 아닌 트랜잭션 구독

이 예제는 특정 계정이 관련된 트랜잭션을 구독하되 vote 트랜잭션을 제외하는 방법을 보여줍니다.
아래 예제는 Serum 프로그램에 연결된 계정을 언급하는 vote 아닌 트랜잭션을 구독합니다.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {
    slots: {},
  },
  accounts: {},
  transactions: {
    serum: {
      vote: false,
      accountInclude: ['9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin'],
    },
  },
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

특정 계정을 제외한 트랜잭션 구독

이 예제는 특정 계정이 관련된 트랜잭션을 제외하고 구독하는 방법을 보여줍니다.
아래 예제는 Serum 및 Tokenkeg 프로그램이 소유한 모든 계정을 제외하고 트랜잭션을 가져옵니다.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {
    slots: {},
  },
  accounts: {},
  transactions: {
    serum: {
      accountExclude: [
        '9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin',
        'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
      ],
    },
  },
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

계정 언급 트랜잭션 구독 & 특정 계정 제외

이 예제는 특정 계정이 관련된 트랜잭션을 구독하면서, 지정된 다른 계정은 명시적으로 제외하는 방법을 보여줍니다.
아래 예제는 Serum의 계정을 언급하는 트랜잭션을 구독하되 지정된 계정은 제외합니다:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {
    slots: {},
  },
  accounts: {},
  transactions: {
    serum: {
      accountInclude: ['9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin'],
      accountExclude: ['9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT'],
    },
  },
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

트랜잭션 시그니처 구독

이 예제는 특정 트랜잭션 시그니처의 실시간 업데이트를 Confirmed 또는 Finalized 상태에 도달할 때까지 구독하는 방법을 보여줍니다.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {},
  accounts: {},
  transactions: {
    sign: {
      signature:
        '5rp2hL9b6kexex11Mugfs3vfU9GhieKruj4CkFFSnu52WLxiGn4VcLLwsB62XURhMmT1j4CZiXT6FFtYbXsLq2Zs',
    },
  },
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

슬롯 구독

이 예제는 들어오는 슬롯의 알림을 구독하는 방법을 보여줍니다. 커스텀 태그 이름을 지정하는 것 외에 추가 세부 사항은 필요 없습니다:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {
    incoming_slots: {},
  },
  accounts: {},
  transactions: {},
  blocks: {},
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

블록 구독

생성된 모든 블록의 실시간 업데이트를 구독합니다. 기본적으로 블록 내 모든 트랜잭션이 검색됩니다:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {},
  accounts: {},
  transactions: {},
  blocks: {
    blocks: {},
  },
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

트랜잭션을 제외하고 업데이트된 계정 정보만 가져오기:

typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {},
  accounts: {},
  transactions: {},
  blocks: {
    blocks: {
      includeTransactions: false,
      includeAccounts: true,
    },
  },
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

특정 계정이 관련된 트랜잭션/계정만 가져오기:

typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {},
  accounts: {},
  transactions: {},
  blocks: {
    blocks: {
      accountInclude: ['So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo'],
    },
  },
  blocksMeta: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

블록 메타데이터 구독

블록이 처리될 때 블록 메타데이터 알림만 구독합니다. 자세한 트랜잭션 데이터는 포함되지 않습니다.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

const request = {
  slots: {},
  accounts: {},
  transactions: {},
  blocks: {},
  blocksMeta: {
    blockmetadata: {},
  },
  accountsDataSlice: [],
  commitment: CommitmentLevel.PROCESSED,
}

커밋먼트 레벨 관리

Solana Geyser gRPC 스트림의 기본값은 Processed 커밋먼트 레벨입니다.
Confirmed 또는 Finalized 같은 더 높은 커밋먼트 레벨을 지정할 수 있습니다. 이 경우 Geyser는 데이터를 버퍼링하고 지정된 커밋먼트 레벨에 도달하면 알림을 보냅니다.
최대 성능을 위해서는 클라이언트 측에서 커밋먼트 레벨 관리를 처리하는 것이 권장됩니다.
커밋먼트 레벨을 지정하는 방법은 다음과 같습니다:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

enum CommitmentLevel {
  PROCESSED = 0,
  CONFIRMED = 1,
  FINALIZED = 2,
}
  • PROCESSED: 처리 직후의 즉시 데이터. 빠른 검색이지만 아직 확인되지 않았습니다.
  • CONFIRMED: 클러스터에서 확인된 데이터로, 더 높은 확실성을 제공합니다.
  • FINALIZED: 리오그 위험이 없는 완전히 확정된 데이터입니다.

Processed에서 작업하는 이점

Processed 커밋먼트 레벨의 주요 이점은 즉각적인 트랜잭션 검색으로, 빠른 클라이언트 측 처리를 가능하게 합니다. 클라이언트는 이후 Confirmed 또는 Finalized로의 전이를 감지할 수 있어 빠른 응답성을 제공합니다.

Confirmed와 Finalized를 관리하는 방법

Confirmed 또는 Finalized 레벨을 사용할 때는 이벤트(트랜잭션 또는 계정 업데이트)를 슬롯별로 버퍼링해야 합니다.
이벤트를 슬롯 단위로 버퍼링하고, 슬롯 알림을 구독하고, 특정 슬롯이 원하는 커밋먼트(Confirmed 또는 Finalized)에 도달하면 버퍼에서 이벤트를 해제합니다.
이벤트는 처음에는 슬롯이 Confirmed 또는 Finalized에 도달하기 전에 수신됩니다.

Finalized의 특수성

Solana Geyser 사양상 모든 슬롯이 명시적인 finalized 알림을 받는 것은 아닙니다. 따라서 어떤 슬롯의 finalized 알림을 받으면, 명시적으로 알림을 받지 않은 경우에도 모든 조상 슬롯을 finalized로 처리해야 합니다.
구체적으로, finalized 알림을 받으면 모든 조상 슬롯을 소급하여 finalized로 처리하세요.