diff options
Diffstat (limited to 'news/phase1-basic-network/index.html')
| -rw-r--r-- | news/phase1-basic-network/index.html | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/news/phase1-basic-network/index.html b/news/phase1-basic-network/index.html new file mode 100644 index 0000000..4852505 --- /dev/null +++ b/news/phase1-basic-network/index.html @@ -0,0 +1,173 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Phase 1: Nodes Find Each Other — Tesseras</title> + <meta name="description" content="Tesseras nodes can now discover peers, form a Kademlia DHT over QUIC, and publish and find tessera pointers across the network."> + <!-- Open Graph --> + <meta property="og:type" content="article"> + <meta property="og:title" content="Phase 1: Nodes Find Each Other"> + <meta property="og:description" content="Tesseras nodes can now discover peers, form a Kademlia DHT over QUIC, and publish and find tessera pointers across the network."> + <meta property="og:image" content="https://tesseras.net/images/social.jpg"> + <meta property="og:image:width" content="1200"> + <meta property="og:image:height" content="630"> + <meta property="og:site_name" content="Tesseras"> + <!-- Twitter Card --> + <meta name="twitter:card" content="summary_large_image"> + <meta name="twitter:title" content="Phase 1: Nodes Find Each Other"> + <meta name="twitter:description" content="Tesseras nodes can now discover peers, form a Kademlia DHT over QUIC, and publish and find tessera pointers across the network."> + <meta name="twitter:image" content="https://tesseras.net/images/social.jpg"> + <link rel="stylesheet" href="https://tesseras.net/style.css?h=21f0f32121928ee5c690"> + + + <link rel="alternate" type="application/atom+xml" title="Tesseras" href="https://tesseras.net/atom.xml"> + + + <link rel="icon" type="image/png" sizes="32x32" href="https://tesseras.net/images/favicon.png?h=be4e123a23393b1a027d"> + +</head> +<body> + <header> + <h1> + <a href="https://tesseras.net/"> + <img src="https://tesseras.net/images/logo-64.png?h=c1b8d0c4c5f93b49d40b" alt="Tesseras" width="40" height="40" class="logo"> + Tesseras + </a> + </h1> + <nav> + + <a href="https://tesseras.net/about/">About</a> + <a href="https://tesseras.net/news/">News</a> + <a href="https://tesseras.net/releases/">Releases</a> + <a href="https://tesseras.net/faq/">FAQ</a> + <a href="https://tesseras.net/subscriptions/">Subscriptions</a> + <a href="https://tesseras.net/contact/">Contact</a> + + </nav> + <nav class="lang-switch"> + + <strong>English</strong> | <a href="/pt-br/news/phase1-basic-network/">Português</a> + + </nav> + </header> + + <main> + +<article> + <h2>Phase 1: Nodes Find Each Other</h2> + <p class="news-date">2026-02-14</p> + <p>Tesseras is no longer a local-only tool. Phase 1 delivers the networking layer: +nodes discover each other through a Kademlia DHT, communicate over QUIC, and +publish tessera pointers that any peer on the network can find. A tessera +created on node A is now findable from node C.</p> +<h2 id="what-was-built">What was built</h2> +<p><strong>tesseras-core</strong> (updated) — New network domain types: <code>TesseraPointer</code> +(lightweight reference to a tessera's holders and fragment locations), +<code>NodeIdentity</code> (node ID + public key + proof-of-work nonce), <code>NodeInfo</code> +(identity + address + capabilities), and <code>Capabilities</code> (bitflags for what a +node supports: DHT, storage, relay, replication).</p> +<p><strong>tesseras-net</strong> — The transport layer, built on QUIC via quinn. The <code>Transport</code> +trait defines the port: <code>send</code>, <code>recv</code>, <code>disconnect</code>, <code>local_addr</code>. Two adapters +implement it:</p> +<ul> +<li><code>QuinnTransport</code> — real QUIC with self-signed TLS, ALPN negotiation +(<code>tesseras/1</code>), connection pooling via DashMap, and a background accept loop +that handles incoming streams.</li> +<li><code>MemTransport</code> + <code>SimNetwork</code> — in-memory channels for deterministic testing +without network I/O. Every integration test in the DHT crate runs against +this.</li> +</ul> +<p>The wire protocol uses length-prefixed MessagePack: a 4-byte big-endian length +header followed by an rmp-serde payload. <code>WireMessage</code> carries a version byte, +request ID, and a body that can be a request, response, or protocol-level error. +Maximum message size is 64 KiB.</p> +<p><strong>tesseras-dht</strong> — A complete Kademlia implementation:</p> +<ul> +<li><em>Routing table</em>: 160 k-buckets with k=20. Least-recently-seen eviction, +move-to-back on update, ping-check before replacing a full bucket's oldest +entry.</li> +<li><em>XOR distance</em>: 160-bit XOR metric with bucket indexing by highest differing +bit.</li> +<li><em>Proof-of-work</em>: nodes grind a nonce until <code>BLAKE3(pubkey || nonce)[..20]</code> has +8 leading zero bits (~256 hash attempts on average). Cheap enough for any +device, expensive enough to make Sybil attacks impractical at scale.</li> +<li><em>Protocol messages</em>: Ping/Pong, FindNode/FindNodeResponse, +FindValue/FindValueResult, Store — all serialized with MessagePack via serde.</li> +<li><em>Pointer store</em>: bounded in-memory store with configurable TTL (24 hours +default) and max entries (10,000 default). When full, evicts pointers furthest +from the local node ID, following Kademlia's distance-based responsibility +model.</li> +<li><em>DhtEngine</em>: the main orchestrator. Handles incoming RPCs, runs iterative +lookups (alpha=3 parallelism), bootstrap, publish, and find. The <code>run()</code> +method drives a <code>tokio::select!</code> loop with maintenance timers: routing table +refresh every 60 seconds, pointer expiry every 5 minutes.</li> +</ul> +<p><strong>tesd</strong> — A full-node binary. Parses CLI args (bind address, bootstrap peers, +data directory), generates a PoW-valid node identity, binds a QUIC endpoint, +bootstraps into the network, and runs the DHT engine. Graceful shutdown on +Ctrl+C via tokio signal handling.</p> +<p><strong>Infrastructure</strong> — OpenTofu configuration for two Hetzner Cloud bootstrap +nodes (cx22 instances in Falkenstein, Germany and Helsinki, Finland). Cloud-init +provisioning script creates a dedicated <code>tesseras</code> user, writes a config file, +and sets up a systemd service. Firewall rules open UDP 4433 (QUIC) and restrict +metrics to internal access.</p> +<p><strong>Testing</strong> — 139 tests across the workspace:</p> +<ul> +<li>47 unit tests in tesseras-dht (routing table, distance, PoW, pointer store, +message serialization, engine RPCs)</li> +<li>5 multi-node integration tests (3-node bootstrap, 10-node lookup convergence, +publish-and-find, node departure detection, PoW rejection)</li> +<li>14 tests in tesseras-net (codec roundtrips, transport send/recv, backpressure, +disconnect)</li> +<li>Docker Compose smoke tests with 3 containerized nodes communicating over real +QUIC</li> +<li>Zero clippy warnings, clean formatting</li> +</ul> +<h2 id="architecture-decisions">Architecture decisions</h2> +<ul> +<li><strong>Transport as a port</strong>: the <code>Transport</code> trait is the only interface between +the DHT engine and the network. Swapping QUIC for any other protocol means +implementing four methods. All DHT tests use the in-memory adapter, making +them fast and deterministic.</li> +<li><strong>One stream per RPC</strong>: each DHT request-response pair uses a fresh +bidirectional QUIC stream. No multiplexing complexity, no head-of-line +blocking between independent operations. QUIC handles the multiplexing at the +connection level.</li> +<li><strong>MessagePack over Protobuf</strong>: compact binary encoding without code generation +or schema files. Serde integration means adding a field to a message is a +one-line change. Trade-off: no built-in schema evolution guarantees, but at +this stage velocity matters more.</li> +<li><strong>PoW instead of stake or reputation</strong>: a node identity costs ~256 BLAKE3 +hashes. This runs in under a second on any hardware, including a Raspberry Pi, +but generating thousands of identities for a Sybil attack becomes expensive. +No tokens, no blockchain, no external dependencies.</li> +<li><strong>Iterative lookup with routing table updates</strong>: discovered nodes are added to +the routing table as they're encountered during iterative lookups, following +standard Kademlia behavior. This ensures the routing table improves +organically as nodes interact.</li> +</ul> +<h2 id="what-comes-next">What comes next</h2> +<ul> +<li><strong>Phase 2: Replication</strong> — Reed-Solomon erasure coding over the network, +fragment distribution, automatic repair loops, bilateral reciprocity ledger +(no blockchain, no tokens)</li> +<li><strong>Phase 3: API and Apps</strong> — Flutter mobile/desktop app via +flutter_rust_bridge, GraphQL API (async-graphql), WASM browser node</li> +<li><strong>Phase 4: Resilience and Scale</strong> — ML-DSA post-quantum signatures, advanced +NAT traversal, Shamir's Secret Sharing for heirs, packaging for +Alpine/Arch/Debian/FreeBSD/OpenBSD, CI on SourceHut</li> +<li><strong>Phase 5: Exploration and Culture</strong> — public tessera browser, institutional +curation, genealogy integration, physical media export</li> +</ul> +<p>Nodes can find each other. Next, they learn to keep each other's memories alive.</p> + +</article> + + </main> + + <footer> + <p>© 2026 Tesseras Project. <a href="/atom.xml">News Feed</a> · <a href="https://git.sr.ht/~ijanc/tesseras">Source</a></p> + </footer> +</body> +</html> |