diff --git a/.gitignore b/.gitignore index c36aad7..0830e95 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ dist/ .devcontainer/ smartcontract/.vscode/settings.json +site/ diff --git a/README.md b/README.md index ac2fa21..ae522a6 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Install the required plugin so `mkdocs serve` works: ```bash pip install mkdocs-static-i18n +pip install pymdown-extensions +pip install mkdocs-material ``` Then run: diff --git a/docs/contribute-geolocation.md b/docs/contribute-geolocation.md new file mode 100644 index 0000000..9ed0df5 --- /dev/null +++ b/docs/contribute-geolocation.md @@ -0,0 +1,174 @@ +# Geoprobe Deployment + +This guide covers deploying and configuring **geoProbe agents** — the servers that perform latency measurements for the DoubleZero [Geolocation](geolocation.md) service. + +A geoProbe sits between [DZDs](glossary.md#dzd-doublezero-device) and target devices in the three-tier measurement chain. It receives signed LocationOffsets from parent DZDs and measures [RTT](glossary.md#rtt-round-trip-time) to registered targets via [TWAMP](glossary.md#twamp-two-way-active-measurement-protocol), signed TWAMP, or ICMP echo. Each geoProbe is registered onchain and linked to one or more parent DZDs. + +For an overview of the geolocation architecture and measurement flows, see the [Geolocation user guide](geolocation.md). + +--- + +## Prerequisites + +!!! warning "DZD Telemetry Agent Version" + Parent DZDs must run **device telemetry agent version 0.17.0 or newer** to support the geolocation service. Earlier versions do not include the probe discovery, TWAMP pinging, and offset-publishing extensions required for geolocation. Verify agent versions before deploying a probe — a probe paired with an older DZD will not receive offsets. + +Before deploying a geoProbe, ensure you have: + +- **Bare metal Linux server** — A VPS can work, but are less ideal. +- **Network proximity to a DZD** — less than 1ms RTT between the probe and its parent DZD. Ideally 0.1ms or less. +- **`CAP_NET_RAW` capability** for the agent process (required for ICMP echo probing with raw sockets) +- **Ed25519 keypair** for the probe's signing identity +- **Foundation authorization** — probe registration is foundation-gated at the moment; coordinate with [DZF](glossary.md#dzf-doublezero-foundation) before proceeding +- **Parent DZD(s)** running telemetry agent v0.17.0+ + +--- + +## Installation + +Install both the agent daemon and the doublezero CLI: + +```bash +curl -1sLf https://dl.cloudsmith.io/public/malbeclabs/doublezero/setup.deb.sh | sudo -E bash +sudo apt install doublezero-geoprobe-agent doublezero +``` + +| Package | Purpose | +|---------|---------| +| `doublezero-geoprobe-agent` | Agent daemon that runs on the probe server, performing latency measurements and generating signed offsets | +| `doublezero` | CLI tool used for probe registration and management commands | + +--- + +## Onchain Registration + +Probe registration requires foundation authorization. Coordinate with DZF before proceeding. + +### Step 1: Register the probe + +```bash +doublezero geolocation probe create \ + --code \ + --exchange \ + --public-ip \ + --signing-pubkey +``` + +| Parameter | Description | +|-----------|-------------| +| `--code` | Unique identifier for the probe (e.g., `ams-tn-gp1`) — max 32 characters | +| `--exchange` | Public key of the Serviceability Exchange account this probe is associated with | +| `--public-ip` | Public IPv4 address where the probe listens | +| `--signing-pubkey` | Public key used to sign offsets and telemetry | + +### Step 2: Link parent DZDs + +```bash +doublezero geolocation probe add-parent \ + --probe \ + --device +``` + +Each parent DZD must be an activated device in the Serviceability Program. DZDs auto-discover child probes every 60 seconds — once linked, the DZD begins TWAMP measurements and offset generation automatically. + +--- + +## Running the Agent + +```bash +doublezero-geoprobe-agent \ + --env mainnet-beta \ + --keypair /etc/geoprobe/keypair.json \ + --geoprobe-pubkey +``` + +### Required Flags + +| Flag | Description | +|------|-------------| +| `--keypair` | Path to the Ed25519 keypair file for signing offsets | +| `--geoprobe-pubkey` | The probe's [onchain](glossary.md#onchain) public key (from `probe create`) | +| `--env` | Network environment: `testnet`, `devnet`, or `mainnet-beta` (sets the ledger RPC URL) | + +Alternatively, use `--ledger-rpc-url` instead of `--env` to specify a custom Solana RPC endpoint. + +### Optional Flags + +| Flag | Default | Description | +|------|---------|-------------| +| `--twamp-listen-port` | 8925 | Port for TWAMP measurements from parent DZDs | +| `--signed-twamp-port` | 8924 | Port for signed TWAMP probes from inbound targets | +| `--udp-listen-port` | 8923 | Port for receiving LocationOffset datagrams from DZDs | +| `--probe-interval` | 30s | How often to measure each target | +| `--max-offset-age` | 1h | Maximum age of a cached DZD offset before it is discarded | +| `--verify-interval` | 29s | How often to re-verify target assignments from the ledger | +| `--verbose` | false | Enable verbose logging | +| `--metrics-enable` | false | Enable Prometheus metrics endpoint | +| `--metrics-addr` | — | Address for the Prometheus metrics endpoint (e.g., `0.0.0.0:9090`) | + +--- + +## Ports and Firewall + +The geoprobe agent requires several ports open: + +| Port | Protocol | Direction | Purpose | +|------|----------|-----------|---------| +| 8923/udp | UDP | Inbound from DZDs | Receives signed LocationOffset datagrams | +| 8924/udp | UDP | Inbound from targets | Signed TWAMP reflector (inbound probe flow) | +| 8925/udp | UDP | Inbound from DZDs | TWAMP measurements from parent DZDs | +| ICMP | ICMP | Outbound to targets | ICMP echo requests for OutboundIcmp targets | + +!!! note + The agent also needs outbound UDP to targets for TWAMP probing (outbound flow) and for delivering signed LocationOffset results to targets. + +--- + +## Monitoring + +Enable the Prometheus metrics endpoint for operational visibility: + +```bash +doublezero-geoprobe-agent \ + --keypair /etc/geoprobe/keypair.json \ + --geoprobe-pubkey \ + --env testnet \ + --metrics-enable \ + --metrics-addr 0.0.0.0:9090 +``` + +Key metrics to monitor: + +- **Probe availability** — uptime of the agent process +- **DZD-to-Probe latency** — should be less than 1ms; higher values indicate a placement problem +- **Active targets** — number of targets the probe is currently measuring +- **Signature verification failures** — non-zero values may indicate key misconfiguration or tampered packets +- **Offset cache hit rate** — a low hit rate means the probe is frequently waiting for fresh DZD offsets + +See the [Operations guide](contribute-operations.md#monitoring) for general guidance on Prometheus scraping and alerting patterns used across DoubleZero agents. + +--- + +## Probe Management Commands + +The `doublezero geolocation` CLI provides the following subcommands for managing probes: + +| Subcommand | Description | +|------------|-------------| +| `probe create` | Register a new geoProbe onchain | +| `probe get` | Get details of a specific probe by code | +| `probe list` | List all registered probes | +| `probe update` | Update probe configuration (IP, port, signing key) | +| `probe delete` | Delete a probe (requires no active target references) | +| `probe add-parent` | Link a parent DZD to the probe | +| `probe remove-parent` | Remove a parent DZD from the probe | + +All subcommands accept `--env` or `--rpc-url` to select the network. Write operations (`create`, `update`, `delete`, `add-parent`, `remove-parent`) require `--keypair`. + +??? note "Example: listing probes" + + ```bash + doublezero geolocation probe list + ``` + + Returns all registered probes with their codes, public IPs, parent DZDs, and current status. diff --git a/docs/contribute-overview.md b/docs/contribute-overview.md index 3202372..5b91b7f 100644 --- a/docs/contribute-overview.md +++ b/docs/contribute-overview.md @@ -135,6 +135,7 @@ New to DoubleZero? Here are the essential terms (see [full Glossary](glossary.md | [Requirements & Architecture](contribute.md) | Hardware specs, network architecture, bandwidth options | | [Device Provisioning](contribute-provisioning.md) | Step-by-step: keys → repo access → device → links → agents | | [Operations](contribute-operations.md) | Agent upgrades, link management, monitoring | +| [Geoprobe Deployment](contribute-geolocation.md) | Deploying and configuring geoProbe agents for geolocation | | [Glossary](glossary.md) | All DoubleZero terminology defined | --- diff --git a/docs/geolocation.md b/docs/geolocation.md new file mode 100644 index 0000000..e527f85 --- /dev/null +++ b/docs/geolocation.md @@ -0,0 +1,290 @@ +# Geolocation + +The DoubleZero Geolocation service helps users determine the physical location of devices using latency measurements. [RTT](glossary.md#rtt-round-trip-time) (round-trip time) measurements between known-location infrastructure and a target device provide cryptographically-signed proof that a device is within a certain distance of a given point. Onchain recording of measurements to the DoubleZero Ledger is planned for a future release. + +Use cases include regulatory compliance (e.g., GDPR — proving validators operate within the EU), geographic distribution audits, and any application that needs verifiable proof of where a device or IP is. + +--- + +## How it works + +```mermaid +flowchart LR + subgraph DZ["DoubleZero Network"] + DZD["DZD\n(known location)"] + Probe["geoProbe\n(bare metal server)"] + DZD -- "TWAMP\n(continuous latency)" --> Probe + end + + subgraph Target["Target Device"] + T["Target\n(validator / server)"] + end + + Probe -- "RTT measurement" --> T + T -- "RTT response" --> Probe + Probe -. "signed offset" .-> T +``` + +The following diagram shows the three probe flow types — Outbound, OutboundIcmp, and Inbound — which differ in how the geoProbe communicates with the target: + +```mermaid +flowchart TB + subgraph out["Outbound Flow (TWAMP)"] + direction LR + P1["geoProbe"] -- "TWAMP probe" --> T1["Target"] + T1 -- "TWAMP reply" --> P1 + end + + subgraph icmp["OutboundIcmp Flow"] + direction LR + P3["geoProbe"] -- "ICMP Echo Request" --> T3["Target"] + T3 -- "ICMP Echo Reply" --> P3 + end + + subgraph in["Inbound Flow (NAT-friendly)"] + direction LR + T2["Target"] -- "signed packets" --> P2["geoProbe"] + P2 -- "reply" --> T2 + end +``` + +Geolocation uses a three-tier measurement chain: + +``` +DZD (known location) ◄──TWAMP──► geoProbe ◄──RTT──► Target device +``` + +- **[DZD](glossary.md#dzd-doublezero-device) <-> geoProbe**: [TWAMP](glossary.md#twamp-two-way-active-measurement-protocol) continuously measures latency between the DoubleZero Device and the probe. DZDs have known, fixed geographic coordinates registered on the DZ Ledger. +- **geoProbe <-> Target**: RTT is measured between the probe and the device being located. + +Offset results are cryptographically signed, and delivered via UDP to the target or a user-specified alternate destination. + +**Important:** Geolocation reports RTT only — not inferred distance or coordinates. A common way to use this would be to divide the RTT by 2, and then multiply by the speed of light through glass (~200km/ms) to provide a radius around the DZD coordinates that the target is located within. How you interpret RTT (e.g., computing a maximum-distance radius) is up to you. + +### Probe flow types + +There are three ways a probe can measure a target: + +| Flow | Who initiates | Protocol | Use when | +|------|---------------|----------|----------| +| **Outbound** | Probe -> Target | [TWAMP](glossary.md#twamp-two-way-active-measurement-protocol) | Target has a public IP, open inbound port, and can run a TWAMP reflector | +| **OutboundIcmp** | Probe -> Target | ICMP echo | Target has a public IP but cannot run a TWAMP reflector (or TWAMP is blocked by firewall) | +| **Inbound** | Target -> Probe | Signed TWAMP | Target cannot accept inbound connections, or want to verify location of a signing key | + +In all cases, the DZD <-> geoProbe measurement happens the same way. Only the direction and protocol of the geoProbe <-> target communication differs. + +!!! info "Technical Specification" + For the full technical specification of the geolocation verification system, including cryptographic signing details and the measurement protocol, see [RFC 16: Geolocation Verification](https://github.com/malbeclabs/doublezero/blob/main/rfcs/rfc16-geolocation-verification.md). + +--- + +## Prerequisites + +### 1. DoubleZero ID with credits + +Geolocation users need a funded DoubleZero ID. You do not need to connect to the DoubleZero network (no access pass required), but your key needs credits on the DoubleZero ledger to create a user account and manage targets — each add/remove target operation costs credits. + +If you don't have a DoubleZero ID: + +```bash +doublezero keygen +doublezero address # get your pubkey +``` + +Contact the DoubleZero team with your pubkey to get your ID funded. Fund it to a higher-than-typical amount if you expect to add and remove targets dynamically. + +### 2. 2Z token account + +You need a [2Z token](glossary.md#2z-token) account. Service fees are deducted from this account on a per-epoch basis. + +--- + +## Installation + +On a management computer: +```bash +curl -1sLf https://dl.cloudsmith.io/public/malbeclabs/doublezero/setup.deb.sh | sudo -E bash +sudo apt install doublezero +``` + +On a target for Inbound or TWAMP Outbound: +```bash +curl -1sLf https://dl.cloudsmith.io/public/malbeclabs/doublezero/setup.deb.sh | sudo -E bash +sudo apt install doublezero-geoprobe-target +``` +This installs the `doublezero-geoprobe-target` (outbound) and `doublezero-geoprobe-target-sender` (inbound) + +!!! note "ICMP Outbound" + `outbound-icmp` targets do not require any software installed. + +--- + +## Check your balance + +```bash +doublezero balance +``` + +--- + +## Setup + +### Step 1: Create a geolocation user + +```bash +doublezero geolocation user create \ + --env testnet \ + --code \ + --token-account +``` + +- `--code`: a short, unique identifier for your account (e.g. `myorg`) +- `--token-account`: the public key of your [2Z token](glossary.md#2z-token) account — service fees are deducted from here + +!!! note "Account activation" + After creating a user, contact the DoubleZero Foundation to activate your account. Payment status must be marked active before probing begins. + +### Step 2: List available probes + +```bash +doublezero geolocation probe list +``` + +Note the **code** or **public_ip**, and the **signing_pubkey** (for inbound targets) of the probe you want to use. + +### Step 3: Add a target + +=== "Outbound (probe sends TWAMP to target)" + + Use this flow if your target has a public IP, an open inbound port, and can run a [TWAMP](glossary.md#twamp-two-way-active-measurement-protocol) reflector. + + ```bash + doublezero geolocation user add-target \ + --user \ + --type outbound \ + --probe \ + --target-ip + ``` + + `--probe`: the code of the geoProbe that will measure the target (e.g. `ams-mn-gp1`) + `--ip-address`: the public IPv4 address of the target device + +=== "OutboundIcmp (probe pings target)" + + Use this flow if your target has a public IP but cannot run a TWAMP reflector, or if TWAMP traffic is blocked by firewall. The target only needs to respond to ICMP echo (ping) requests — no additional software required. + + ```bash + doublezero geolocation user add-target \ + --user \ + --type OutboundIcmp \ + --probe \ + --ip-address + ``` + + `--probe`: the code of the geoProbe that will measure the target (e.g. `ams-mn-gp1`) + `--ip-address`: the public IPv4 address of the target device + !!! Warning "Result Destination" + Outbound ICMP targets only work if your user has an alternate result destination set. (See Step 3b) + +=== "Inbound (target sends to probe)" + + Use this flow if your target is behind NAT or cannot accept inbound connections. + + ```bash + doublezero geolocation user add-target \ + --user \ + --type inbound \ + --probe \ + --target-pk + ``` + + `--probe`: the code of the geoProbe that will measure the target (e.g. `ams-mn-gp1`) + `--target-pk`: public key of the keypair the target will use to sign messages — the probe only accepts messages from registered public keys + +### Step 3b: Set a result destination (optional) + +Configure an alternate `host:port` where composite LocationOffset results are delivered for any Outbound target types. This replaces sending the LocationOffset to the target and is configured on a per-user basis. If different per-target behavior is needed, it is required to set up two users, one for each desired behavior type. + +The alternate destination is useful for aggregating results from multiple targets to a single endpoint. It is required for ICMP probing. + +```bash +doublezero geolocation user set-result-destination \ + --user \ + --destination +``` + +`--destination`: a publicly routable IPv4 address or valid domain name with port (e.g., `203.0.113.10:9000` or `results.example.com:9000`). Pass an empty string to clear. + +Use `user get` to verify your result destination: + +```bash +doublezero geolocation user get --user +``` + +### Step 4: Run the target application + +Both outbound and inbound flows require running an application on the target device. Reference implementations with examples are available in Go — you can run them directly or use them as a starting point for your own integration. + +=== "Outbound" + + For outbound probing, the target device must run a [TWAMP](glossary.md#twamp-two-way-active-measurement-protocol) reflector so the geoProbe can measure RTT. Run the target application on the device being measured: + + ```bash + doublezero-geoprobe-target + ``` + +=== "Inbound" + + For inbound probing, the target device must run software that sends signed messages to the probe. + + On the device being measured: + + ```bash + doublezero-geoprobe-target-sender \ + -probe-ip \ + -probe-pk \ + -keypair + ``` + +`-probe-ip`: IP address of the geoProbe (from `probe list`) +`-probe-pk`: public key of the geoProbe (from `probe list`) +`-keypair`: path to the keypair whose public key was registered as `--target-pk` in Step 3 + +The target sender uses a two-probe-pair mechanism: it sends two pre-signed [TWAMP](glossary.md#twamp-two-way-active-measurement-protocol) probes in quick succession. The probe's reply to the second packet includes `SinceLastRxNs` — the time between the probe sending reply 0 and receiving probe 1 — which serves as the probe-measured [RTT](glossary.md#rtt-round-trip-time). This paired approach provides an accurate RTT measurement even when the target cannot perform precise kernel-level timestamping. + +--- + +## Command reference + +### `doublezero geolocation user` + +| Subcommand | Description | +|------------|-------------| +| `create` | Create a new geolocation user account | +| `get` | Get details of a specific user | +| `list` | List all geolocation users | +| `delete` | Delete a user | +| `add-target` | Add a target to a user | +| `remove-target` | Remove a target from a user | +| `set-result-destination` | Set an alternate host:port for offset delivery | +| `update-payment` | Update payment status (foundation use) | + +### `doublezero geolocation probe` + +| Subcommand | Description | +|------------|-------------| +| `create` | Register a new geoProbe | +| `get` | Get details of a specific probe | +| `list` | List all probes | +| `update` | Update probe configuration | +| `delete` | Delete a probe | +| `add-parent` | Link a DZD as a parent of the probe | +| `remove-parent` | Remove a parent DZD | + +### Global flags + +| Flag | Description | +|------|-------------| +| `--env` | Network environment: `testnet`, `devnet`, or `mainnet-beta` | +| `--rpc-url` | Custom DoubleZero RPC endpoint | +| `--keypair` | Path to signing keypair (required for write operations) | diff --git a/docs/glossary.md b/docs/glossary.md index 0541948..76c8506 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -134,6 +134,19 @@ A link-state routing protocol used internally by the DoubleZero network. IS-IS m --- +## Geolocation + +### Geolocation +A DoubleZero service that verifies the physical location of devices using latency measurements. [RTT](#rtt-round-trip-time) measurements between known-location infrastructure ([DZDs](#dzd-doublezero-device)) and target devices provide cryptographically signed proof that a device is within a certain distance of a reference point. Onchain recording of measurements is planned for a future release. See [Geolocation](geolocation.md) for user documentation. + +### geoProbe +A bare metal server that acts as an intermediary for latency measurements in the [Geolocation](#geolocation) system. geoProbes are located within ~1ms of a [DZD](#dzd-doublezero-device), receive signed LocationOffsets from parent DZDs, and measure [RTT](#rtt-round-trip-time) to target devices via [TWAMP](#twamp-two-way-active-measurement-protocol), signed TWAMP, or ICMP echo. Each geoProbe is registered [onchain](#onchain) and linked to one or more parent DZDs. See [Geoprobe Deployment](contribute-geolocation.md) for contributor documentation. + +### LocationOffset +A signed data structure containing a [DZD's](#dzd-doublezero-device) geographic location (latitude and longitude) and a chain of latency relationships between entities (DZD↔Probe or Probe↔Target). LocationOffsets are signed with Ed25519 and sent via UDP through the measurement chain. Composite offsets include references to previous measurements, creating an auditable trail. + +--- + ## Blockchain & Keys ### Onchain diff --git a/mkdocs.yml b/mkdocs.yml index eff2bdd..4e2ec73 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -64,12 +64,14 @@ nav: - Shelby: - Shelby Connection: Shelby Permissioned Connection.md - New Tenant: New Tenant.md + - Geolocation: geolocation.md - Contributors: - Overview: contribute-overview.md - Requirements & Architecture: contribute.md - Device Provisioning: contribute-provisioning.md - Operations: contribute-operations.md - OPS Management: contribute-ops-management.md + - Geolocation: contribute-geolocation.md - Architecture: architecture.md - Glossary: glossary.md markdown_extensions: @@ -79,6 +81,8 @@ markdown_extensions: - pymdownx.caret - pymdownx.tasklist: custom_checkbox: true + - pymdownx.tabbed: + alternate_style: true - pymdownx.superfences: custom_fences: - name: mermaid