Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Reseller Bootstrap: Zero-Float Mesh Formation (Implementation Plan)

Aperta
#239 3 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
25/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Tranquilla
Stack tecnologico
go, playwright, react

Direzione di ricerca

This is a multi-phase plan; start with Phase 1 in config_manager_config.go, config_schema.go, upstream_manager.go, vendor_element_manager.go, main.go, and upstream_session_manager/types.go. Read PR #235 first, since the vendor IE work depends on its TLV format, then add unit coverage for hop-count derivation and check the balance JSON and vendor IE tests. Done means hop_count is propagated as specified; the later phases require separate backend and captive-portal work.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

enhancement

Reseller Bootstrap: Zero-Float Mesh Formation

Problem

A freshly configured TollGate in reseller mode has no internet, no upstream
session, and no ecash balance. When a customer pays, the reseller cannot
grant internet access because it has none to grant. The network cannot
bootstrap without pre-funding or trust.

Solution

The first customer's first proof is forwarded in full to the upstream
TollGate. No split, no swap, no margin on the first transaction. The
upstream authorizes the reseller's STA MAC, granting a data session. The
reseller now has internet. Every subsequent payment earns margin normally.

This works recursively — a reseller-of-a-reseller bootstraps the same way.
Each hop adds latency only on the first transaction (5-15s for payment
forwarding). After that, the reseller can reach the mint directly for
proof swaps.

No walled gardens. No whitelists. No pre-funding. No trust. The first
proof is the spark that lights the network.

Bootstrap Flow

First customer transaction (cold start)
  1. Customer connects to reseller WiFi, sees captive portal, pays 2 sats
  2. Reseller detects: no active upstream session → bootstrap mode
  3. Reseller forwards the ENTIRE proof to upstream via Nostr payment
  4. Upstream receives proof, validates at mint, authorizes reseller STA MAC
  5. Reseller's upstream session begins (2 MB at 1 sat/MB upstream rate)
  6. Reseller opens valve for customer: 1 MB (what 2 sats buys at reseller rate)
  7. Reseller retains 1 MB of prepaid upstream bandwidth as float

Customer UX during cold start (5-15s):

  • "Payment received"
  • "Establishing internet link..."
  • "Link established — N hops to gateway"
  • "Access granted!"
Second transaction (warm path)
  1. Customer pays 2 sats (renewal or new customer)
  2. Reseller HAS internet — reaches mint directly
  3. Reseller swaps proof at mint, splits: 1 sat upstream + 1 sat profit
  4. Sends 1 sat to upstream for 1 MB more
  5. Customer gets 1 MB

Every subsequent transaction: normal margin. The "cost" of cold start
was zero — the reseller didn't lose money, it just didn't earn margin
on transaction #1, and gained 1 MB of prepaid float.

Recursive multi-hop

A chain of TollGates A → B → C:

  1. Customer pays C (hop 2 reseller)
  2. C has no internet → forwards proof to B
  3. B has no internet → forwards proof to A
  4. A is the gateway → has internet, validates proof, authorizes B's MAC
  5. B now has internet → authorizes C's MAC
  6. C now has internet → opens valve for customer

Each hop adds one payment round-trip (~5-8s). A 3-hop chain cold-starts
in ~20s on the first transaction only.

Hop Count Propagation

Each TollGate advertises its hop distance from the internet gateway:

  • Direct gateway (has its own internet): hop_count = 0
  • Reseller of a gateway: hop_count = upstream.hop_count + 1

Propagated via:

  1. Vendor IE (802.11, for router-to-router discovery)
  2. NostR details event (kind 21023, for client-facing portal)
  3. Balance JSON (/balance endpoint, for status display)

Customer sees on balance page:

Connection active
2 hops to internet
0.8 MB remaining

Implementation Phases

Phase 1: Hop Count Propagation (backend)

