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

# Справочник протокола Jetstream v2

> Спецификация Protocol Buffer для OrbitFlare Jetstream v2

## Доступные эндпоинты

Jetstream v2 обслуживается на **тех же эндпоинтах, что и v1** — отдельного хоста нет. Сервис
`JetstreamV2` предоставляется через то же HTTP/2-соединение и маршрутизируется по пути gRPC-метода,
поэтому вы подключаетесь к региону, ближайшему к вашей инфраструктуре, точно так же, как и для v1.

<Tabs>
  <Tab title="США">
    | Город          | Идентификатор региона | Эндпоинт                              |
    | -------------- | --------------------- | ------------------------------------- |
    | Нью-Йорк       | `ny`                  | `http://ny.jetstream.orbitflare.com`  |
    | Солт-Лейк-Сити | `slc`                 | `http://slc.jetstream.orbitflare.com` |
  </Tab>

  <Tab title="Европа">
    | Город         | Идентификатор региона | Эндпоинт                               |
    | ------------- | --------------------- | -------------------------------------- |
    | Франкфурт     | `fra`                 | `http://fra.jetstream.orbitflare.com`  |
    | Амстердам     | `ams`                 | `http://ams.jetstream.orbitflare.com`  |
    | Лондон        | `lon`                 | `http://lon.jetstream.orbitflare.com`  |
    | Дублин        | `dub`                 | `http://dub.jetstream.orbitflare.com`  |
    | Шяуляй, Литва | `siau`                | `http://siau.jetstream.orbitflare.com` |
  </Tab>

  <Tab title="Азиатско-Тихоокеанский регион">
    | Город    | Идентификатор региона | Эндпоинт                              |
    | -------- | --------------------- | ------------------------------------- |
    | Токио    | `jp`                  | `http://jp.jetstream.orbitflare.com`  |
    | Сингапур | `sgp`                 | `http://sgp.jetstream.orbitflare.com` |
  </Tab>
</Tabs>

<Note>
  Jetstream использует обычный `http://` (не `https://`) для gRPC-соединений. gRPC согласовывает
  собственную безопасность транспорта через HTTP/2. Используйте `https://` только если ваш выделенный
  узел явно этого требует.
</Note>

## Аутентификация

Аутентификация такая же, как в v1: укажите ваш API-ключ в gRPC-заголовке метаданных `x-token` или
используйте аутентификацию по белому списку IP. Подробнее см. в разделе
[Аутентификация](/ru/authentication).

## Спецификация Protocol Buffer

