Solana Geyser gRPC - Filters

Solana Stream SDK распространяется как open-source software. Подробнее см. в репозитории GitHub ниже.
Обзор gRPC Filters
Solana Geyser gRPC использует filters, чтобы эффективно получать только интересующие вас данные: конкретные accounts, programs, transactions, slots и blocks.
Ниже приведены TypeScript-примеры на базе Solana Stream SDK с пояснением конкретной роли каждого filter. При использовании Rust структура и смысл filters полностью совпадают.
Назначение и примеры каждого filter
Подписка на account
Подписка на обновления конкретного account в реальном времени. Следующий пример подписывается на SOL-USDC OpenBook account на уровне 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,
}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, задаваемый клиентом.- Несколько filters для accounts, programs, blocks и slots можно объединить в одном JSON request.
Подписка на account с account_data_slice
Этот пример показывает, как получать только определенную часть account data. Вместо загрузки всех данных USDC token account (165 bytes) здесь извлекаются 40 bytes, начиная с offset 32. Этот диапазон включает информацию, такую как owner и balance в 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 }],
}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 }],
}Подписка на program
Этот пример показывает, как подписаться на обновления accounts, связанных с конкретным program.
Ниже мы подписываемся на обновления 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,
}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, который клиент может задать произвольно.- Чтобы подписаться сразу на несколько programs, см. следующий раздел "Подписка на несколько programs".
Подписка на несколько programs
Этот пример показывает, как одновременно подписаться на обновления accounts, связанных с несколькими programs.
В примере ниже оформлена подписка на обновления accounts, принадлежащих и 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,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {
slots: {},
},
accounts: {
programs: {
owner: [
'So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo',
'9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin',
],
},
},
transactions: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}Если вам удобнее назначить отдельный label каждому 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,
}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,
}Подписка на все finalized non-vote и 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,
}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.
Подписка на non-vote transactions, упоминающие 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,
}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,
}Подписка на transactions с исключением 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,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {
slots: {},
},
accounts: {},
transactions: {
serum: {
accountExclude: [
'9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin',
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
],
},
},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}Подписка на transactions, упоминающие accounts, с одновременным исключением отдельных 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,
}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,
}Подписка на signature transaction
Этот пример показывает подписку на обновления конкретной 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,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {},
accounts: {},
transactions: {
sign: {
signature:
'5rp2hL9b6kexex11Mugfs3vfU9GhieKruj4CkFFSnu52WLxiGn4VcLLwsB62XURhMmT1j4CZiXT6FFtYbXsLq2Zs',
},
},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}Подписка на slots
Этот пример показывает подписку на уведомления о входящих slots. Никакие дополнительные параметры не нужны, кроме пользовательского tag name:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {
incoming_slots: {},
},
accounts: {},
transactions: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {
incoming_slots: {},
},
accounts: {},
transactions: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}Подписка на blocks
Подписка на обновления всех генерируемых blocks в реальном времени. По умолчанию будут получены все transactions внутри block:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {},
accounts: {},
transactions: {},
blocks: {
blocks: {},
},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {},
accounts: {},
transactions: {},
blocks: {
blocks: {},
},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}Чтобы исключить transactions и получать только обновленную информацию об accounts:
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,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {},
accounts: {},
transactions: {},
blocks: {
blocks: {
includeTransactions: false,
includeAccounts: true,
},
},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}Чтобы получать только transactions/accounts, затрагивающие конкретные accounts:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {},
accounts: {},
transactions: {},
blocks: {
blocks: {
accountInclude: ['So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo'],
},
},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {},
accounts: {},
transactions: {},
blocks: {
blocks: {
accountInclude: ['So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo'],
},
},
blocksMeta: {},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}Подписка на metadata block
Подписка только на уведомления о metadata block по мере обработки blocks. Подробные transaction data не включаются.
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {},
accounts: {},
transactions: {},
blocks: {},
blocksMeta: {
blockmetadata: {},
},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
const request = {
slots: {},
accounts: {},
transactions: {},
blocks: {},
blocksMeta: {
blockmetadata: {},
},
accountsDataSlice: [],
commitment: CommitmentLevel.PROCESSED,
}Управление уровнями commitment
По умолчанию stream Solana Geyser gRPC использует уровень commitment
Processed.Вы можете указать более высокий уровень commitment, например
Confirmed или Finalized. В этих случаях Geyser буферизует данные и отправляет уведомления, когда достигается указанный уровень commitment.Для максимальной производительности рекомендуется управлять уровнями commitment на стороне клиента.
Вот как задаются уровни commitment:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
enum CommitmentLevel {
PROCESSED = 0,
CONFIRMED = 1,
FINALIZED = 2,
}import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'
enum CommitmentLevel {
PROCESSED = 0,
CONFIRMED = 1,
FINALIZED = 2,
}PROCESSED: данные сразу после обработки. Получение максимально быстрое, но данные еще не подтверждены.CONFIRMED: данные подтверждены кластером, что дает большую определенность.FINALIZED: полностью finalized data без риска reorganization.
Преимущества работы на уровне Processed
Главное преимущество уровня commitment
Processed - немедленное получение transactions, что позволяет очень быстро обрабатывать их на стороне клиента. Затем клиент может отслеживать переход в Confirmed или Finalized, сохраняя высокую отзывчивость.Как управлять Confirmed и Finalized
При использовании уровней
Confirmed или Finalized events (transactions или account updates) следует буферизовать по slot.Буферизуйте events по slot, подпишитесь на slot notifications и выпускайте events из buffer, когда конкретный slot достигает нужного commitment (
Confirmed или Finalized).Изначально events приходят до того, как slot достигает
Confirmed или Finalized.Особенность Finalized
Из-за особенностей спецификации Solana Geyser не все slots получают явные finalized notifications. Поэтому, когда вы получаете finalized notification для slot, вы должны считать finalized также все ancestor slots, даже если для них не пришло явных notifications.
Иными словами, при получении finalized notification нужно ретроактивно считать finalized все ancestor slots.