Scope: Add hop_count field end-to-end through the backend.

  • Add hop_count int field to UpstreamManagerConfig and config schema
  • Add hop_count byte to vendor IE encoding (#235's TLV format, new type 0x03)
  • Add hop_count tag to NostR details event (kind 21023)
  • Add hop_count to balanceResponse JSON struct in main.go
  • UpstreamManager: when connecting to upstream, read its hop_count from
    vendor IE or probe response, set local = upstream + 1
  • Direct gateway: hop_count = 0 when reseller_mode = false
  • Config default: hop_count = 0 (updated at runtime by UpstreamManager)

Files touched: config_manager_config.go, config_schema.go,
upstream_manager.go, vendor_element_manager.go, main.go,
upstream_session_manager/types.go

Dependencies: PR #235 (vendor IE) must merge first (for the TLV encoding)

Testing: Unit test hop_count derivation logic. Router test: verify
hop_count appears in balance JSON and vendor IE on real hardware.

Estimate: 2-3 tasks

Phase 2: Bootstrap Passthrough Logic (backend)

Scope: First-proof-forward bootstrap in the merchant payment flow.

  • Add bootstrap_mode state to merchant/upstream session manager
  • Detect cold start: no active upstream session + reseller_mode = true
  • In bootstrap mode: forward entire received proof to upstream via Nostr
  • After upstream session established: set bootstrap_mode = false
  • Subsequent payments: normal proof swap + split flow
  • Add /bootstrap-status endpoint (or extend /balance):
    • bootstrap_phase: idle | forwarding | establishing | complete | error
    • hop_count: derived from upstream

Files touched: merchant/merchant.go, upstream_session_manager/session.go,
main.go (new endpoint or extended balance response)

Dependencies: Phase 1 (hop_count field exists in response structs)

Testing: Unit test bootstrap state machine. Integration test: mock
upstream, verify first proof forwarded whole, second proof split.

Estimate: 3-4 tasks

Phase 3: Bootstrap Status UI (frontend)

Scope: Customer-facing UI for bootstrap progress + hop count display.

  • New processing states in captive portal during bootstrap:
    • "Payment received"
    • "Establishing internet link..." (with hop count if >1)
    • "Link established — N hops to gateway"
    • "Access granted!"
  • Poll /balance (or /bootstrap-status) during bootstrap for phase updates
  • Balance page: add hop count display alongside remaining/usage
  • i18n strings for all new status messages

Files touched: captive portal React app (separate repo:
OpenTollGate/tollgate-captive-portal-site), locale files

Dependencies: Phase 2 (backend serves bootstrap phase data)

Testing: Playwright/visual test of bootstrap UI states

Estimate: 2 tasks

Phase 4: Pre-connect, Post-pay (optimization)

Scope: Eliminate cold-start latency for subsequent network formations.

  • Upstream TollGate: add reseller_grace_seconds config (default: 0 = off)
  • When grace > 0: upstream allows identified reseller STAs to connect and
    get a local IP without payment, for N seconds
  • Reseller: pre-connects to upstream WiFi immediately on boot
  • When first customer pays: upstream session already established,
    payment flows instantly
  • Grace window expires → upstream disconnects unpaid STA
  • Reseller can reconnect (grace restarts) but must pay to stay

Files touched: upstream_session_manager/, config_manager/,
nodogsplash configuration in packaging/

Dependencies: Phases 1-3 (bootstrap flow works end-to-end first)

Testing: Two-router test: cold start with grace enabled, verify
first customer experiences <2s latency instead of 5-15s

Estimate: 3-4 tasks

Key Design Decisions

  1. No walled gardens. The upstream does not whitelist mint URLs.
    The first proof goes directly to the upstream TollGate via Nostr,
    which has internet and can validate it.

  2. No proof splitting on cold start. The entire first proof is
    forwarded. Splitting requires a mint swap, which requires internet,
    which requires paying the upstream — circular dependency. Forwarding
    the whole proof breaks the cycle.

  3. Hop count is informational, not control. Display only. No
    automatic chain-depth limiting in v1. Operators can configure
    max_reseller_hops later if abuse becomes a concern.

  4. Vendor IE carries hop count. This lets scanning resellers see
    the hop depth before connecting, enabling price calculation
    (markup compounds per hop).

  5. Phase 4 is the goal, Phases 1-3 are stepping stones. The
    pre-connect grace window is the optimal UX, but the passthrough
    bootstrap must work first as the fallback when grace is not
    available or expires.

Open Questions

  • Should the reseller calculate its price dynamically from upstream
    price + configured markup, or keep static pricing? (Dynamic is
    correct but adds complexity.)
  • Should hop count be capped? (e.g., refuse to resell beyond hop 5)
  • What happens if the upstream rejects the forwarded proof (wrong mint)?
    Error message to customer: "This mint is not accepted by the upstream
    gateway. Try a different token."

Related PRs

  • #235 (vendor IE) — provides the TLV encoding framework
  • #232 / #231 (identity) — reseller identity is derived from merchant key
Lingua principale
Go
Stelle
12
Fork
14
Merge medio
1g 6h
PR unite (30g)
217

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di OpenTollGate/tollgate-module-basic-go

Tutte le issue di OpenTollGate/tollgate-module-basic-go

Issue simili

Altre issue su Go

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.