Этот документ описывает спецификацию Protocol Buffer (protobuf), используемую OrbitFlare Jetstream v2.
Полную спецификацию можно найти в нашем [репозитории на GitHub](https://github.com/orbitflare/orbitflare-sdk-proto-rs/blob/HEAD/protos/jetstream_v2.proto) —
скачайте там `jetstream_v2.proto`, чтобы сгенерировать ваш клиент, или используйте определение,
воспроизведённое ниже. Пакет `jetstream.v2` полностью независим от v1 — сгенерируйте из него отдельный
клиент.

### Определение сервиса

```protobuf theme={null}
syntax = "proto3";

package jetstream.v2;

import "google/protobuf/timestamp.proto";

service JetstreamV2 {
  rpc SubscribeTransactions(stream SubscribeTransactionsRequest) returns (stream SubscribeTransactionsResponse) {}

  // Server-streaming slot lifecycle events.
  rpc SubscribeSlots(SubscribeSlotsRequest) returns (stream SlotEvent) {}

  // Unary health/version probes.
  rpc Ping(PingRequest) returns (PongResponse) {}
  rpc GetVersion(GetVersionRequest) returns (GetVersionResponse) {}
}
```

### Сообщения запросов

`SubscribeTransactions` — это двунаправленный поток. Клиент отправляет последовательность сообщений
запросов — каждое несёт ровно одну полезную нагрузку — чтобы управлять своей подпиской, пока поток
открыт.

#### SubscribeTransactionsRequest

```protobuf theme={null}
message SubscribeTransactionsRequest {
  oneof payload {
    Ping          ping           = 1;
    AddFilters    add_filters    = 2;
    RemoveFilters remove_filters = 3;
  }
}

message Ping {
  int32 ping_id = 1;
}
```

#### Добавление фильтров

Фильтры добавляются динамически, пока поток открыт. Каждый фильтр несёт выбранный клиентом
`filter_id`, который возвращается в каждой совпавшей транзакции и в подтверждении валидации.

```protobuf theme={null}
message AddFilters {
  repeated TxFilter filters = 1;
}

message TxFilter {
  string                             filter_id = 1;  // client-provided, max 127 chars
  SubscribeRequestFilterTransactions filter    = 2;
}

message SubscribeRequestFilterTransactions {
  repeated string account_include  = 1;
  repeated string account_exclude  = 2;
  repeated string account_required = 3;
  // account_required matches a tx that references AT LEAST ONE of these accounts
  // (any-of — identical to account_include, and identical to v1). It is NOT the
  // "tx must contain ALL of these accounts" meaning.

  // Opt-in enrichment. Default false = lean response (core fields only). Set
  // true to also receive fee_payer / writable_accounts / program_ids /
  // compute_unit_price / compute_limit / tx_size. Applies to the whole
  // subscription: if any of your active filters sets this true, every
  // transaction you receive is enriched.
  bool include_enrichment = 4;
}
```

<Note>
  Фильтр должен указывать хотя бы один из `account_include` / `account_exclude` / `account_required`.
  Пустые (совпадающие со всем) фильтры отклоняются — см. [FilterResult](#filter-validation).
</Note>

#### Удаление фильтров

```protobuf theme={null}
message RemoveFilters {
  repeated string filter_ids = 1;
}
```

### Сообщения ответов

#### SubscribeTransactionsResponse

Каждое сообщение в потоке несёт серверную временную метку и монотонно возрастающий номер `sequence`
(на поток), чтобы клиенты могли обнаруживать пропуски. Устанавливается ровно одна полезная нагрузка.

```protobuf theme={null}
message SubscribeTransactionsResponse {
  google.protobuf.Timestamp created_at = 1;

  oneof payload {
    FilteredTransaction transaction       = 2;
    Pong                pong              = 3;
    FilterResult        filter_validation = 5;
    Heartbeat           heartbeat         = 6;
  }

  uint64 sequence = 4;
}

message Pong {
  int32 ping_id = 1;
}
```

#### Валидация фильтров

После каждого `AddFilters` / `RemoveFilters` сервер возвращает один `FilterResult` на каждый фильтр,
подтверждая принятие или объясняя отклонение.

```protobuf theme={null}
message FilterResult {
  string filter_id        = 1;
  bool   accepted         = 2;
  string rejection_reason = 3;  // empty string when accepted=true (proto3 default elision)
}
```

#### Heartbeat

```protobuf theme={null}
message Heartbeat {
  // Server wall-clock at emit time, milliseconds since Unix epoch. Lets
  // clients measure one-way skew / network delay and age out stale
  // connections.
  uint64 server_ts_ms = 1;
}
```

#### Отфильтрованная транзакция

Каждая совпавшая транзакция перечисляет значения `filter_id`, с которыми она совпала, за которыми
следует сама транзакция.

```protobuf theme={null}
message FilteredTransaction {
  repeated string    filter_ids  = 1;
  TransactionMessage transaction = 2;
}

// TransactionMessage — a flat transaction representation (all fields inline).
// Fields 1-13 are the core transaction and are always present (the default
// "lean" output). Fields 14-22 are optional enrichment, emitted only when the
// session opts in via SubscribeRequestFilterTransactions.include_enrichment.
message TransactionMessage {
  // Identity / placement
  uint64 slot      = 1;
  bytes  signature = 2;  // primary signature (signatures[0])
  uint32 tx_index  = 3;  // position of this tx within its entry

  // Full signature set (repeated bytes)
  repeated bytes signatures = 4;

  // Always false: vote transactions are filtered out and never delivered (v1 and v2).
  bool is_vote = 5;

  // Message header
  uint32 num_required_signatures        = 6;
  uint32 num_readonly_signed_accounts   = 7;
  uint32 num_readonly_unsigned_accounts = 8;

  // Recent blockhash
  bytes recent_blockhash = 9;

  // Versioned-transaction flag.
  bool versioned = 10;

  // Core body contents
  repeated bytes                     account_keys          = 11;
  repeated CompiledInstruction       instructions          = 12;
  repeated MessageAddressTableLookup address_table_lookups = 13;

  // Enrichment — emitted only when the session opts in via
  // SubscribeRequestFilterTransactions.include_enrichment.
  bytes          fee_payer         = 14;
  repeated bytes writable_accounts = 15;
  repeated bytes program_ids       = 16;
  // Compute-unit price (micro-lamports per CU) from SetComputeUnitPrice; 0 if unset.
  // The per-CU price, NOT the total priority fee — total priority fee in lamports
  // ~= compute_unit_price * compute_limit / 1_000_000.
  uint64         compute_unit_price = 17;
  // Explicit SetComputeUnitLimit only; 0 if the tx sets none (no implicit
  // 200k-CU-per-instruction default is applied).
  uint32         compute_limit     = 18;
  uint32         tx_size           = 19;

  // Resolved addresses from a versioned tx's address_table_lookups. Emitted
  // only when enrichment is opted in (same gate as fields 14-19). Empty for a
  // legacy (non-versioned) tx; when a lookup can't be fully resolved,
  // alt_resolution_incomplete (field 22) is set and any addresses that did
  // resolve are still included.
  repeated bytes loaded_writable_addresses = 20;
  repeated bytes loaded_readonly_addresses = 21;

  // Set true when one or more of this transaction's address_table_lookups could
  // NOT be fully resolved, so the loaded_writable_addresses /
  // loaded_readonly_addresses above are INCOMPLETE. When true, resolve the tx's
  // accounts yourself from address_table_lookups (fetch the tables via
  // RPC). Default false = fully resolved. Emitted only under
  // enrichment (same gate as fields 14-21).
  bool alt_resolution_incomplete = 22;
}
```

#### Общие типы

```protobuf theme={null}
message CompiledInstruction {
  uint32 program_id_index = 1;
  bytes  accounts         = 2;
  bytes  data             = 3;
}

message MessageAddressTableLookup {
  bytes account_key      = 1;
  bytes writable_indexes = 2;
  bytes readonly_indexes = 3;
}
```

### Потоковая передача слотов

`SubscribeSlots` — это серверный поток событий жизненного цикла слотов. Он не принимает параметров —
откройте поток и получайте события по мере продвижения слотов.

```protobuf theme={null}
// SubscribeSlots takes no request parameters.
message SubscribeSlotsRequest {
}

enum SlotStatus {
  SLOT_STATUS_UNSPECIFIED = 0;
  SLOT_STATUS_ALIVE       = 1;  // first shred of this slot received
  SLOT_STATUS_COMPLETE    = 2;  // last shred of this slot received
  SLOT_STATUS_DEAD        = 3;  // slot skipped, or superseded by later slots without completing
}

message SlotEvent {
  uint64     slot           = 1;
  SlotStatus status         = 2;
  // 32-byte pubkey. Empty bytes (proto3 default) means the current leader is
  // unavailable.
  bytes      current_leader = 3;
  // Parent slot, from the first shred received for this slot. 0 means
  // "unknown parent" (e.g. a DEAD event for a slot that was never observed).
  uint64     parent_slot    = 4;
  uint64     sequence       = 5;  // monotonic per-stream
}
```

### Нестриминговые методы

```protobuf theme={null}
message PingRequest {
  int32 count = 1;
}

message PongResponse {
  int32 count = 1;
}

message GetVersionRequest {}

message GetVersionResponse {
  string version = 1;
}
```

## Использование протокола

Типичный клиент v2:

1. Сгенерируйте клиентский код из определения `jetstream.v2` выше.
2. Откройте двунаправленный поток `SubscribeTransactions` и аутентифицируйтесь (заголовок `x-token`
   или белый список IP).
3. Отправьте запрос `AddFilters` с одним или несколькими элементами `TxFilter`, каждый с уникальным
   `filter_id`.
4. Прочитайте подтверждения `FilterResult`, затем поток сообщений `FilteredTransaction`.
5. Добавляйте или удаляйте фильтры в любой момент без повторного открытия потока.
6. Отслеживайте `sequence` для обнаружения пропусков и рассматривайте закрытие соединения как сигнал
   к переподключению.
7. При необходимости откройте `SubscribeSlots` (отдельный поток) для событий жизненного цикла слотов.

### Генерация кода

Для TypeScript/JavaScript:

```bash theme={null}
protoc --plugin=protoc-gen-ts_proto=./node_modules/.bin/protoc-gen-ts_proto \
  --ts_proto_out=. \
  --ts_proto_opt=esModuleInterop=true \
  jetstream_v2.proto
```

Для Rust:

```bash theme={null}
protoc --rust_out=. jetstream_v2.proto
```

## Лучшие практики

1. **Фильтрация**
   * Всегда задавайте хотя бы одно ограничение по аккаунту; пустые фильтры отклоняются.
   * Используйте стабильный, уникальный `filter_id` для каждого фильтра, чтобы вы могли сопоставлять совпадения и удалять фильтры позже.

2. **Обогащение**
   * Держите `include_enrichment` выключенным, если вам не нужны дополнительные поля — экономный вывод
     меньше. Его включение не добавляет задержки; единственная цена — умеренно больший размер сообщения.
   * Обогащение действует на всю подписку: его включение на любом одном фильтре обогащает каждую транзакцию, которую получает сессия.

3. **Последовательность и переподключение**
   * Отслеживайте номер `sequence` для обнаружения потерянных сообщений.
   * Реализуйте автоматическое переподключение; при переподключении повторно отправляйте ваш `AddFilters`.

4. **Живость**
   * Используйте `Heartbeat` и `Ping`/`Pong`, чтобы подтвердить, что поток исправен, и измерять задержку.

## Смотрите также

<CardGroup cols={2}>
  <Card title="Обзор Jetstream v2" icon="bolt" href="/ru/data-streaming/jetstream-v2">
    Что v2 добавляет по сравнению с v1, модель потоковой передачи и начало работы.
  </Card>

  <Card title="Справочник Jetstream (v1)" icon="book" href="/ru/data-streaming/jetstream-reference">
    Спецификация Protocol Buffer для v1.
  </Card>
</CardGroup>

## Поддержка

По техническим вопросам о протоколе v2 или деталях реализации присоединяйтесь к нашему
[сообществу в Discord](https://discord.gg/orbitflare).
