> ## 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.

# Set up Execution Events

This guide walks you through configuring your Monad node to enable the Execution Events system, which allows you to build high-performance applications that receive lowest-latency event data via shared memory.

## Prerequisites

* A running Monad full node ([full node installation guide](/node-ops/full-node-installation))
* A stable way to access the node

<Info title="Why execution events?">
  Monad produces blocks every 400 milliseconds and can process thousands of transactions per block. Traditional JSON-RPC and WebSocket APIs may not keep up with this data volume. Execution events provide the highest-throughput, lowest-latency option for consuming real-time blockchain data.

  For more details, see the [Execution Events documentation](/execution-events/).
</Info>

## Step 1: Install required packages

Install the `hugeadm` utility for managing huge pages:

```bash theme={null}
sudo apt install libhugetlbfs-bin
```

<Accordion title="Behind the scenes">
  Installs the `libhugetlbfs-bin` package, which provides the `hugeadm` command-line tool. This tool manages "huge pages" - large memory pages (2MB instead of the standard 4KB) that reduce memory management overhead and improve performance for applications that need to share large amounts of data quickly, like execution events.
</Accordion>

If you plan to write applications using the Execution Events SDK (C, C++, or Rust), also install these development packages:

```bash theme={null}
sudo apt install libhugetlbfs-dev libhugetlbfs0 libzstd-dev
```

<Accordion title="Behind the scenes">
  * **libhugetlbfs-dev**: Header files for developing applications that use huge pages
  * **libhugetlbfs0**: Runtime library for huge page support
  * **libzstd-dev**: Zstandard compression library, used for efficient data encoding in the SDK
</Accordion>

## Step 2: Set up the `hugetlbfs` mount

The execution events system uses huge pages for high-performance shared memory communication. You need to create a persistent `hugetlbfs` mount.

### Create a systemd service for persistent mounts

Create the service file:

```bash theme={null}
sudo nano /etc/systemd/system/events-hugepages-mounts.service
```

Paste the following contents (replace `monad` with your user if different):

```ini theme={null}
[Unit]
Description=Create hugepage mounts for monad
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/usr/bin/hugeadm --create-user-mounts monad
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
```

<Accordion title="Behind the scenes">
  This systemd service runs `hugeadm --create-user-mounts monad` at boot time, which:

  * Creates a `hugetlbfs` filesystem mount at `/var/lib/hugetlbfs/user/monad/`
  * Sets up separate directories for different page sizes (2MB and 1GB)
  * Ensures the `monad` user has permission to create files in these directories

  The `Type=oneshot` means it runs once at startup, and `RemainAfterExit=yes` keeps the service marked as "active" so systemd knows the mount is still needed.
</Accordion>

Save and exit (`Ctrl+O`, `Enter`, `Ctrl+X`).

Enable and start the service:

```bash theme={null}
sudo systemctl daemon-reload
sudo systemctl enable --now events-hugepages-mounts
```

<Accordion title="Behind the scenes">
  * **daemon-reload**: Tells systemd to re-read all service files, picking up your new service
  * **enable --now**: Enables the service to start at boot AND starts it immediately

  After this, the hugepage mount will be available now and on every reboot.
</Accordion>

## Step 3: Create the event-rings directory

The execution daemon writes event data to files in this directory:

```bash theme={null}
sudo mkdir -p /var/lib/hugetlbfs/user/monad/pagesize-2MB/event-rings
sudo chown monad:monad /var/lib/hugetlbfs/user/monad/pagesize-2MB/event-rings
```

<Accordion title="Behind the scenes">
  * **mkdir -p**: Creates the `event-rings` directory (and any parent directories if needed)
  * **chown monad:monad**: Changes ownership to the `monad` user so the execution daemon can write event ring files here

  The path `/var/lib/hugetlbfs/user/monad/pagesize-2MB/` is where `hugeadm` created the 2MB huge page mount. The execution daemon will create shared memory files in `event-rings/` that your consumer applications can read.
</Accordion>

<Note>
  Replace `monad` with your actual user if you're running the node as a different user.
</Note>

## Step 4: Configure the Execution daemon

Create a systemd override to enable execution events output.

