Architecture
LNS bridges two blockchains into a DNS-compatible naming system. The main chain holds identity (aliases), the sidechain holds DNS records, and LNS merges them into a queryable cache.
System Overview
+-----------------+ +------------------+ +-------+
| Lethean Main | | HSD Sidechain | | |
| Chain Daemon | ----> | (ITNS) | ----> | LNS |
| (alias registry)| | (DNS records) | | |
+-----------------+ +------------------+ +---+---+
|
+--------------+--------------+
| |
+-----+------+ +------+-----+
| DNS Server | | HTTP API |
| :5354 | | :5553 |
| UDP + TCP | | JSON |
+------------+ +------------+
Three Modes
LNS is designed around three operating modes. Currently only light mode is implemented.
| Mode | Description | Chain Sync | Use Case |
|---|---|---|---|
| light | Queries remote RPC endpoints for both chains | None | Default. Quick start, no local storage needed. |
| full | Runs with local chain data, syncs state to disk | Full | Gateway operators who need offline resilience. |
| cache | Reads from a pre-populated cache directory, no RPC | None | Air-gapped or read-only deployments. |
Light Mode (Current)
Light mode connects to two RPC endpoints:
- Main chain daemon (
DAEMON_URL) -- callsget_all_alias_detailsto discover registered names - HSD sidechain (
HSD_URL) -- callsgetnameresourcefor each discovered name to fetch DNS records
No local chain data is stored. The cache lives entirely in memory.
Discovery: Main Chain to HNS Names
LNS discovers which names to resolve by reading aliases from the main chain.
Alias Format
Aliases are registered on the Lethean main chain with an optional structured comment:
v=lthn1;type=gateway;cap=vpn,dns;hns=charon.lthn
The comment is a semicolon-delimited set of key=value pairs:
| Key | Description |
|---|---|
v |
Version tag (currently lthn1) |
type |
Node type (gateway, relay, miner, etc.) |
cap |
Capabilities (comma-separated: vpn, dns, proxy) |
hns |
Override HNS name (e.g., charon.lthn makes LNS resolve charon on the sidechain) |
Discovery Algorithm
1. Call get_all_alias_details on main chain
2. For each alias:
a. If comment contains hns=X.lthn, use X as the HNS name
b. Otherwise, use the alias name directly
3. Deduplicate names
4. If main chain is unreachable, fall back to hardcoded list
The fallback list includes well-known infrastructure names: lethean, snider, charon, cladius, explorer, testnet, gateway, monitor, network, and others.
Record Resolution: Sidechain to DNS
For each discovered name, LNS calls getnameresource on the HSD sidechain. The sidechain returns records typed as:
| Sidechain Type | DNS Type | Example |
|---|---|---|
GLUE4 |
A |
IPv4 address |
GLUE6 |
AAAA |
IPv6 address |
TXT |
TXT |
Metadata strings |
NS |
NS |
Nameserver delegation |
LNS maps these into standard DNS record types and stores them in the in-memory cache.
Cache System
In-Memory Cache
The current implementation uses a simple in-memory map keyed by bare name (e.g., charon). Each entry holds the full set of DNS records for that name.
Sync Trigger
Every 15 seconds (configurable via CHECK_INTERVAL), LNS checks the HSD tree root:
1. Call getblockchaininfo on HSD
2. Compare treeroot to last known value
3. If unchanged, skip sync
4. If changed, re-discover names and re-resolve all records
This means the cache updates only when the sidechain state actually changes, not on every tick.
Hash-Derived Cache (Full/Cache Modes -- Planned)
The full and cache modes use a hash-derived directory structure for persistent storage:
lthn.HASH(charon)/
zone.db -- charon.lthn records
certs/ -- TLS certs (gateway operators)
lthn.HASH(vpn.HASH(charon))/
zone.db -- vpn.charon.lthn records
lthn.HASH(api.HASH(vpn...))/
zone.db -- api.vpn.charon.lthn
Cryptographic properties of this structure:
- Cache key:
lthn.HASH(name)-- the directory name cannot be reversed to discover the plain name - Parent-child access: A parent can decrypt children (it knows the composite hash input). Children cannot traverse up.
- Zone encryption: Each
zone.dbis encrypted with a key derived from the hash chain - Cross-domain management: A parent zone owner can manage all child zones beneath it
This structure allows gateway operators to host zone data for names they control without exposing the full namespace.
DNS Server
The DNS server uses the miekg/dns library and runs on both UDP and TCP. It is authoritative for the lthn. zone (sets the AA flag in responses).
Query Processing
1. Parse the query
2. If PTR (reverse DNS): scan cache for matching IPs, return name
3. If not under lthn. zone: return REFUSED
4. If zone apex (lthn. itself): return SOA
5. Look up bare name in cache
6. If not found: return NXDOMAIN with SOA authority
7. Return matching records for the requested type
8. If no records match the type: return SOA in authority section
Reverse DNS
LNS supports PTR queries for in-addr.arpa. addresses. It reverses the IP octets, scans all cached A records for a match, and returns the corresponding .lthn name. This enables dig -x <ip> to resolve back to the name.
Module Structure
cmd/lns/
main.go -- Entry point, HTTP handlers, cache sync, configuration
discovery.go -- Main chain alias discovery, comment parsing
dnsserver.go -- DNS server, query handling, PTR resolution
discovery_test.go -- Tests for alias parsing and discovery
dnsserver_test.go -- Tests for DNS name parsing and ARPA conversion
Built with dappco.re/go/core and github.com/miekg/dns.