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)
- A stable way to access the node
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.
Step 1: Install required packages
Install the hugeadm utility for managing huge pages:
sudo apt install libhugetlbfs-binBehind 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.
If you plan to write applications using the Execution Events SDK (C, C++, or Rust), also install these development packages:
sudo apt install libhugetlbfs-dev libhugetlbfs0 libzstd-devBehind 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
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:
sudo nano /etc/systemd/system/events-hugepages-mounts.servicePaste the following contents (replace monad with your user if different):
[Unit]Description=Create hugepage mounts for monadAfter=local-fs.target
[Service]Type=oneshotExecStart=/usr/bin/hugeadm --create-user-mounts monadRemainAfterExit=yes
[Install]WantedBy=multi-user.targetBehind the scenes
This systemd service runs hugeadm --create-user-mounts monad at boot time, which:
- Creates a
hugetlbfsfilesystem mount at/var/lib/hugetlbfs/user/monad/ - Sets up separate directories for different page sizes (2MB and 1GB)
- Ensures the
monaduser 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.
Save and exit (Ctrl+O, Enter, Ctrl+X).
Enable and start the service:
sudo systemctl daemon-reloadsudo systemctl enable --now events-hugepages-mountsBehind 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.
Step 3: Create the event-rings directory
The execution daemon writes event data to files in this directory:
sudo mkdir -p /var/lib/hugetlbfs/user/monad/pagesize-2MB/event-ringssudo chown monad:monad /var/lib/hugetlbfs/user/monad/pagesize-2MB/event-ringsBehind the scenes
- mkdir -p: Creates the
event-ringsdirectory (and any parent directories if needed) - chown monad:monad: Changes ownership to the
monaduser 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.
Replace monad with your actual user if you're running the node as a different user.
Step 4: Configure the Execution daemon
Create a systemd override to enable execution events output.
Open the override editor:
sudo systemctl edit monad-executionBehind 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.
Add the following configuration:
[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 INFOBehind 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.
Both ExecStart= lines are required. The first clears the original value, and the second sets the new value with the --exec-event-ring flag.
Reload and restart the Execution daemon:
sudo systemctl daemon-reloadsudo systemctl restart monad-executionBehind 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.
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.
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.
Open the RPC override editor:
sudo systemctl edit monad-rpcBehind the scenes
Creates an override file at /etc/systemd/system/monad-rpc.service.d/override.conf to customize the RPC service configuration.
Add the following configuration:
[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-enabledBehind 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)
Reload and restart the RPC daemon:
sudo systemctl daemon-reloadsudo systemctl restart monad-rpcBehind 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
Step 6: Verify the setup
Check that the event ring file has been created:
ls -la /var/lib/hugetlbfs/user/monad/pagesize-2MB/event-rings/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.
You should see a file named monad-exec-events (or similar).
Check the Execution daemon status:
sudo systemctl status monad-executionBehind 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.
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, 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:
websocat -v ws://localhost:8081You 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 pingTo subscribe to new block headers, type this JSON-RPC call and press enter:
{ "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 for examples.
-
Learn more about WebSocket subscriptions: See the WebSocket Guide for all available subscription types.
Troubleshooting
Event ring file not created
Ensure the hugepage mount is active:
mount | grep hugetlbfsBehind 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.
You should see a mount point like /var/lib/hugetlbfs/user/monad/pagesize-2MB.
If not, restart the hugepages service:
sudo systemctl restart events-hugepages-mountsBehind 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.
Execution daemon fails to start
Check the logs for errors:
sudo journalctl -u monad-execution -fBehind 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.
Common issues:
- The
event-ringsdirectory 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:
sudo chown -R monad:monad /var/lib/hugetlbfs/user/monad/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.
Further resources
- Execution Events documentation - Comprehensive documentation on the execution events system
- Execution Events overview - Core concepts and event types
- C API reference - C library documentation
- Rust API reference - Rust crate documentation
- Execution Events and WebSocket Setup - Enable WebSocket support in RPC