Open the override editor:

```bash theme={null}
sudo systemctl edit monad-execution
```

<Accordion title="Behind the scenes">
  Opens a text editor to create an "override" file for the `monad-execution` service. Overrides let you modify service settings without editing the original unit file (which would be overwritten on package updates). The override file is saved at `/etc/systemd/system/monad-execution.service.d/override.conf`.
</Accordion>

Add the following configuration:

```ini theme={null}
[Service]
ExecStart=
ExecStart=/usr/local/bin/monad \
    --chain "$CHAIN" \
    --db /dev/triedb \
    --block_db /home/monad/monad-bft/ledger \
    --statesync /home/monad/monad-bft/statesync.sock \
    --exec-event-ring /var/lib/hugetlbfs/user/monad/pagesize-2MB/event-rings/monad-exec-events \
    --sq_thread_cpu 1 \
    --log_level INFO
```

<Accordion title="Behind the scenes">
  * **ExecStart=** (empty): Clears the original command from the base unit file (required for overrides)
  * **ExecStart=/usr/local/bin/monad ...**: Sets the new command with all flags
  * **--exec-event-ring**: The key flag that enables execution events output. It specifies the path where the daemon will create the shared memory event ring file

  The other flags are standard execution daemon options copied from the default configuration.
</Accordion>

<Warning>
  Both `ExecStart=` lines are required. The first clears the original value, and the second sets the new value with the `--exec-event-ring` flag.
</Warning>

Reload and restart the Execution daemon:

```bash theme={null}
sudo systemctl daemon-reload
sudo systemctl restart monad-execution
```

<Accordion title="Behind the scenes">
  * **daemon-reload**: Tells systemd to re-read all service files, including your new override
  * **restart monad-execution**: Stops and starts the execution daemon with the new configuration

  After restart, the daemon will begin writing execution events to the shared memory ring buffer.
</Accordion>

## Step 5: Configure the RPC daemon for WebSocket support

This step enables WebSocket support in the RPC server, allowing you to use `eth_subscribe` for real-time data.

<Warning>
  RPC with WebSocket enabled has a hard dependency on Execution running with events enabled. If you start RPC with `--ws-enabled` before completing Step 4, RPC will crash.
</Warning>

Open the RPC override editor:

```bash theme={null}
sudo systemctl edit monad-rpc
```

<Accordion title="Behind the scenes">
  Creates an override file at `/etc/systemd/system/monad-rpc.service.d/override.conf` to customize the RPC service configuration.
</Accordion>

Add the following configuration:

```ini theme={null}
[Service]
ExecStart=
ExecStart=/usr/local/bin/monad-rpc \
    --ipc-path /home/monad/monad-bft/mempool.sock \
    --triedb-path /dev/triedb \
    --otel-endpoint "http://0.0.0.0:4317" \
    --allow-unprotected-txs \
    --node-config /home/monad/monad-bft/config/node.toml \
    --exec-event-path /var/lib/hugetlbfs/user/monad/pagesize-2MB/event-rings/monad-exec-events \
    --ws-enabled
```

<Accordion title="Behind the scenes">
  * **ExecStart=** (empty): Clears the original command from the base unit file (required for overrides)
  * **--exec-event-path**: Points to the same event ring file that the Execution daemon writes to
  * **--ws-enabled**: Enables WebSocket support on port 8081 (default)
</Accordion>

Reload and restart the RPC daemon:

```bash theme={null}
sudo systemctl daemon-reload
sudo systemctl restart monad-rpc
```

<Accordion title="Behind the scenes">
  * **daemon-reload**: Tells systemd to re-read all service files, including your new override
  * **restart monad-rpc**: Stops and starts the RPC daemon with WebSocket support enabled
</Accordion>

## Step 6: Verify the setup

Check that the event ring file has been created:

```bash theme={null}
ls -la /var/lib/hugetlbfs/user/monad/pagesize-2MB/event-rings/
```

<Accordion title="Behind the scenes">
  Lists the contents of the event-rings directory. You should see a file named `monad-exec-events`. This is the shared memory file that the execution daemon writes to and your consumer applications read from.
</Accordion>

You should see a file named `monad-exec-events` (or similar).

