# Processor inputs (Carbon 2.0)

> Every type a Carbon 2.0.0 processor receives, field by field, for account, instruction, transaction, deletion and block-details pipes.

A processor implements `Processor<T>` for the input type of the pipe it is registered on. This page lists each input type and every field in it, so you know what data your `process` method can read. For how to write a processor, see [Processors](https://carbon.sevenlabs.org/concepts/processors.md).

| Builder method                                                                                      | Processor implements                              | Defined in                                                                                              |
| --------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| [`account`](https://carbon.sevenlabs.org/reference/pipeline-builder.md#account)                     | `Processor<AccountProcessorInputType<'_, T>>`     | `carbon_core::account`                                                                                  |
| [`instruction`](https://carbon.sevenlabs.org/reference/pipeline-builder.md#instruction)             | `Processor<InstructionProcessorInputType<'_, T>>` | `carbon_core::instruction`                                                                              |
| [`transaction`](https://carbon.sevenlabs.org/reference/pipeline-builder.md#transaction)             | `Processor<TransactionProcessorInputType<'_, T>>` | `carbon_core::transaction`                                                                              |
| [`account_deletions`](https://carbon.sevenlabs.org/reference/pipeline-builder.md#account_deletions) | `Processor<AccountDeletion>`                      | `carbon_core::datasource` ([fields](https://carbon.sevenlabs.org/reference/updates.md#accountdeletion)) |
| [`block_details`](https://carbon.sevenlabs.org/reference/pipeline-builder.md#block_details)         | `Processor<BlockDetails>`                         | `carbon_core::datasource` ([fields](https://carbon.sevenlabs.org/reference/updates.md#blockdetails))    |

Every input is passed by reference and borrows data the pipeline owns for the duration of one `process` call. Clone what you need to keep.

## Example

This program prints the instruction input for each Meteora DLMM `Swap2` the transaction crawler finds on the public RPC endpoint.

`Cargo.toml`:

```toml
[dependencies]
carbon-core = "2.0.0"
carbon-meteora-dlmm-decoder = "2.0.0"
carbon-rpc-transaction-crawler-datasource = "2.0.0"
tokio = { version = "1", features = ["full"] }
tokio-util = "0.7"
```

`src/main.rs`:

```rust
use {
    carbon_core::{
        error::CarbonResult, instruction::InstructionProcessorInputType, pipeline::Pipeline,
        processor::Processor,
    },
    carbon_meteora_dlmm_decoder::{
        instructions::MeteoraDlmmInstruction, MeteoraDlmmDecoder, PROGRAM_ID,
    },
    carbon_rpc_transaction_crawler_datasource::{ConnectionConfig, Filters, RpcTransactionCrawler},
    std::time::Duration,
    tokio_util::sync::CancellationToken,
};

struct InputPrinter;

impl Processor<InstructionProcessorInputType<'_, MeteoraDlmmInstruction>> for InputPrinter {
    async fn process(
        &mut self,
        input: &InstructionProcessorInputType<'_, MeteoraDlmmInstruction>,
    ) -> CarbonResult<()> {
        let MeteoraDlmmInstruction::Swap2 { data, accounts, .. } = input.decoded_instruction else {
            return Ok(());
        };
        let meta = input.metadata;
        let tx = &meta.transaction_metadata;
        println!("signature:      {}", tx.signature);
        println!("slot:           {} (block_time {:?})", tx.slot, tx.block_time);
        println!("fee payer:      {}", tx.fee_payer);
        println!("stack height:   {}", meta.stack_height);
        println!("index:          {}", meta.index);
        println!("absolute path:  {:?}", meta.absolute_path);
        println!("inner ixs:      {}", input.nested_instructions.len());
        println!("raw accounts:   {}", input.raw_instruction.accounts.len());
        println!("lb_pair:        {}", accounts.lb_pair);
        println!("amount_in:      {}", data.amount_in);
        println!();
        Ok(())
    }
}

#[tokio::main]
async fn main() -> CarbonResult<()> {
    let datasource = RpcTransactionCrawler::new(
        "https://api.mainnet-beta.solana.com".to_string(),
        PROGRAM_ID,
        ConnectionConfig::default(),
        Filters::new(None, None, None),
        None,
    );

    let token = CancellationToken::new();
    let stop = token.clone();
    tokio::spawn(async move {
        tokio::time::sleep(Duration::from_secs(90)).await;
        stop.cancel();
    });

    Pipeline::builder()
        .datasource(datasource)
        .instruction(MeteoraDlmmDecoder, InputPrinter)
        .datasource_cancellation_token(token)
        .build()?
        .run()
        .await
}
```

```sh
cargo run
```

The first swap is a top-level instruction; the second is a CPI from another program, so its `stack_height` is 2 and its `index` is the index of the top-level instruction that called it:

Output:

```text
signature:      43eGCzcyUFYtJsuoWwmFsirBBu51tm6BRs7WiCWYRfR7txoz1DATD5iSQNFfS1LXuGJvYG2AXTA3t38N1DG9eYJp
slot:           467120934 (block_time Some(1794185094))
fee payer:      6TWMHcW3gGXRnzRoe6vTgENjJhCbTFApcA5yLEJJaBDh
stack height:   1
index:          2
absolute path:  [2]
inner ixs:      4
raw accounts:   17
lb_pair:        GeUkx21Vc6yg63YZ1BdXY95ZATm9LeBYCgSN1uJ3o18S
amount_in:      404287484

signature:      2W5fitdRrbLo2pNF4ChwDPPcmRNC3EfR1u7viGGyPXdnHZM8HBu2dFnJbVxktupvJKbXcxheZaadphndEMkCfNTi
slot:           467120933 (block_time Some(1794185094))
fee payer:      AgmLJBMDCqWynYnQiPCuj9ewsNNsBJXyzoUhD9LJzN51
stack height:   2
index:          1
absolute path:  [1, 1]
inner ixs:      4
raw accounts:   19
lb_pair:        CcG3fyDZn6uXTV5p2TV9cceCA2YhE3bUMLeXGn6vZSNr
amount_in:      680804450
```

## `AccountProcessorInputType`

What an account processor receives for each account its decoder accepts.

```rust
#[derive(Debug)]
pub struct AccountProcessorInputType<'a, T> {
    pub metadata: &'a AccountMetadata,
    pub decoded_account: &'a DecodedAccount<T>,
    pub raw_account: &'a solana_account::Account,
}
```

**Details.**

| Field             | Type                       | Meaning                                                                               |
| ----------------- | -------------------------- | ------------------------------------------------------------------------------------- |
| `metadata`        | `&AccountMetadata`         | Slot, address and writing transaction. See [`AccountMetadata`](#accountmetadata).     |
| `decoded_account` | `&DecodedAccount<T>`       | Decoder output. `T` is the decoder's `AccountType`, for example `MeteoraDlmmAccount`. |
| `raw_account`     | `&solana_account::Account` | The account exactly as the datasource sent it, including the undecoded `data` bytes.  |

**Example.**

```rust
impl Processor<AccountProcessorInputType<'_, MeteoraDlmmAccount>> for PoolLogger {
    async fn process(
        &mut self,
        input: &AccountProcessorInputType<'_, MeteoraDlmmAccount>,
    ) -> CarbonResult<()> {
        if let MeteoraDlmmAccount::LbPair(pool) = &input.decoded_account.data {
            println!(
                "{} active_id={} ({} bytes, slot {})",
                input.metadata.pubkey,
                pool.active_id,
                input.raw_account.data.len(),
                input.metadata.slot
            );
        }
        Ok(())
    }
}
```

**See also.** [`account`](https://carbon.sevenlabs.org/reference/pipeline-builder.md#account), [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/account/struct.AccountProcessorInputType.html).

## `AccountMetadata`

Where and when an account update was observed.

```rust
#[derive(Debug, Clone)]
pub struct AccountMetadata {
    pub slot: u64,
    pub pubkey: Pubkey,
    pub transaction_signature: Option<Signature>,
}
```

**Details.** Copied from the [`AccountUpdate`](https://carbon.sevenlabs.org/reference/updates.md#accountupdate).

| Field                   | Type                                  | Meaning                                                                                                         |
| ----------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `slot`                  | `u64`                                 | Slot of the update.                                                                                             |
| `pubkey`                | `solana_pubkey::Pubkey`               | Address of the account.                                                                                         |
| `transaction_signature` | `Option<solana_signature::Signature>` | Transaction that wrote this state. Only Yellowstone gRPC and Helius LaserStream set it; `None` everywhere else. |

**Example.**

```rust
let key = (input.metadata.pubkey, input.metadata.slot);
```

**See also.** [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/account/struct.AccountMetadata.html).

## `DecodedAccount`

An account decoder's output: the typed data plus the account header.

```rust
#[derive(Debug, Clone)]
pub struct DecodedAccount<T> {
    pub lamports: u64,
    pub data: T,
    pub owner: Pubkey,
    pub executable: bool,
    pub rent_epoch: u64,
}
```

**Details.**

| Field        | Type                    | Meaning                                                                                                                                             |
| ------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lamports`   | `u64`                   | Balance. Always above 0 here: zero-lamport accounts arrive as deletions.                                                                            |
| `data`       | `T`                     | The decoded account. Generated decoders use an enum with one boxed variant per account type, for example `MeteoraDlmmAccount::LbPair(Box<LbPair>)`. |
| `owner`      | `solana_pubkey::Pubkey` | Owning program.                                                                                                                                     |
| `executable` | `bool`                  | Whether the account is a program.                                                                                                                   |
| `rent_epoch` | `u64`                   | Rent epoch from the account.                                                                                                                        |

Generated decoders copy the four header fields from the raw account. A hand-written [`AccountDecoder`](https://carbon.sevenlabs.org/reference/traits.md#accountdecoder) builds this struct itself.

**Example.**

```rust
let decoded = &input.decoded_account;
println!("owner={} lamports={}", decoded.owner, decoded.lamports);
```

**See also.** [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/account/struct.DecodedAccount.html).

## `InstructionProcessorInputType`

What an instruction processor receives for each instruction its decoder accepts.

```rust
#[derive(Debug)]
pub struct InstructionProcessorInputType<'a, T> {
    pub metadata: &'a InstructionMetadata,
    pub decoded_instruction: &'a T,
    pub nested_instructions: &'a NestedInstructions,
    pub raw_instruction: &'a solana_instruction::Instruction,
}
```

**Details.**

| Field                 | Type                               | Meaning                                                                                                                                                                                                               |
| --------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metadata`            | `&InstructionMetadata`             | Position in the transaction and the shared transaction data. See [`InstructionMetadata`](#instructionmetadata).                                                                                                       |
| `decoded_instruction` | `&T`                               | Decoder output. For generated decoders, an enum with struct variants: `MeteoraDlmmInstruction::Swap { program_id, data, accounts }`.                                                                                  |
| `nested_instructions` | `&NestedInstructions`              | This instruction's own CPIs (its subtree), not the whole transaction. Empty when it made no CPIs.                                                                                                                     |
| `raw_instruction`     | `&solana_instruction::Instruction` | The instruction with `program_id`, resolved `accounts` (`AccountMeta` with `is_signer` and `is_writable`) and raw `data`. Lookup-table accounts of V0 transactions are already resolved from `meta.loaded_addresses`. |

The pipe runs once per matching instruction, top-level or inner. If a program calls your program through CPI, you receive that inner instruction with `stack_height > 1`.

**Example.**

```rust
for child in input.nested_instructions.iter() {
    println!("CPI to {}", child.instruction.program_id);
}
```

**See also.** [`instruction`](https://carbon.sevenlabs.org/reference/pipeline-builder.md#instruction), [Instructions](https://carbon.sevenlabs.org/concepts/instructions.md), [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/instruction/struct.InstructionProcessorInputType.html).

## `InstructionMetadata`

Where an instruction sits in its transaction.

```rust
#[derive(Debug, Clone)]
pub struct InstructionMetadata {
    pub transaction_metadata: Arc<TransactionMetadata>,
    pub stack_height: u32,
    pub index: u32,
    pub absolute_path: Vec<u8>,
}
```

**Details.**

| Field                  | Type                       | Meaning                                                                                                                                                                                                                                                                                                      |
| ---------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `transaction_metadata` | `Arc<TransactionMetadata>` | The transaction this instruction belongs to, shared by all its instructions. See [`TransactionMetadata`](#transactionmetadata).                                                                                                                                                                              |
| `stack_height`         | `u32`                      | `1` for a top-level instruction, `2` for a CPI made by it, up to `5` (`MAX_INSTRUCTION_STACK_DEPTH`).                                                                                                                                                                                                        |
| `index`                | `u32`                      | Index of the **top-level** instruction in the message. Inner instructions carry the index of the top-level instruction they descend from, not their position among siblings.                                                                                                                                 |
| `absolute_path`        | `Vec<u8>`                  | Path from the root of the instruction tree: `[top_level_index, child_position, grandchild_position, …]`, one entry per stack level, with positions counted from 0. `[2]` is the third top-level instruction; `[1, 1]` is the second CPI under the second top-level instruction. Unique within a transaction. |

Use `(transaction_metadata.signature, absolute_path)` as a unique key for an instruction; `(signature, index, stack_height)` is not unique when one instruction makes several CPIs at the same depth.

Carbon reads inner instructions from `meta.inner_instructions` and their depth from each inner instruction's `stack_height`. When the source reports a missing or out-of-range `stack_height` (outside 2 to 5), Carbon logs `invalid inner instruction stack height (…), dropping the remaining inner instructions of this group` at `warn` level and skips the rest of that group.

**Example.**

```rust
let key = (
    input.metadata.transaction_metadata.signature,
    input.metadata.absolute_path.clone(),
);
```

**See also.** [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/instruction/struct.InstructionMetadata.html), [source](https://github.com/sevenlabs-hq/carbon/blob/v2.0.0/crates/core/src/transformers.rs).

## `InstructionMetadata::decode_log_events`

Decodes the program log events emitted by this instruction.

```rust
pub fn decode_log_events<T: CarbonDeserialize>(&self) -> Vec<T>
```

**Details.** Walks `transaction_metadata.meta.log_messages`, tracks `Program … invoke [n]` and `Program … success` / `failed` lines to follow the call stack, and keeps the log lines emitted while this instruction (matched by `absolute_path`) was executing. For each such line, it base64-decodes the last whitespace-separated token and calls `T::deserialize`; lines that fail to decode or deserialize are skipped. This targets Anchor `emit!` events, logged as `Program data: <base64>`. Logs emitted by this instruction's own CPIs are not included.

Precompile instructions (Ed25519, Secp256k1, Secp256r1) log nothing, so Carbon subtracts the number of precompiles before this instruction from the top-level index before matching. Returns an empty `Vec` when the transaction has no log messages. If the runtime truncated the logs (`Log truncated`), events after the cut are missing.

Generated decoders in 2.0.0 do not implement `CarbonDeserialize` for their event types; they expose an inherent `decode` method instead, and Anchor events emitted through self-CPI (`emit_cpi!`) arrive as a decoded `CpiEvent` instruction. Implement `CarbonDeserialize` yourself to use this method; see [`CarbonDeserialize`](https://carbon.sevenlabs.org/reference/traits.md#carbondeserialize).

**Example.**

```rust
for event in input.metadata.decode_log_events::<MyEvent>() {
    println!("{} moved {}", event.pool, event.amount);
}
```

**See also.** [Instructions](https://carbon.sevenlabs.org/concepts/instructions.md), [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/instruction/struct.InstructionMetadata.html#method.decode_log_events).

## `NestedInstruction`

One node in a transaction's instruction tree.

```rust
#[derive(Debug, Clone)]
pub struct NestedInstruction {
    pub metadata: InstructionMetadata,
    pub instruction: solana_instruction::Instruction,
    pub inner_instructions: NestedInstructions,
}
```

**Details.**

| Field                | Type                              | Meaning                                                                                          |
| -------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------ |
| `metadata`           | `InstructionMetadata`             | Position of this instruction.                                                                    |
| `instruction`        | `solana_instruction::Instruction` | The raw instruction. It is not decoded: run a decoder on it yourself if you need its typed form. |
| `inner_instructions` | `NestedInstructions`              | The CPIs this instruction made, recursively.                                                     |

**Example.**

```rust
fn count(instructions: &NestedInstructions) -> usize {
    instructions
        .iter()
        .map(|ix| 1 + count(&ix.inner_instructions))
        .sum()
}
```

**See also.** [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/instruction/struct.NestedInstruction.html).

## `NestedInstructions`

An ordered list of `NestedInstruction`s.

```rust
#[derive(Debug, Default)]
pub struct NestedInstructions(pub Vec<NestedInstruction>);

impl NestedInstructions {
    pub fn len(&self) -> usize;
    pub fn is_empty(&self) -> bool;
    pub fn push(&mut self, nested_instruction: NestedInstruction);
}
```

**Details.** Derefs to `[NestedInstruction]`, so slice methods such as `iter()`, `first()` and indexing work. It also implements `Clone`, owned `IntoIterator`, and `From<InstructionsWithMetadata>`, which builds the tree from a flat `Vec<(InstructionMetadata, Instruction)>` ordered top-level-first as the runtime reports it. Filters receive the whole transaction's tree in `filter_transaction`; instruction processors receive one subtree in `nested_instructions`.

`From<InstructionsWithMetadata>` asserts that every `stack_height` is between 1 and `MAX_INSTRUCTION_STACK_DEPTH` (5) and panics otherwise. The pipeline only builds trees from validated data, but if you call it yourself, check heights first.

**Example.**

```rust
if let Some(first) = input.nested_instructions.first() {
    println!("first CPI: {:?}", first.metadata.absolute_path);
}
```

**See also.** [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/instruction/struct.NestedInstructions.html).

## `TransactionProcessorInputType`

What a transaction processor receives, once per transaction.

```rust
#[derive(Debug)]
pub struct TransactionProcessorInputType<'a, T> {
    pub metadata: &'a Arc<TransactionMetadata>,
    pub instructions: &'a [(InstructionMetadata, T)],
}
```

**Details.**

| Field          | Type                          | Meaning                                                                                                                                                                                                                                                                                                                  |
| -------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `metadata`     | `&Arc<TransactionMetadata>`   | The transaction. See [`TransactionMetadata`](#transactionmetadata).                                                                                                                                                                                                                                                      |
| `instructions` | `&[(InstructionMetadata, T)]` | Every instruction that `T::parse_instruction` recognized, top-level and inner, in execution order (each top-level instruction followed by its CPIs). Unrecognized instructions are omitted. `T` is your [`InstructionDecoderCollection`](https://carbon.sevenlabs.org/reference/traits.md#instructiondecodercollection). |

The processor runs for every transaction the datasource sends, including transactions where `instructions` is empty. There is no nested tree here; use `InstructionMetadata::stack_height` and `absolute_path` to rebuild parent-child relations.

**Example.**

```rust
impl Processor<TransactionProcessorInputType<'_, AllInstructions>> for TxLogger {
    async fn process(
        &mut self,
        input: &TransactionProcessorInputType<'_, AllInstructions>,
    ) -> CarbonResult<()> {
        if input.instructions.is_empty() {
            return Ok(());
        }
        println!(
            "{}: {} known instructions",
            input.metadata.signature,
            input.instructions.len()
        );
        Ok(())
    }
}
```

**See also.** [`transaction`](https://carbon.sevenlabs.org/reference/pipeline-builder.md#transaction), [Transactions](https://carbon.sevenlabs.org/concepts/transactions.md), [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/transaction/struct.TransactionProcessorInputType.html).

## `TransactionMetadata`

Data shared by every instruction of one transaction.

```rust
#[derive(Debug, Clone, Default)]
pub struct TransactionMetadata {
    pub slot: u64,
    pub signature: Signature,
    pub fee_payer: Pubkey,
    pub meta: solana_transaction_status::TransactionStatusMeta,
    pub message: solana_message::VersionedMessage,
    pub index: Option<u64>,
    pub block_time: Option<i64>,
    pub block_hash: Option<Hash>,
}
```

**Details.** Built from the [`TransactionUpdate`](https://carbon.sevenlabs.org/reference/updates.md#transactionupdate) with `TryFrom`, which fails with [`MissingFeePayer`](https://carbon.sevenlabs.org/reference/errors.md#missingfeepayer) when the message has no account keys.

| Field        | Type                               | Meaning                                                                                                                                                                                                                                                                                                                                   |
| ------------ | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `slot`       | `u64`                              | Slot the transaction landed in.                                                                                                                                                                                                                                                                                                           |
| `signature`  | `solana_signature::Signature`      | Transaction signature.                                                                                                                                                                                                                                                                                                                    |
| `fee_payer`  | `solana_pubkey::Pubkey`            | First static account key of the message.                                                                                                                                                                                                                                                                                                  |
| `meta`       | `TransactionStatusMeta`            | Status, fee, balances, inner instructions, logs, token balances, rewards, loaded addresses, return data, compute units. For RPC datasources Carbon converts it from the JSON-RPC form: token balances without an `owner` or `programId` are dropped, and `return_data.data` holds the base64 text as bytes rather than the decoded bytes. |
| `message`    | `solana_message::VersionedMessage` | The full message (legacy, V0 or V1), including `recent_blockhash`, static account keys and compiled instructions.                                                                                                                                                                                                                         |
| `index`      | `Option<u64>`                      | Position in the block, when the datasource knows it. `None` for the RPC transaction crawler and Helius Atlas.                                                                                                                                                                                                                             |
| `block_time` | `Option<i64>`                      | Unix timestamp in seconds, when provided.                                                                                                                                                                                                                                                                                                 |
| `block_hash` | `Option<solana_hash::Hash>`        | Only set by the RPC block crawler and RPC block subscribe.                                                                                                                                                                                                                                                                                |

Check `meta.status.is_err()` to detect failed transactions. Whether you receive failed transactions depends on the datasource: the RPC transaction crawler, RPC block crawler and RPC block subscribe drop them before they reach the pipeline; Yellowstone and LaserStream follow your subscription's `failed` filter; Helius GTFA follows its `status` filter.

**Example.**

```rust
let tx = &input.metadata.transaction_metadata;
if tx.meta.status.is_err() {
    return Ok(());
}
println!("{} paid {} lamports", tx.fee_payer, tx.meta.fee);
```

**See also.** [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/transaction/struct.TransactionMetadata.html).

## `MAX_INSTRUCTION_STACK_DEPTH`

The deepest instruction nesting Carbon accepts.

```rust
pub const MAX_INSTRUCTION_STACK_DEPTH: usize = 5;
```

**Details.** Matches the Agave runtime's limit of a top-level instruction plus four levels of CPI. Inner instructions reported deeper than this are dropped with a warning.

**Example.**

```rust
assert!(input.metadata.stack_height as usize <= MAX_INSTRUCTION_STACK_DEPTH);
```

**See also.** [docs.rs](https://docs.rs/carbon-core/2.0.0/carbon_core/instruction/constant.MAX_INSTRUCTION_STACK_DEPTH.html).

## Deletions and block details

Account-deletion and block-details processors receive the update itself, with no metadata wrapper and no decoder:

```rust
impl Processor<AccountDeletion> for DeletionLogger {
    async fn process(&mut self, deletion: &AccountDeletion) -> CarbonResult<()> {
        println!("closed {} (owner {})", deletion.pubkey, deletion.account.owner);
        Ok(())
    }
}

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

See [`AccountDeletion`](https://carbon.sevenlabs.org/reference/updates.md#accountdeletion) and [`BlockDetails`](https://carbon.sevenlabs.org/reference/updates.md#blockdetails) for their fields.

---

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