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

# 如何在 Rust 中消费执行事件

# 如何在 Rust 中消费执行事件:一个基本示例

本指南将逐步介绍如何构建一个从运行中的 Monad 节点读取执行事件的最小 Rust 应用程序。指南结束时,您将拥有一个可用的事件消费者,它会在每个 EVM 动作发生时将其打印出来。

<iframe style={{ aspectRatio: "16 / 9" }} src="https://www.youtube.com/embed/CZniZnBVIzU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen />

## 前置条件

本指南假设您已具备:

* 一个已启用执行事件的运行中的 Monad 节点([设置指南](/zh/guides/execution-events/setup))

## 项目设置

以下是[包含代码的仓库](https://github.com/portdeveloper/simple-execution-events)。

创建一个新的 Rust 项目:

```bash theme={null}
cargo new --bin exec-events-demo
cd exec-events-demo
```

将 `Cargo.toml` 替换为:

```toml theme={null}
[package]
name = "exec-events-demo"
version = "0.1.0"
edition = "2021"

[dependencies]
monad-exec-events = { git = "https://github.com/category-labs/monad-bft", tag = "release/exec-events-sdk-v1.0" }
monad-event-ring = { git = "https://github.com/category-labs/monad-bft", tag = "release/exec-events-sdk-v1.0" }
```

## 代码

将 `src/main.rs` 替换为:

```rust title="src/main.rs" theme={null}
use std::time::Duration;

use monad_event_ring::{DecodedEventRing, EventNextResult, EventPayloadResult, EventRingPath};
use monad_exec_events::{ExecEvent, ExecEventReaderExt, ExecEventRing, ExecEventType};

/// Default path for the execution event ring
const EVENT_RING_PATH: &str =
    "/var/lib/hugetlbfs/user/monad/pagesize-2MB/event-rings/monad-exec-events";

fn main() {
    // Resolve the event ring path (full path bypasses hugetlbfs lookup)
    let event_ring_path =
        EventRingPath::resolve(EVENT_RING_PATH).expect("Failed to resolve path");

    // Open the live event ring
    let ring = ExecEventRing::new(&event_ring_path).expect("Failed to open event ring");

    println!("Connected to event ring");
    println!("Waiting for events...\n");

    // Create a reader and rewind to the start of the current block
    let mut reader = ring.create_reader();
    reader.consensus_prev(Some(ExecEventType::BlockStart));

    loop {
        match reader.next_descriptor() {
            EventNextResult::Ready(event) => {
                let seqno = event.info().seqno;

                // Try to read the event payload
                match event.try_read() {
                    EventPayloadResult::Ready(exec_event) => {
                        print_event(&exec_event, seqno);
                    }
                    EventPayloadResult::Expired => {
                        eprintln!("[{}] Payload expired!", seqno);
                        reader.reset();
                    }
                }
            }
            EventNextResult::Gap => {
                eprintln!("Warning: event gap occurred (reader too slow)");
                reader.reset();
            }
            EventNextResult::NotReady => {
                // No events available, wait briefly
                std::thread::sleep(Duration::from_millis(10));
            }
        }
    }
}

fn print_event(event: &ExecEvent, seqno: u64) {
    match event {
        ExecEvent::BlockStart(block) => {
            println!(
                "[{}] BLOCK_START: number={}",
                seqno, block.block_tag.block_number
            );
        }
        ExecEvent::BlockEnd(_) => {
            println!("[{}] BLOCK_END", seqno);
        }
        ExecEvent::TxnHeaderStart { txn_index, .. } => {
            println!("[{}] TXN_START: index={}", seqno, txn_index);
        }
        ExecEvent::TxnEvmOutput { txn_index, output } => {
            println!(
                "[{}] TXN_OUTPUT: index={} gas_used={}",
                seqno, txn_index, output.receipt.gas_used
            );
        }
        ExecEvent::TxnLog { txn_index, txn_log, .. } => {
            println!(
                "[{}] LOG: txn={} topics={}",
                seqno, txn_index, txn_log.topic_count
            );
        }
        ExecEvent::TxnEnd => {
            println!("[{}] TXN_END", seqno);
        }
        // Silently ignore other events (call frames, storage access, etc.)
        _ => {}
    }
}
```

## 构建并运行

```bash theme={null}
cargo build --release
./target/release/exec-events-demo
```

## 预期输出

当您的节点处理交易时,您将看到事件流:

```
Connected to event ring
Waiting for events...

[508183802] BLOCK_START: number=45199825
[508183811] TXN_START: index=0
[508183822] TXN_OUTPUT: index=0 gas_used=0
[508183823] LOG: txn=0 topics=3
[508183838] TXN_END
[508183942] BLOCK_END
```

## 关键概念

### 事件环

事件环是一块共享内存缓冲区,执行守护进程会在其中写入事件。多个读取者可以同时消费,每个读取者维护自己的位置。

### EventNextResult

* **Ready**:有可处理的事件
* **NotReady**:尚无新事件(守护进程未写入任何事件)
* **Gap**:读取者落后,事件被覆盖——调用 `reset()` 以恢复

### 事件类型

您将看到的常见事件:

* `BlockStart` / `BlockEnd` - 区块边界
* `TxnHeaderStart` / `TxnEnd` - 交易边界
* `TxnEvmOutput` - 交易执行结果(包含带 gas\_used 的收据)
* `TxnLog` - EVM 日志释放(Solidity 事件)
* `AccountAccess` - 执行期间访问的账户
* `StorageAccess` - 合约存储的读/写

## 后续步骤

* 查看完整的 [eventwatch.rs](https://github.com/category-labs/monad-bft/blob/release/exec-events-sdk-v1.0/monad-exec-events/examples/eventwatch.rs) 示例,了解生产模式(时间戳、超时检测、CLI 参数)
* 阅读 [Rust API 文档](/zh/execution-events/rust-api)获取详细的类型信息
* 探索[事件环内部结构](/zh/execution-events/event-ring)以了解共享内存协议