Check the Execution daemon status:

```bash theme={null}
sudo systemctl status monad-execution
```

<Accordion title="Behind the scenes">
  Shows the current status of the execution daemon service. Look for:

  * **Active: active (running)** - the service is running
  * No error messages in the recent log output

  If you see errors related to the event ring or hugepages, check the Troubleshooting section below.
</Accordion>

The service should be active and running without errors.

### Check WebSocket connectivity

A quick way to check if WebSocket connectivity is working is to use [`websocat`](https://github.com/vi/websocat), a command-line WebSocket client. It can be installed via `cargo install websocat` or by downloading precompiled binaries.

Run it in verbose mode with the WebSocket service on default port 8081:

```bash theme={null}
websocat -v ws://localhost:8081
```

You should see output like:

```
[INFO  websocat::lints] Auto-inserting the line mode
[INFO  websocat::stdio_threaded_peer] get_stdio_peer (threaded)
[INFO  websocat::ws_client_peer] get_ws_client_peer
[INFO  websocat::net_peer] Connected to TCP 127.0.0.1:8081
[INFO  websocat::ws_client_peer] Connected to ws
[INFO  websocat::ws_peer] Received WebSocket ping
```

To subscribe to new block headers, type this JSON-RPC call and press enter:

```json theme={null}
{ "id": 1, "jsonrpc": "2.0", "method": "eth_subscribe", "params": ["newHeads"] }
```

Every half-second or so, you should see updates about new blocks.

## Next steps

With execution events and WebSocket support enabled, you can now:

* **Build your own data consumer**: Write high-performance applications in C, C++, or Rust using the Execution Events SDK. See the [Getting Started guide](/execution-events/getting-started/) for examples.

* **Learn more about WebSocket subscriptions**: See the [WebSocket Guide](/reference/websockets) for all available subscription types.

## Troubleshooting

### Event ring file not created

Ensure the hugepage mount is active:

```bash theme={null}
mount | grep hugetlbfs
```

<Accordion title="Behind the scenes">
  Lists all mounted filesystems and filters for `hugetlbfs` mounts. You should see output like:

  ```
  hugetlbfs on /var/lib/hugetlbfs/user/monad/pagesize-2MB type hugetlbfs (rw,relatime,...)
  ```

  If there's no output, the hugepage mount isn't active.
</Accordion>

You should see a mount point like `/var/lib/hugetlbfs/user/monad/pagesize-2MB`.

If not, restart the hugepages service:

```bash theme={null}
sudo systemctl restart events-hugepages-mounts
```

<Accordion title="Behind the scenes">
  Re-runs the hugepage mount service, which will recreate the `hugetlbfs` mount points. After this, run the `mount | grep hugetlbfs` command again to verify.
</Accordion>

### Execution daemon fails to start

Check the logs for errors:

```bash theme={null}
sudo journalctl -u monad-execution -f
```

<Accordion title="Behind the scenes">
  * **journalctl -u monad-execution**: Shows logs for the execution daemon service
  * **-f**: Follows the log in real-time (like `tail -f`)

  Press `Ctrl+C` to stop following. Look for error messages mentioning the event ring path, permissions, or hugepages.
</Accordion>

Common issues:

* The `event-rings` directory doesn't exist or has wrong permissions
* The hugepage mount is not available
* Incorrect paths in the systemd override

### Permission denied errors

Ensure the `event-rings` directory is owned by the correct user:

```bash theme={null}
sudo chown -R monad:monad /var/lib/hugetlbfs/user/monad/
```

<Accordion title="Behind the scenes">
  Recursively changes ownership of the entire hugepage directory tree to the `monad` user. The `-R` flag ensures all subdirectories and files are updated.
</Accordion>

## Further resources

* [Execution Events documentation](/execution-events/) - Comprehensive documentation on the execution events system
* [Execution Events overview](/execution-events/overview) - Core concepts and event types
* [C API reference](/execution-events/c-api) - C library documentation
* [Rust API reference](/execution-events/rust-api) - Rust crate documentation
* [Execution Events and WebSocket Setup](/node-ops/events-and-websockets) - Enable WebSocket support in RPC
