# Updates (Carbon 2.0)

> The Update enum that datasources send into a pipeline, its four variants, UpdateType, zero-lamport account deletions, Transaction V1 and block details.

Every piece of data a datasource produces enters the pipeline as a `carbon_core::datasource::Update`. You meet this type when you write a [custom datasource](https://carbon.sevenlabs.org/guides/custom-datasource.md), and its fields show up again in the metadata your processors receive. Full field-by-field details are in the [updates reference](https://carbon.sevenlabs.org/reference/updates.md).

## The `Update` enum

```rust
pub enum Update {
    Account(AccountUpdate),
    Transaction(Box<TransactionUpdate>),
    AccountDeletion(AccountDeletion),
    BlockDetails(BlockDetails),
}
```

| Variant           | Means                                                                                     | Delivered to                                                                   |
| ----------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `Account`         | An account's state at a slot: a write, or a read from a snapshot or `getProgramAccounts`. | `account` pipes, through their decoder                                         |
| `Transaction`     | A transaction with its execution metadata.                                                | `instruction` pipes (one call per decoded instruction) and `transaction` pipes |
| `AccountDeletion` | An account that was closed: its lamports reached zero.                                    | `account_deletions` pipes                                                      |
| `BlockDetails`    | Metadata about a block.                                                                   | `block_details` pipes                                                          |

The pipeline routes each variant only to pipes of the matching kind; [Architecture](https://carbon.sevenlabs.org/concepts/architecture.md#how-each-update-is-processed) gives the exact order.

## Account updates

```rust
pub struct AccountUpdate {
    pub pubkey: Pubkey,
    pub account: Account,
    pub slot: u64,
    pub transaction_signature: Option<Signature>,
}
```

`account` is a `solana_account::Account` with `lamports`, `data`, `owner`, `executable` and `rent_epoch`. `transaction_signature` is the transaction that wrote the account, when the source knows it: Geyser streams usually set it; `getProgramAccounts` and snapshots don't.

## Account deletions

Solana has no explicit "account closed" event. A program closes an account by moving all its lamports out, and the runtime then removes it. Carbon 2.0 reports every account write with zero lamports as an `AccountDeletion`:

```rust
pub struct AccountDeletion {
    pub pubkey: Pubkey,
    pub account: Account, // the final state the source reported
    pub slot: u64,
    pub transaction_signature: Option<Signature>,
}
```

Datasources do this conversion with `AccountUpdate::into_update`, which returns `Update::AccountDeletion` when `account.lamports == 0` and `Update::Account` otherwise. The Yellowstone gRPC, Helius LaserStream, Helius Atlas websocket, RPC program subscribe and stream message datasources all use it. Call it in your own datasources too, so that deletions are classified in one place:

```rust
let update = AccountUpdate { pubkey, account, slot, transaction_signature }.into_update();
```

Because deletions are a separate variant, an `account` pipe never sees a zero-lamport account from these datasources. Register an `account_deletions` processor to handle closures. The final `account` keeps the owner and data the source reported, so you can tell which program the account belonged to.

## Transactions

```rust
pub struct TransactionUpdate {
    pub signature: Signature,
    pub transaction: VersionedTransaction,
    pub meta: TransactionStatusMeta,
    pub is_vote: bool,
    pub slot: u64,
    pub index: Option<u64>,
    pub block_time: Option<i64>,
    pub block_hash: Option<Hash>,
}
```

- `transaction` is the signed transaction; `meta` is its execution result: status, fee, balances, log messages, inner instructions, loaded addresses and so on.
- `index` is the transaction's position in its block. Yellowstone, LaserStream, RPC block subscribe, the block crawler and Helius GTFA set it; the transaction crawler and Helius Atlas websockets leave it `None`.
- `block_time` is a Unix timestamp in seconds, when the source provides it.

The pipeline turns each `TransactionUpdate` into a shared [`TransactionMetadata`](https://carbon.sevenlabs.org/concepts/transactions.md#transaction-metadata) and the list of its instructions before any processor runs.

### Transaction V1

The Agave 4.2 Solana crates add the V1 transaction format alongside legacy and v0 transactions. `transaction.message` is a `VersionedMessage`, and Carbon 2.0 handles all three variants (`Legacy`, `V0` and `V1`) when it extracts instructions and their accounts.

Datasources must request V1 transactions and a binary encoding, because Carbon can't rebuild a transaction from a `Json` or `JsonParsed` payload. The RPC transaction crawler and the Helius GTFA datasource set this internally. When you pass your own `RpcBlockSubscribeConfig` or `RpcBlockConfig`, set it yourself:

```rust
RpcBlockSubscribeConfig {
    encoding: Some(UiTransactionEncoding::Base64),
    transaction_details: Some(TransactionDetails::Full),
    max_supported_transaction_version: Some(1),
    ..RpcBlockSubscribeConfig::default()
}
```

## Block details

```rust
pub struct BlockDetails {
    pub slot: u64,
    pub block_hash: Option<Hash>,
    pub previous_block_hash: Option<Hash>,
    pub rewards: Option<Rewards>,
    pub num_reward_partitions: Option<u64>,
    pub block_time: Option<i64>,
    pub block_height: Option<u64>,
}
```

Among the Carbon 2.0 datasources, only [RPC block subscribe](https://carbon.sevenlabs.org/datasources/rpc-block-subscribe.md) sends `BlockDetails`: one per block, before that block's transactions. A [custom datasource](https://carbon.sevenlabs.org/guides/custom-datasource.md) can send them too.

## `UpdateType`

`UpdateType` names the variants without their data:

```rust
pub enum UpdateType {
    AccountUpdate,
    Transaction,
    AccountDeletion,
    BlockDetails,
}
```

`Update::update_type()` returns the `UpdateType` of an update, and `Datasource::update_types()` returns the types a datasource declares it sends. In 2.0.0 the pipeline doesn't read `update_types()` or check updates against it, so treat it as documentation. It isn't always complete: RPC block subscribe declares only `Transaction` but also sends `BlockDetails`.

## Example

This program builds the same token account twice, once funded and once with zero lamports, and shows how `into_update` classifies each.

```sh
cargo add carbon-core@2.0.0 solana-account@4.3.2 solana-pubkey@4.2.1
```

`src/main.rs`:

```rust
use {
    carbon_core::datasource::{AccountUpdate, Update},
    solana_account::Account,
    solana_pubkey::Pubkey,
};

fn main() {
    let token_program = Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");

    for lamports in [2_039_280, 0] {
        let update = AccountUpdate {
            pubkey: Pubkey::new_unique(),
            account: Account {
                lamports,
                data: vec![0; 165],
                owner: token_program,
                executable: false,
                rent_epoch: u64::MAX,
            },
            slot: 371_000_000,
            transaction_signature: None,
        };

        match update.into_update() {
            Update::Account(update) => {
                println!("account update: {} lamports", update.account.lamports)
            }
            Update::AccountDeletion(deletion) => println!(
                "account deletion: owner {}, {} bytes of final data",
                deletion.account.owner,
                deletion.account.data.len()
            ),
            other => println!("{:?}", other.update_type()),
        }
    }
}
```

```sh
cargo run
```

Output:

```text
account update: 2039280 lamports
account deletion: owner TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA, 165 bytes of final data
```

## Next steps

- [Datasources](https://carbon.sevenlabs.org/concepts/datasources.md): Where updates come from, and how to choose a source.
- [Processors](https://carbon.sevenlabs.org/concepts/processors.md): What each pipe passes to your code.
- [Updates reference](https://carbon.sevenlabs.org/reference/updates.md): Every field of every update type.

---

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