diff --git a/PLAN-NAME-REGISTRATION.md b/PLAN-NAME-REGISTRATION.md new file mode 100644 index 00000000..48c72981 --- /dev/null +++ b/PLAN-NAME-REGISTRATION.md @@ -0,0 +1,147 @@ +# Mainnet Name Registration Plan + +> **Status:** Validating on testnet +> **Date:** 2026-04-03 +> **Authors:** Snider, Charon + +## Problem + +The Lethean chain merges two blockchains — a main chain (aliases) and an HNS sidechain (DNS). The sidechain blocks Alexa top 100K domains and ICANN TLDs from being registered by random users. But the main chain has no such protection — anyone could register `@google` as an alias before the sidechain has a chance to refuse it. + +This creates a window for name squatting that corrupts the namespace before real users arrive. + +## Numbers + +| Category | Count | +|----------|-------| +| Reserved (Alexa top 100K) | 90,016 | +| Locked (ICANN TLDs) | 11,554 | +| **Total unique names** | **90,041** | +| Long names (>=6 chars, public) | 73,977 | +| Short names (<6 chars, need authority key) | 16,062 | + +**Source:** `blockchain-network-dcore/lib/covenants/names.json` and `lockup.json` + +## Strategy + +### Phase 1: Genesis + HF Warmup + +1. Mainnet launches with HF0 — 10M LTHN premine in SWAP wallet +2. During HF warmup (HF0 → HF1), send **1,000+ LTHN** from genesis to dedicated namereg wallets +3. Multiple namereg wallets (2-4) for parallel registration +4. Destination for all reserved aliases: a **multi-sig wallet** controlled by the team + +### Phase 2: Staking Funds the Protection + +1. Network wallet stakes during warmup — earns ~720 LTHN/day from PoS +2. Legacy users haven't reclaimed tokens yet (SWAP happens later) +3. Staking rewards from the network's own balance fund all registrations +4. The network literally pays for its own name protection + +### Phase 3: Batch Registration + +When aliases activate (HF that enables alias registration): + +1. Namereg wallets already have coins and mature UTXOs ready +2. Multiple wallets work in parallel, each tackling a chunk of the 90K list +3. Priority order: + - **Tier 1:** Top brands (google, facebook, amazon, etc) — ~120 names + - **Tier 2:** Long names from Alexa list (>=6 chars) — ~73,977 names + - **Tier 3:** Short names with authority key (<6 chars) — ~16,062 names +4. Rate: ~1 alias per 3 seconds per wallet = ~28,800/day with 1 wallet, ~115,200/day with 4 + +### Phase 4: Ongoing Governance + +1. All reserved names sit in a multi-sig wallet +2. Legitimate brand owners can request transfer (proof of domain ownership) +3. Community aliases (common words like "wallet", "exchange") remain locked +4. Infrastructure names (@vpn, @proxy, @exit, etc) transferred to service operators + +## Cost Model + +| Item | Cost | +|------|------| +| Alias registration fee | 1 LTHN each | +| Transaction fee | 0.01 LTHN each | +| **Total for 90K names** | **~90,900 LTHN** | +| PoS earnings (720/day) | Covered in ~126 days | +| With 1000 LTHN seed | First ~1000 names immediate | + +The network earns back the registration cost through staking before legacy users even begin the SWAP process. + +## Technical Requirements + +### Testnet Validation (current) + +- [x] PoS staking working (first PoS block at height 12,382) +- [x] Alias registration via wallet RPC confirmed +- [x] Batch registration script built and tested +- [x] Priority name list generated from HNS data (90,041 names) +- [ ] Multi-wallet parallel registration tested +- [ ] Authority key for short names (<6 chars) tested +- [ ] Full 90K registration completed on testnet +- [ ] Explorer confirms all names visible +- [ ] LNS resolves registered names + +### Mainnet Requirements + +- [ ] Multi-sig wallet created for reserved names +- [ ] Genesis transaction plan (SWAP wallet → namereg wallets) +- [ ] Authority key provisioned for short-name registration +- [ ] Ansible playbook for deploying namereg wallets on prod +- [ ] Monitoring: alias count dashboard, registration rate, failures + +## Alias Comment Format + +All reserved names use this comment format for identification: + +``` +v=lthn1;type=reserved;reason=hns-protected +``` + +This allows: +- LNS to identify reserved vs user-registered names +- Future tools to query reserved names +- Governance decisions (release to brand owners) to be automated + +## Daemon Configuration + +PoS staking requires `--rpc-ignore-offline` when the daemon has no peers: + +``` +lethean-chain-node --rpc-ignore-offline --do-pos-mining +``` + +Without this flag, the daemon refuses PoS mining requests when disconnected. + +## Batch Registration Tool + +```bash +# Generate priority list from HNS data +python3 tools/generate-name-list.py + +# Register names (3s delay, checks balance every 10) +bash tools/register-reserved.sh /tmp/protected-names-long.txt http://127.0.0.1:46944/json_rpc 10 3 +``` + +Tool location: `docker/tools/register-reserved.sh` + +## Risk Mitigations + +| Risk | Mitigation | +|------|-----------| +| Tx pool congestion | Multiple wallets, 3s delay, batch checkpoints | +| Insufficient funds | Staking covers ongoing costs, seed from genesis | +| Authority key compromise | Multi-sig for the key, not single holder | +| Name disputes post-launch | Governance process for brand transfers | +| Testnet/mainnet drift | Same tooling, same scripts, validated on testnet first | + +## Timeline + +| Phase | When | Duration | +|-------|------|----------| +| Testnet validation | Now (Apr 2026) | 1-2 weeks | +| Mainnet genesis | TBD (Darbs approval) | Day 0 | +| HF warmup | Day 0-7 | 1 week | +| Batch registration | Day 7+ | 1-4 days (with parallel wallets) | +| Full coverage | Day 14 | All 90K protected | diff --git a/docker/tools/register-reserved.sh b/docker/tools/register-reserved.sh new file mode 100755 index 00000000..9db394f7 --- /dev/null +++ b/docker/tools/register-reserved.sh @@ -0,0 +1,130 @@ +#!/bin/bash +# Lethean Reserved Name Registrar +# Batch-registers protected aliases on the main chain to prevent squatting. +# +# Usage: +# bash register-reserved.sh [names-file] [wallet-rpc] [batch-size] [delay] +# +# Defaults: +# names-file: /tmp/protected-names-priority.txt +# wallet-rpc: http://127.0.0.1:46944/json_rpc +# batch-size: 10 (aliases per batch before checking balance) +# delay: 2 (seconds between registrations) + +NAMES_FILE="${1:-/tmp/protected-names-priority.txt}" +WALLET_RPC="${2:-http://127.0.0.1:46944/json_rpc}" +BATCH_SIZE="${3:-10}" +DELAY="${4:-2}" +COMMENT="v=lthn1;type=reserved;reason=hns-protected" +LOG_FILE="/tmp/register-reserved.log" +DONE_FILE="/tmp/registered-names.txt" + +touch "$DONE_FILE" + +get_balance() { + curl -sf "$WALLET_RPC" -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' \ + -H 'Content-Type: application/json' | python3 -c " +import sys,json +d=json.load(sys.stdin)['result'] +print(d['unlocked_balance']) +" 2>/dev/null +} + +get_address() { + curl -sf "$WALLET_RPC" -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' \ + -H 'Content-Type: application/json' | python3 -c " +import sys,json +print(json.load(sys.stdin)['result']['address']) +" 2>/dev/null +} + +register_alias() { + local name="$1" + local address="$2" + + result=$(curl -sf "$WALLET_RPC" -d "{ + \"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"register_alias\", + \"params\":{ + \"alias\":\"$name\", + \"address\":\"$address\", + \"comment\":\"$COMMENT\" + } + }" -H 'Content-Type: application/json' 2>/dev/null) + + if echo "$result" | grep -q '"result"'; then + tx=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin)['result'].get('tx_hash','ok'))" 2>/dev/null) + echo "$name" >> "$DONE_FILE" + echo "$(date +%H:%M:%S) OK @$name ($tx)" | tee -a "$LOG_FILE" + return 0 + else + error=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('error',{}).get('message','unknown')[:80])" 2>/dev/null) + echo "$(date +%H:%M:%S) ERR @$name — $error" | tee -a "$LOG_FILE" + return 1 + fi +} + +# Get wallet address +ADDRESS=$(get_address) +if [ -z "$ADDRESS" ]; then + echo "ERROR: Can't connect to wallet at $WALLET_RPC" + exit 1 +fi +echo "Wallet: $ADDRESS" +echo "Names file: $NAMES_FILE ($(wc -l < "$NAMES_FILE") names)" +echo "Already registered: $(wc -l < "$DONE_FILE") names" +echo "Comment: $COMMENT" +echo "Batch: $BATCH_SIZE, Delay: ${DELAY}s" +echo "Log: $LOG_FILE" +echo "---" + +BALANCE=$(get_balance) +BALANCE_LTHN=$(echo "scale=2; $BALANCE / 1000000000000" | bc 2>/dev/null) +echo "Balance: $BALANCE_LTHN LTHN" +echo "" + +COUNT=0 +REGISTERED=0 +FAILED=0 +SKIPPED=0 + +while IFS= read -r name; do + # Skip empty lines and comments + [[ -z "$name" || "$name" == \#* ]] && continue + + # Skip already registered + if grep -qxF "$name" "$DONE_FILE" 2>/dev/null; then + ((SKIPPED++)) + continue + fi + + # Check balance every batch + if (( COUNT % BATCH_SIZE == 0 && COUNT > 0 )); then + BALANCE=$(get_balance) + BALANCE_LTHN=$(echo "scale=2; $BALANCE / 1000000000000" | bc 2>/dev/null) + echo "--- Batch checkpoint: $BALANCE_LTHN LTHN, $REGISTERED registered, $FAILED failed ---" + + # Stop if balance too low (need 1 LTHN + fee) + if (( BALANCE < 1100000000000 )); then + echo "Balance too low ($BALANCE_LTHN LTHN). Stopping." + break + fi + fi + + register_alias "$name" "$ADDRESS" + if [ $? -eq 0 ]; then + ((REGISTERED++)) + else + ((FAILED++)) + fi + + ((COUNT++)) + sleep "$DELAY" + +done < "$NAMES_FILE" + +echo "" +echo "=== Done ===" +echo "Registered: $REGISTERED" +echo "Failed: $FAILED" +echo "Skipped: $SKIPPED" +echo "Total processed: $COUNT"