Reseller Bootstrap: Zero-Float Mesh Formation (Implementation Plan)
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
- Ambito
- backend, frontend, networking
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
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)
- Customer connects to reseller WiFi, sees captive portal, pays 2 sats
- Reseller detects: no active upstream session → bootstrap mode
- Reseller forwards the ENTIRE proof to upstream via Nostr payment
- Upstream receives proof, validates at mint, authorizes reseller STA MAC
- Reseller's upstream session begins (2 MB at 1 sat/MB upstream rate)
- Reseller opens valve for customer: 1 MB (what 2 sats buys at reseller rate)
- 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)
- Customer pays 2 sats (renewal or new customer)
- Reseller HAS internet — reaches mint directly
- Reseller swaps proof at mint, splits: 1 sat upstream + 1 sat profit
- Sends 1 sat to upstream for 1 MB more
- 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:
- Customer pays C (hop 2 reseller)
- C has no internet → forwards proof to B
- B has no internet → forwards proof to A
- A is the gateway → has internet, validates proof, authorizes B's MAC
- B now has internet → authorizes C's MAC
- 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:
- Vendor IE (802.11, for router-to-router discovery)
- NostR details event (kind 21023, for client-facing portal)
- Balance JSON (
/balanceendpoint, 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_countint field toUpstreamManagerConfigand config schema - Add
hop_countbyte to vendor IE encoding (#235's TLV format, new type0x03) - Add
hop_counttag to NostR details event (kind 21023) - Add
hop_counttobalanceResponseJSON 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_modestate 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-statusendpoint (or extend/balance):bootstrap_phase: idle | forwarding | establishing | complete | errorhop_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_secondsconfig (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
-
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. -
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. -
Hop count is informational, not control. Display only. No
automatic chain-depth limiting in v1. Operators can configure
max_reseller_hopslater if abuse becomes a concern. -
Vendor IE carries hop count. This lets scanning resellers see
the hop depth before connecting, enabling price calculation
(markup compounds per hop). -
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
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di OpenTollGate/tollgate-module-basic-go
-
go-battery needs an ndsctl on PATH: TestPurchaseSessionGuardHoldsThroughTheOutcomeUnknownWindow fails on bare hosts (passes with stub)Forse già presa @Amperstrand l’ha presa 1 giorno fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
OpenTollGate/tollgate-module-basic-go#726 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
rebrand-literal-gutter: uhttpd section-vocabulary check trips on a COMMENT (uhttpd.luci in 92-tollgate-admin-setup:178)Forse già presa @Amperstrand l’ha presa 1 giorno fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
OpenTollGate/tollgate-module-basic-go#723 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 20/100
OpenTollGate/tollgate-module-basic-go#768 ·
I maintainer di solito rispondono entro 1 giorno
-
Four drift fences for tests/contract/ (+ test.yml clean-container lane + pre-commit wiring)Forse già presa Una pull request collegata a questa issue è aperta o già unita. Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
OpenTollGate/tollgate-module-basic-go#767 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 20/100
OpenTollGate/tollgate-module-basic-go#763 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di OpenTollGate/tollgate-module-basic-go
Issue simili
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
enhancement pkg:sdk
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
aws/aws-durable-execution-sdk-go#144 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
cloudflare/cloudflared#1761 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno