> ## Documentation Index
> Fetch the complete documentation index at: https://monadfoundation-40611fb6-devops-1498-direct-udp-implementat.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct UDP Migration

<Warning>
  Please do not proceed until Monad Foundation provides notice.
</Warning>

## Overview

Monad nodes exchange consensus and transaction traffic over [RaptorCast](/monad-arch/consensus/raptorcast), a broadcast protocol optimized for 1-to-many delivery. Direct UDP adds a dedicated unicast channel for 1-to-1 transaction forwarding, skipping RaptorCast's broadcast overhead. It's currently **opt-in** and will become required in a future release.

**Benefits:**

* **Reduced Amplification**: No 2.5x amplification when both peers have direct UDP enabled
* **Dedicated Transport**: Separates transaction forwarding from consensus traffic
* **Performance**: More efficient peer-to-peer transaction delivery

## Notes

* **Backward Compatibility**: Nodes can communicate with both direct-UDP-enabled and non-enabled peers
* **Prerequisite**: Authenticated UDP (port 8001) must be configured first
* **Sequence Numbers**: Always increment `self_record_seq_num` when regenerating signatures — if not bumped, the updated name record won't propagate
* **Key Reuse**: Direct UDP uses your existing validator keys (secp256k1) — same as authenticated UDP
* **Port Summary**: 8000 (TCP), 8001 (authenticated UDP), 8002 (direct UDP)

## Prerequisites

* **Monad Version**: `v0.16.2` or later
* **Access**: Root access on your node — all commands below assume you are running as root (e.g. `sudo -i` or `su -` first)
* **[Authenticated UDP](/node-ops/upgrade-instructions/auth-udp)** must be enabled before enabling Direct UDP.
* **Keystore**: Existing `/home/monad/monad-bft/config/id-secp` file
* **Network**: Ability to open UDP port 8002 on your firewall

## Instructions

### 1. Verify the Monad version

Verify the installation:

```bash theme={null}
monad-rpc -V
# Expected output v0.16.2+
```

