Solana Geyser gRPC - 过滤器

Solana Stream SDK
Solana Stream SDK 作为开源软件提供。更多详情请访问以下 GitHub 仓库。

gRPC 过滤器概述

Solana Geyser gRPC 使用过滤器高效获取您感兴趣的数据,如特定账户、程序、交易、slot 和区块。
以下是使用 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" 是客户端自定义的标签。
  • 账户、程序、区块和 slot 的多个过滤器可以在单个 JSON 请求中组合使用。

使用 account_data_slice 订阅账户

此示例演示仅检索账户数据的特定部分。不获取 USDC 代币账户的全部数据(165 字节),而是从偏移量 32 开始检索 40 字节。此范围包含所有者和 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,
}

订阅所有已最终确认的非投票且未失败的交易

此示例演示以 Finalized 确认级别订阅所有交易,排除投票交易和失败交易。
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 排除投票交易。
  • failed: false 排除失败交易。
  • 如果字段留空,将检索所有交易。
  • 指定多个字段时,它们以 AND 条件运行。

订阅涉及特定账户的非投票交易

此示例演示订阅涉及特定账户但排除投票交易的交易。
以下示例订阅涉及 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,
}

订阅排除特定账户的交易

此示例演示订阅排除涉及特定账户的交易。
以下示例检索排除 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,
}

订阅交易签名

此示例演示订阅特定交易签名的实时更新,直到它达到 ConfirmedFinalized 状态。
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

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

订阅 slot

此示例演示订阅传入 slot 的通知。除了分配自定义标签名称外,无需其他详细信息:
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 确认级别。
您可以指定更高的确认级别,如 ConfirmedFinalized。在这些情况下,Geyser 会缓冲数据并在达到指定的确认级别后发送通知。
为获得最佳性能,建议在客户端管理确认级别。
以下是指定确认级别的方法:
typescript
import { CommitmentLevel } from '@validators-dao/solana-stream-sdk'

enum CommitmentLevel {
  PROCESSED = 0,
  CONFIRMED = 1,
  FINALIZED = 2,
}
  • PROCESSED:处理后的即时数据。检索速度快,但尚未确认。
  • CONFIRMED:经集群确认的数据,提供更高的确定性。
  • FINALIZED:完全最终确认的数据,没有重组风险。

使用 Processed 的优势

Processed 确认级别的主要优势是即时交易检索,能够快速进行客户端处理。客户端随后可以检测到向 ConfirmedFinalized 的转换,提供快速响应能力。

如何管理 ConfirmedFinalized

使用 ConfirmedFinalized 级别时,应按 slot 缓冲事件(交易或账户更新)。
按 slot 缓冲事件,订阅 slot 通知,并在特定 slot 达到所需确认级别(ConfirmedFinalized)后从缓冲区释放事件。
事件最初会在 slot 达到 ConfirmedFinalized 之前接收。

Finalized 的特殊之处

由于 Solana Geyser 规范,并非所有 slot 都会收到明确的最终确认通知。因此,当您收到某个 slot 的最终确认通知时,必须将所有祖先 slot 也视为已最终确认,即使没有收到明确的通知。
具体来说,收到最终确认通知后,追溯地将所有祖先 slot 视为已最终确认。