# Configuring a BDN root and its edges

> Where BDN node role, upstream root, leader target, and dedup TTL are persisted, how per-edge health is derived, and how a config change reaches a running node.

The **BDN network** screen in the FirstByte console renders one root
relay and its subscribed edge relays as a star topology. The lower half
of the screen exposes four settings — node role, upstream `root`
address, `leader` target, and `dedup_ttl_secs` — as editable controls.
This page explains what those controls are bound to, what they are
*not* bound to, and where the authoritative values actually live.

The screen reads exactly two procedures:

| Procedure    | Returns                                                                 |
| ------------ | ----------------------------------------------------------------------- |
| `bdn.root`   | The root relay: `region`, `host`, `port`, and a `dedup` block.           |
| `bdn.edges`  | One record per edge relay, with its reported status and counters.        |

Both are queries. Neither the node-role selector, the `root` and
`leader` inputs, the cluster selector, nor the `dedup_ttl_secs` slider
has a corresponding mutation. Read the sections below before you assume
a change you made on this screen took effect.

## Where BDN configuration lives

BDN node settings originate in the `mod_bdn` module deployment, not in
the console. The console is a projection of what the deployed root and
edges report about themselves.

That is the same mechanism that governs membership. Edge relays are
enrolled by deploying the BDN module on them; there is no enrol-by-form
API, which is why the screen has no "Add edge" action. For the same
reason there are no per-edge re-subscribe or disconnect buttons — edges
are driven by the module itself, and the console has no per-edge control
API.

The controls in the **Node role** and **Dedup cache** cards behave as
follows:

| Control                          | Binding                                                                  |
| -------------------------------- | ------------------------------------------------------------------------ |
| Mode (`root` / `edge`)           | Local component state. Only effect is enabling the `root` input.          |
| `root` (`quic://host:port`)      | `defaultValue` composed from `bdn.root`'s `host` and `port`. Uncontrolled. |
| `leader`                         | `defaultValue` of `auto`. Not read back from `bdn.root`.                   |
| `cluster`                        | Local state driven by the page-header segment. Rendered `readOnly` here.   |
| `dedup_ttl_secs`                 | Local state, initialised from `bdn.root`'s `dedup.ttlSecs`.                |

Editing any of them changes what the screen displays. It does not
change what the node is running.

## Node role: root vs edge

The role determines the direction of the fan-out:

- A **root** ingests transactions and fans them out to every subscribed
  edge.
- An **edge** subscribes from the root and lands transactions to its TPU
  target.

Each edge record carries its own `mode`, shown as a tag in the **Mode**
column and in the inspector. The topology header tags the root with its
`region` from `bdn.root`.

The mode segment on this screen selects which node role the form is
describing. When it is set to `root`, the `root` input is disabled,
because an upstream address is only meaningful for a node running in
edge mode.

## Upstream and leader targets

The `root` field is the upstream QUIC address an edge subscribes to. The
console composes its displayed value as `quic://<host>:<port>` from the
`host` and `port` returned by `bdn.root`, so what you see is the address
of the root the console is currently pointed at — not necessarily what a
given edge has configured.

The `leader` field is the default landing target for fanned-out
transactions. The screen ships it as `auto`, meaning no explicit target
is pinned in the form.

Per-edge landing targets are reported, not configured, here: the **TPU**
column and the inspector's **TPU target** stat both come from each
edge's `tpu` field.

## Cluster selection

The header segment switches between `mainnet` and `testnet`. The
selection is local to the screen and feeds two places:

- The fan-out track shown in the inspector and its copy button,
  `bdn/tx track=<cluster>`.
- The subtitle of the **Edge relays** table.

`bdn.root` and `bdn.edges` are called without arguments, so changing the
cluster does not re-scope the data that the topology, the table, or the
dedup stats show. Treat the selector as a label for the track namespace
you intend to work with.

## Tuning the dedup cache

The root deduplicates on the **first 64 bytes** of each transaction —
the Solana signature. The **Dedup cache** card reports the live state of
that cache from `bdn.root`'s `dedup` block:

| Stat            | Source                                                                |
| --------------- | --------------------------------------------------------------------- |
| Cache entries   | `dedup.entries`                                                       |
| Capacity        | `dedup.capacity`                                                      |
| Hit rate        | `dedup.hitRate`, rendered as a percentage                             |
| Utilisation     | `entries / capacity`, rounded to a whole percent                      |
| Cache occupancy | The same ratio as a meter, `entries` out of `capacity`                |

When `capacity` is `0` or missing, utilisation renders as `—` and the
occupancy meter falls back to a denominator of `1` rather than dividing
by zero.

The `dedup_ttl_secs` slider is initialised from `dedup.ttlSecs` and
moves in the range 10–300 seconds in steps of 5. If the reported TTL is
below 10, the slider position clamps to 10 while the numeric readout
continues to show the reported value. Moving the slider updates only the
readout next to it; persist the value through the module deployment.

## How edge health is measured

The console does not compute edge health. Each edge record arrives from
`bdn.edges` with a `status` of `healthy`, `degraded`, or `offline`,
derived from the stats that edge reports back — which is why "edge nodes
reporting stats" is listed as a prerequisite for this screen. The
console only maps the string onto a pill and a health pip, and marks the
`healthy` pill as live.

RTT is handled the same way, with one guard. The **RTT → root** stat and
the **RTT** column render `—` rather than a number when either:

- the edge's `status` is `offline`, or
- `rtt` is absent or not a finite number, which is the case for an edge
  the status feed has not measured yet.

Two aggregates in the topology header are derived locally:

- Online edge count is every edge whose `status` is not `offline`,
  displayed as `<online>/<total> edges`.
- Subscriber total is the sum of `subs` across all edges, including
  offline ones.

The **Subscribers** and **Landed/s** columns are each edge's reported
`subs` and `landed`. The region swatch beside each city is a colour
derived from the edge's `region`.

## Applying a change to a running node

There is no apply or save path on this screen. To change a node's role,
its upstream root, its leader target, or its dedup TTL, change the
`mod_bdn` deployment config for that node — the same mechanism that
enrolled the edge in the first place.

Once the node is running the new config, use **Re-sync edges** to pull
the change into the console. That button refetches `bdn.root` and
`bdn.edges` and nothing else; it sends no configuration and issues no
per-edge command. After a re-sync, verify:

- the root header tag still shows the expected `region`;
- the edge you changed reports the expected `mode` and `tpu`;
- `dedup.ttlSecs` now matches the value you deployed, which you can
  confirm by the position and readout of the `dedup_ttl_secs` slider
  after a reload.

## When the screen shows no data

If the BDN module is not deployed, the screen renders a pending state
instead of the topology. It lists what is still required:

- `mod_bdn` root and edge relays running
- edge nodes reporting stats

The pending state references the `bdn/tx` namespace, the track the root
fans out on.

If the module is deployed but `bdn.edges` returns an empty list, the
topology and table render with no rows and the inspector shows the empty
state "No edge relays" — edge relays appear there once the module is
deployed on them.

## Related

- [Authentication](/concepts/authentication) — relay tokens and namespace scope for `bdn/tx`
- [Telemetry](/platform/telemetry) — metrics and traces emitted by the gateway