If not, please refer to the official documentation to upgrade to the latest recommended version: [https://docs.monad.xyz/node-ops/upgrade-instructions/](https://docs.monad.xyz/node-ops/upgrade-instructions/).

### 2. Configure Firewall

Open UDP port 8002 for direct UDP traffic:

```bash theme={null}
ufw allow 8002
```

<Note>
  If the node is behind a Network Firewall, make sure to also open port 8002.
</Note>

### 3. Generate Updated Name Record Signature

#### 3.1 Get IP address and current Seq number

This step uses `tomlq` (bundled with the `yq` package) to reliably parse the TOML config, rather than a plain-text `grep`. Install it if you don't already have it:

```bash theme={null}
apt install -y yq
```

Read the current values:

```bash theme={null}
NODE_IP=$(curl -4 -s ifconfig.me)
CURRENT_SEQ_NUM=$(tomlq '.peer_discovery.self_record_seq_num' /home/monad/monad-bft/config/node.toml)
NEXT_SEQ_NUM=$((CURRENT_SEQ_NUM + 1))
echo "Node IP: $NODE_IP"
echo "Current seq num: $CURRENT_SEQ_NUM"
echo "Next seq num: $NEXT_SEQ_NUM"
```

#### 3.2 Generate the new signature

Generate your node's name record signature with the new direct UDP port, using the values read in step 3.1:

```bash theme={null}
source /home/monad/.env
monad-sign-name-record \
  --ip $NODE_IP \
  --tcp-port 8000 \
  --authenticated-udp-port 8001 \
  --direct-udp-port 8002 \
  --self-record-seq-num $NEXT_SEQ_NUM \
  --keystore-path /home/monad/monad-bft/config/id-secp \
  --password "$KEYSTORE_PASSWORD"
```

<Warning>
  The `--self-record-seq-num` value must be **greater** than your current `self_record_seq_num` in `node.toml`.
</Warning>

<Info>
  Ports 8000 (TCP), 8001 (authenticated UDP), and 8002 (direct UDP) are the node's public external ports on the network. These ports can be changed to custom values.
</Info>

**Example Output:**

```toml theme={null}
self_address = "192.0.2.45"
self_tcp_port = 8000
self_record_seq_num = 2
self_auth_port = 8001
self_direct_udp_auth_port = 8002
self_name_record_sig = "6742dafda88c164f0a3392fac1e99957de7b436c1a9b34a80cba3eb098e11a8f617ad4eb823cb74ee60a7dc6aa286be52523f5675e012948160c8ec8b44e9fd500"
```

**Save this output** - you'll need it in the next step.

### 4. Update Configuration

Back up the current configuration:

```bash theme={null}
cp /home/monad/monad-bft/config/node.toml /tmp/node.toml.bak
```

Edit your Monad configuration:

```bash theme={null}
vim /home/monad/monad-bft/config/node.toml
```

#### 4.1 Update Peer Discovery Section

Replace all `self_*` fields in the `[peer_discovery]` section with the output from step 3.2, for example:

```diff theme={null}
  [peer_discovery]
- self_address              = "192.0.2.45:8000"
+ self_address              = "192.0.2.45"
+ self_tcp_port             = 8000
- self_record_seq_num       = 0
+ self_record_seq_num       = 1
  self_auth_port            = 8001
+ self_direct_udp_auth_port = 8002
- self_name_record_sig      = "e7ad7b423f346f755dd13f7abd4b7c5623c29df11b00630c86912e5aebfa754c3eefed0b183d8012f0e1f702c43e7d735ffecde91cee7b81dff414b461a60ab000"
+ self_name_record_sig      = "07e4dad19db11125dbc94da4467836c8fc43b43b84a2b0ac22e88a20948b7dfa2260f2fa59c51ec22197c2471da28294f5852530729f2620e909df323503971d00"
```

<Note>
  `self_direct_udp_auth_port` is an alias of `self_direct_udp_port` — both configure the same value, kept for backward compatibility.
</Note>

#### 4.2 Update Network Section

In network section, add the `direct_udp_bind_address_port` parameter and now use `bind_address_tcp_port` parameter, for example:

```diff theme={null}
  [network]
  bind_address_host               = "0.0.0.0"
- bind_address_port               = 8000
+ bind_address_tcp_port           = 8000
  authenticated_bind_address_port = 8001
+ direct_udp_bind_address_port    = 8002
  max_rtt_ms                      = 300
  max_mbps                        = 1000
```

#### 4.3 Update Peer Records (Validators Only)

If you operate a **validator** with downstream full nodes, update peer configurations as they enable direct UDP.

**For peers that have enabled direct UDP**:

```toml theme={null}
[[bootstrap.peers]]
address = "188.214.131.5:8000"
record_seq_num = 3
secp256k1_pubkey = "0x0342f3..."
name_record_sig = "0xa1b2c3..."
auth_port = 8001
direct_udp_port = 8002                     # Add this for upgraded peers
```

Save and exit the file.

### 5. Check and apply configuration

#### 5.1 Configuration check

Run this before restarting, to catch configuration mistakes early. Requires `tomlq` (`apt install -y yq`, see step 3.1):

```bash theme={null}
#!/bin/bash

GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'

FAILED=0

pass() { echo -e "${GREEN}OK${NC}    $1"; }
fail() { echo -e "${RED}ERROR${NC} $1"; FAILED=1; }

CONFIG=/home/monad/monad-bft/config/node.toml

echo ""
echo "=== Monad Direct UDP Health Check ==="
echo ""

SELF_ADDRESS=$(tomlq -r '.peer_discovery.self_address // "null"' "$CONFIG")
[[ "$SELF_ADDRESS" != "null" && "$SELF_ADDRESS" != *:* ]] && pass "[peer_discovery] self_address is IP-only ($SELF_ADDRESS)" || fail "[peer_discovery] self_address should be IP-only, found: $SELF_ADDRESS"
[ "$(tomlq -r '.peer_discovery.self_tcp_port // "null"' "$CONFIG")" != "null" ] && pass "[peer_discovery] self_tcp_port configured" || fail "[peer_discovery] self_tcp_port not found"
[ "$(tomlq -r '.peer_discovery.self_udp_port // "null"' "$CONFIG")" != "null" ] && fail "[peer_discovery] self_udp_port still present (should be removed)" || pass "[peer_discovery] self_udp_port unset"
[ "$(tomlq -r '.peer_discovery.self_auth_port // "null"' "$CONFIG")" != "null" ] && pass "[peer_discovery] self_auth_port configured" || fail "[peer_discovery] self_auth_port not found"
[ "$(tomlq -r '.peer_discovery.self_direct_udp_port // .peer_discovery.self_direct_udp_auth_port // "null"' "$CONFIG")" != "null" ] && pass "[peer_discovery] self_direct_udp_port configured" || fail "[peer_discovery] self_direct_udp_port not found"
[ "$(tomlq -r '.peer_discovery.self_record_seq_num // "null"' "$CONFIG")" != "null" ] && pass "[peer_discovery] self_record_seq_num configured" || fail "[peer_discovery] self_record_seq_num not found"
[ "$(tomlq -r '.peer_discovery.self_name_record_sig // "null"' "$CONFIG")" != "null" ] && pass "[peer_discovery] self_name_record_sig configured" || fail "[peer_discovery] self_name_record_sig not found"
[ "$(tomlq -r '.network.bind_address_port // "null"' "$CONFIG")" != "null" ] && fail "[network] bind_address_port still present (should be removed)" || pass "[network] bind_address_port unset"
[ "$(tomlq -r '.network.bind_address_tcp_port // "null"' "$CONFIG")" != "null" ] && pass "[network] bind_address_tcp_port configured" || fail "[network] bind_address_tcp_port not found"
[ "$(tomlq -r '.network.authenticated_bind_address_port // "null"' "$CONFIG")" != "null" ] && pass "[network] authenticated_bind_address_port configured" || fail "[network] authenticated_bind_address_port not found"
[ "$(tomlq -r '.network.direct_udp_bind_address_port // "null"' "$CONFIG")" != "null" ] && pass "[network] direct_udp_bind_address_port configured" || fail "[network] direct_udp_bind_address_port not found"

echo ""
[ "$FAILED" -eq 0 ] && echo -e "${GREEN}Direct UDP configuration is valid.${NC}"
```

**Expected output:**

```
=== Monad Direct UDP Health Check ===

OK    [peer_discovery] self_address is IP-only (192.0.2.45)
OK    [peer_discovery] self_tcp_port configured
OK    [peer_discovery] self_udp_port unset
OK    [peer_discovery] self_auth_port configured
OK    [peer_discovery] self_direct_udp_port configured
OK    [peer_discovery] self_record_seq_num configured
OK    [peer_discovery] self_name_record_sig configured
OK    [network] bind_address_port unset
OK    [network] bind_address_tcp_port configured
OK    [network] authenticated_bind_address_port configured
OK    [network] direct_udp_bind_address_port configured

Direct UDP configuration is valid.
```

#### 5.2 Restart the service

Restart the Monad service:

```bash theme={null}
systemctl restart monad-bft
```

Monitor the logs for successful startup:

```bash theme={null}
journalctl -u monad-bft -f -n 50 --no-pager
```

## Support

If you encounter issues not covered in this guide:

1. Check logs: `journalctl -u monad-bft -n 500 --no-pager`
2. Verify all configuration parameters match the examples
3. Ensure your firewall and network policies allow UDP/8002
4. Contact Monad support with your logs and configuration (sanitized of sensitive data)
