# RPC blockSubscribe (Carbon 2.0)

> Receive every confirmed block, or only transactions that mention a program, over a Solana RPC WebSocket with blockSubscribe.

`RpcBlockSubscribe` opens a `blockSubscribe` WebSocket subscription and emits a block-details update for every block, followed by a transaction update for each successful transaction in it. Use it for live transactions from an RPC node that has block subscriptions enabled, when you don't have a Geyser gRPC endpoint.

> **Warning: Not available on the public endpoint.** `api.mainnet-beta.solana.com` rejects `blockSubscribe` with `Method not found (-32601)`. You need a node started with `--rpc-pubsub-enable-block-subscription`, or a provider that offers the method.

|          |                                                                                                                                                          |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Crate    | `carbon-rpc-block-subscribe-datasource` 2.0.0                                                                                                            |
| Install  | `cargo add carbon-rpc-block-subscribe-datasource@2.0.0`                                                                                                  |
| Emits    | `BlockDetails`, `Transaction`. `update_types()` declares only `Transaction`.                                                                             |
| Mode     | Live. Runs until cancelled.                                                                                                                              |
| Provider | An RPC WebSocket endpoint that supports `blockSubscribe`.                                                                                                |
| API docs | [docs.rs](https://docs.rs/carbon-rpc-block-subscribe-datasource/2.0.0/carbon_rpc_block_subscribe_datasource/)                                            |
| Source   | [`datasources/rpc-block-subscribe-datasource`](https://github.com/sevenlabs-hq/carbon/blob/v2.0.0/datasources/rpc-block-subscribe-datasource/src/lib.rs) |

## Quick example

This program subscribes to confirmed blocks that mention the Orca Whirlpool program, prints each block and each `swapV2` instruction. It compiles as shown; to run it, set `RPC_WS_URL` to an endpoint that supports `blockSubscribe`.

```sh
cargo new block-subscribe && cd block-subscribe
cargo add carbon-core@2.0.0 carbon-log-metrics@2.0.0 carbon-orca-whirlpool-decoder@2.0.0 carbon-rpc-block-subscribe-datasource@2.0.0
cargo add solana-client@=4.2.2
cargo add tokio@1 --features full
cargo add env_logger@0.11 log@0.4
```

`src/main.rs`:

```rust
use {
    carbon_core::{
        datasource::BlockDetails, error::CarbonResult,
        instruction::InstructionProcessorInputType, pipeline::Pipeline, processor::Processor,
    },
    carbon_log_metrics::LogMetrics,
    carbon_orca_whirlpool_decoder::{
        instructions::OrcaWhirlpoolInstruction, OrcaWhirlpoolDecoder, PROGRAM_ID,
    },
    carbon_rpc_block_subscribe_datasource::{Filters, RpcBlockSubscribe},
    solana_client::rpc_config::{
        CommitmentConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter, TransactionDetails,
        UiTransactionEncoding,
    },
    std::{env, sync::Arc},
};

#[tokio::main]
async fn main() -> CarbonResult<()> {
    env_logger::init();

    let config = RpcBlockSubscribeConfig {
        commitment: Some(CommitmentConfig::confirmed()),
        encoding: Some(UiTransactionEncoding::Base64), // required: Carbon can't decode JSON payloads
        transaction_details: Some(TransactionDetails::Full),
        show_rewards: Some(false),
        max_supported_transaction_version: Some(1),
    };

    let datasource = RpcBlockSubscribe::new(
        env::var("RPC_WS_URL").expect("RPC_WS_URL must be set"),
        Filters::new(
            RpcBlockSubscribeFilter::MentionsAccountOrProgram(PROGRAM_ID.to_string()),
            Some(config),
        ),
    );

    Pipeline::builder()
        .datasource(datasource)
        .metrics(Arc::new(LogMetrics::new()))
        .instruction(OrcaWhirlpoolDecoder, SwapLogger)
        .block_details(BlockLogger)
        .build()?
        .run()
        .await
}

struct SwapLogger;

impl Processor<InstructionProcessorInputType<'_, OrcaWhirlpoolInstruction>> for SwapLogger {
    async fn process(
        &mut self,
        input: &InstructionProcessorInputType<'_, OrcaWhirlpoolInstruction>,
    ) -> CarbonResult<()> {
        let tx = &input.metadata.transaction_metadata;
        if let OrcaWhirlpoolInstruction::SwapV2 { data, accounts, .. } = input.decoded_instruction {
            println!("slot {} swapV2 pool={} amount={}", tx.slot, accounts.whirlpool, data.amount);
        }
        Ok(())
    }
}

struct BlockLogger;

impl Processor<BlockDetails> for BlockLogger {
    async fn process(&mut self, block: &BlockDetails) -> CarbonResult<()> {
        println!("block {} time={:?} hash={:?}", block.slot, block.block_time, block.block_hash);
        Ok(())
    }
}
```

```sh
RPC_WS_URL=wss://your-node.example.com RUST_LOG=info cargo run
```

Against the public endpoint the subscription is refused and retried every few seconds:

Output:

```text
[ERROR carbon_rpc_block_subscribe_datasource] Failed to subscribe to block updates: SubscribeFailed { reason: "Method not found (-32601)", message: "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32601,\"message\":\"Method not found\"},\"id\":1}" }
```

## Configuration

### Constructors

```rust
pub fn new(rpc_ws_url: String, filters: Filters) -> Self
pub fn with_disconnect_notifier(
    rpc_ws_url: String,
    filters: Filters,
    disconnect_notifier: tokio::sync::mpsc::Sender<DatasourceDisconnection>,
) -> Self
pub fn with_stream_timeout(self, timeout: Duration) -> Self
```

| Field                 | Type                                            | Default                              | Meaning                                                                        |
| --------------------- | ----------------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------ |
| `rpc_ws_url`          | `String`                                        | —                                    | WebSocket endpoint.                                                            |
| `filters`             | `Filters`                                       | —                                    | Block filter and subscription config.                                          |
| `disconnect_notifier` | `Option<mpsc::Sender<DatasourceDisconnection>>` | `None`                               | Receives one event per reconnect with the slot gap. See below.                 |
| `stream_timeout`      | `Duration`                                      | 30 s (`DEFAULT_STREAM_TIMEOUT_SECS`) | With no message for this long, the connection is treated as dead and reopened. |

### `Filters`

```rust
pub const fn new(
    block_filter: RpcBlockSubscribeFilter,
    block_subscribe_config: Option<RpcBlockSubscribeConfig>,
) -> Self
```

`RpcBlockSubscribeFilter` (from `solana_client::rpc_config`) is `All` or `MentionsAccountOrProgram(String)`, the latter taking a base58 address. `RpcBlockSubscribeConfig`:

| Field                               | Type                            | Recommended    | Meaning                                                                                                           |
| ----------------------------------- | ------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------- |
| `commitment`                        | `Option<CommitmentConfig>`      | `confirmed`    | `None` uses the server default (`finalized`).                                                                     |
| `encoding`                          | `Option<UiTransactionEncoding>` | `Some(Base64)` | **Required in practice.** JSON encodings can't be decoded: every transaction logs `Failed to decode transaction`. |
| `transaction_details`               | `Option<TransactionDetails>`    | `Some(Full)`   | Anything else yields no transactions to decode.                                                                   |
| `show_rewards`                      | `Option<bool>`                  | as needed      | Rewards are copied into `BlockDetails.rewards`.                                                                   |
| `max_supported_transaction_version` | `Option<u8>`                    | `Some(1)`      | Needed for blocks with versioned transactions.                                                                    |

### `DatasourceDisconnection`

Sent with `try_send` on the first block after a reconnect: `source` (`"rpc-websocket"`), `disconnect_time`, `last_slot_before_disconnect`, `first_slot_after_reconnect`, `missed_slots`. Use it to trigger a backfill of the gap with [`RpcBlockCrawler`](https://carbon.sevenlabs.org/datasources/rpc-block-crawler.md).

## Behaviour

- **Updates per block.** One `BlockDetails` (slot, block hash, previous block hash, rewards, reward partitions, block time, block height), then one `Transaction` per transaction whose status is `Ok`. Transactions carry the block's `block_time` and `block_hash`, `is_vote: false`, and `index` set to the position in the notification's transaction list. With `MentionsAccountOrProgram` that list contains only matching transactions, so `index` is not the position in the full block.
- **`update_types()`.** Declares only `Transaction`, although `BlockDetails` is emitted too. The pipeline does not check this list, so `.block_details(…)` processors receive the blocks.
- **Reconnects.** On stream close or `stream_timeout`, the datasource waits 3 seconds and reconnects. Connection failures are retried every 3 seconds up to 10 times, subscription failures up to 11 times, then `consume` returns an error. The counter resets after a successful subscription. Missed blocks are not replayed.
- **Backpressure.** Updates use `try_send`. If the `BlockDetails` send fails, the subscription is dropped and reopened. If a transaction send fails, the rest of that block's transactions are dropped. Both log `Error sending …`.
- **Finishing.** Never finishes on its own.
- **Metrics.** `block_subscribe_blocks_received_total`, `block_subscribe_transactions_processed_total` (counters), `block_subscribe_block_process_time_nanoseconds`, `block_subscribe_transaction_process_time_nanoseconds` (histograms).

## Troubleshooting

### `Failed to subscribe to block updates: … Method not found (-32601)`

The endpoint doesn't support `blockSubscribe`. The public mainnet endpoint never does. Use a node with `--rpc-pubsub-enable-block-subscription`, a provider that exposes it, or switch to [Yellowstone gRPC](https://carbon.sevenlabs.org/datasources/yellowstone-grpc.md) or [the block crawler](https://carbon.sevenlabs.org/datasources/rpc-block-crawler.md).

### Every transaction logs `Failed to decode transaction`

Set `encoding: Some(UiTransactionEncoding::Base64)` in `RpcBlockSubscribeConfig`.

### `Block stream timeout - no messages for 30s`

The node stopped sending blocks, often because the filter matched nothing for 30 seconds. With a narrow `MentionsAccountOrProgram` filter on a quiet program, raise the timeout with `.with_stream_timeout(Duration::from_secs(300))`.

### Blocks are missing after a reconnect

Expected: nothing is replayed. Pass a `disconnect_notifier` and backfill `last_slot_before_disconnect..first_slot_after_reconnect` with the block crawler.

## See also

- [Stream with RPC](https://carbon.sevenlabs.org/guides/stream-with-rpc.md)
- [RPC block crawler](https://carbon.sevenlabs.org/datasources/rpc-block-crawler.md)
- [Processor inputs](https://carbon.sevenlabs.org/reference/processor-inputs.md) for `BlockDetails`
- [Datasources concept](https://carbon.sevenlabs.org/concepts/datasources.md) and [update types](https://carbon.sevenlabs.org/concepts/updates.md)

---

Carbon 2.0.0 documentation · Web: https://carbon.sevenlabs.org/datasources/rpc-block-subscribe · Last updated 2026-11-09 · Index of all pages: https://carbon.sevenlabs.org/llms.txt
