Solana Geyser gRPC - Filters

Solana Stream SDK
Solana Stream SDK предоставляется как open-source software. Для более подробной информации посетите GitHub repository ниже.

Overview of gRPC Filters

Solana Geyser gRPC использует filters, чтобы эффективно получать только те данные, которые вас интересуют, например определенные accounts, programs, transactions, slots и blocks.
Ниже приведены примеры на TypeScript с использованием Solana Stream SDK и четким объяснением конкретной роли каждого filter. При использовании Rust структура и значение filters полностью идентичны.

Roles and Examples of Each Filter

Subscribe to an account

Подпишитесь на updates в реальном времени для конкретного account. В следующем примере выполняется подписка на account SOL-USDC OpenBook на уровне commitment Confirmed:
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" - label, задаваемый client.
  • Несколько filters для accounts, programs, blocks и slots можно объединять в одном JSON request.

Subscribe to an account with account_data_slice

Этот пример показывает, как получать только определенную часть данных account. Вместо получения всех данных account USDC token (165 bytes) он получает 40 bytes, начиная со смещения 32. Этот диапазон включает такую информацию, как 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 }],
}

Subscribe to a program

Этот пример показывает подписку на updates account, связанные с конкретным program.
Ниже мы подписываемся на updates account для accounts, принадлежащих program Solend, на уровне commitment Processed.
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" - пользовательский label, который client может задавать произвольно.
  • Чтобы подписаться на несколько programs, перейдите к следующему разделу "Subscribe to multiple programs".

Subscribe to multiple programs

Этот пример показывает, как подписаться сразу на updates account, связанные с несколькими programs.
В примере ниже выполняется подписка на updates для accounts, принадлежащих programs 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,
}
Если вы предпочитаете назначать отдельные labels для каждого program, используйте следующий подход:
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,
}

Subscribe to all finalized non-vote and non-failed transactions

Этот пример показывает подписку на все transactions на уровне commitment Finalized, исключая vote-transactions и failed transactions.
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-transactions.
  • failed: false исключает failed transactions.
  • Если поля оставить пустыми, будут получены все transactions.
  • Когда указано несколько полей, они работают по условию AND.

Subscribe to non-vote transactions mentioning an account

Этот пример показывает подписку на transactions, в которых участвует определенный account, но без vote-transactions.
В примере ниже выполняется подписка на non-vote transactions, упоминающие accounts, связанные с program Serum.
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,
}

Subscribe to transactions excluding accounts

Этот пример показывает подписку на transactions, исключая те, которые затрагивают определенные accounts.
В примере ниже получаются transactions, исключающие любые accounts, которыми владеют programs 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,
}

Subscribe to transactions mentioning accounts & excluding certain accounts

Этот пример показывает подписку на transactions, связанные с определенными accounts, при этом явно исключая другие указанные accounts.
В примере ниже выполняется подписка на transactions, упоминающие account Serum, но исключающие указанный account:
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,
}

Subscribe to a transaction signature

Этот пример показывает подписку на updates в реальном времени для конкретной transaction signature, пока она не достигнет состояния 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,
}

Subscribe to slots

Этот пример показывает подписку на уведомления о входящих slots. Никаких дополнительных деталей не требуется, кроме назначения пользовательского имени тега:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

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

Subscribe to blocks

Подпишитесь на updates в реальном времени для всех создаваемых blocks. По умолчанию будут получены все transactions внутри block:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

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

To exclude transactions and only retrieve updated account information:

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,
}

To only retrieve transactions/accounts involving specific accounts:

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

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

Subscribe to block metadata

Подписка только на уведомления metadata block при обработке blocks. Подробные данные transactions не включаются.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

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

Managing commitment levels

Поток Solana Geyser gRPC по умолчанию использует уровень commitment Processed.
Вы можете указать более высокие уровни commitment, такие как Confirmed или Finalized. В этом случае Geyser буферизует данные и отправляет уведомления, когда достигается указанный уровень commitment.
Для максимальной производительности рекомендуется управлять уровнями commitment на стороне client.
Вот как указывать уровни commitment:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

enum CommitmentLevel {
  PROCESSED = 0,
  CONFIRMED = 1,
  FINALIZED = 2,
}
  • PROCESSED: Немедленные данные после обработки. Получение быстрое, но данные еще не подтверждены.
  • CONFIRMED: Данные подтверждены cluster, что обеспечивает большую уверенность.
  • FINALIZED: Полностью finalized данные без риска reorganization.

Benefits of working at Processed

Главное преимущество уровня commitment Processed заключается в немедленном получении transactions, что позволяет быстро обрабатывать их на стороне client. Затем client может отслеживать переходы к Confirmed или Finalized, сохраняя высокую отзывчивость.

How to manage Confirmed and Finalized

При использовании уровней Confirmed или Finalized events (transactions или updates account) следует буферизовать по slot.
Буферизуйте events по slot, подпишитесь на уведомления slots и выпускайте events из buffer, когда конкретный slot достигает требуемого commitment (Confirmed или Finalized).
Сначала events будут получены до того, как slot достигнет Confirmed или Finalized.

The special thing about Finalized

Из-за спецификации Solana Geyser не все slots получают явные finalized уведомления. Поэтому, когда вы получаете finalized уведомление для slot, вы должны считать finalized все ancestor slots, даже если для них уведомления явно не приходили.
Точнее, при получении finalized уведомления нужно ретроактивно считать finalized все ancestor slots.