Philosophy
Stoicism rewards operators who run their nodes in a way that benefits the network— not for uptime alone. Nodes earn when they run with the flags and configuration that strengthen StoaChain (accepting peers, valid p2p hostname, backup-api reachable, serving chainweb data). Configurations that only help the operator without helping the network don’t earn. That’s why it’s called Stoicism.
6.1 · Overview
- What it is. Off-chain reward unit keyed to an Ouronet account (
Ѻ.…— the standard Ouronet prefix, U+047A “barred O”, not Kadena-stylek:). Every point minted will become a real on-chain asset once ouronet-core lands (v0.8.x). - Who earns. Any node the hub manages whose owner has set an Ouronet account on their profile. Per-node overrides let an Ancient Admin direct a specific node’s earnings to a different account.
- What currently matters. We are in shadow mode: every tick + gate + mint runs, every number is visible, but the on-chain representation hasn’t landed yet. Shadow-mode balances zero-out on the flip to live. Pending survives warmup.
6.2 · Base rate
~86 points/day at reference hardware. A node at ServerScore = 5.0earns 5× that: ~430 points/day. Linear in ServerScore; no cap.
ServerScore is stamped by the benchmark job on first run + re-evaluated on commitment changes. It weights CPU, disk (read/write/latency), network (bandwidth + RTT), RAM, and a provisioning-commitment multiplier. See Mechanics / commitment curve below.
6.3 · The seven eligibility gates
Every 60 seconds the scoring worker checks each node against seven gates. Failing any gate pauses accrual silently; previously-banked points are never lost.
| # | Gate | Why it exists |
|---|---|---|
| 1 | Ouronet bound | Without an account to credit, there\’s no destination for the reward. |
| 2 | Benchmark present | ServerScore is the rate multiplier; without a benchmark the rate is undefined. |
| 3 | Cut within tip tolerance | Accrual only while the node is actually near the network\’s tip. Lagging nodes don\’t count. |
| 4 | Warmup cleared | 24 h of cumulative eligible time before the main tap opens. Filters transient setups + drive-by operators. |
| 5 | Provisioning ok | Committed storage ≥ actual use + 5 GB headroom. Stops rewarding nodes about to run out of disk. |
| 6 | Reachable on last tick | SSH hub\’s last contact within the tolerance window. An unreachable node isn\’t contributing. |
| 7 | Not in breach | Commitment violations, provision breaches, or flag violations (see §6.4) freeze accrual until the operator fixes. |
6.4 · Enforced flag list
The distinguishing mechanic: Stoicism enforces how the node is run, not just that it runs. The hub maintains a required-flag list; a node whose live argv (read via ps) is missing a required flag, or carries a disallowed one, fails gate #7 and stops accruing until the operator corrects the configuration.
Why flag enforcement matters
A node that rejects incoming peers, sets p2p-hostname to a non-resolvable value, or disables backup-api is still a running stoa node— but it’s not helping the rest of the network. Rewarding those configurations would make Stoicism a participation trophy. By making enforcement explicit + public, the philosophy (reward contribution, not presence) becomes durable and operator-facing.
The exact required-flag list lives in lib/stoachain-flags-catalog.ts (the full catalog) combined with the Ancient-Admin-configured policy in system_state.mandatory_flags. Two layers:
- Baseline — every catalog entry with
role: ‘mandatory’is always required (e.g.--chainweb-version,--database-directory,--p2p-port). These can’t be unticked; a node missing them can’t sync at all. - Admin policy — every other catalog entry is ticked on/off by the Ancient Admin on
/admin/stoicism/settings. Changes apply at the next scoring tick (~60 s); a node that fell out of compliance sees a pulsing red banner on its scoring card naming the missing flags.
The scoring worker logs a flag_violationevent on every tick a node remains non-compliant, so the operator’s earnings timeline shows exactly when accrual paused and why. Restart chainweb-node with the missing flag present and the very next tick resumes earning — no re-benchmark, no grace period, just immediate correction.
Known limitation (z20).Some mandatory flags require operator-supplied values that the hub can’t infer (e.g. --hostname, --p2p-hostname). For these, Gate 7 checks presence only — any value satisfies. A follow-up patch will surface per-node value collection so the policy can enforce specific values too (and so the auto-restart path knows what to inject).
6.5 · The three-bucket ledger
Pending
Probationary. Earned during warmup; swept into Current on warmup complete; discarded on warmup reset.
Current
Ready to mint. Grows every scoring tick; gets minted daily at 06:00 UTC into Redeemed (integer units).
Redeemed
On-chain amount (integer). Once ouronet-core ships + scoring flips live, this is the number visible in your Ouronet wallet.
Grand Total = Current + Redeemed. Pending is not counted until it completes warmup — a node that warmups-resets loses Pending but keeps what was already swept into Current.
6.6 · Commitment curve
Operators commit a storage amount on each node. The ServerScore provisioning multiplier scales with how much headroom they commit vs. the fleet-wide minimum (which moves as chainweb grows). Over-committing is cheap rewards; committing at exactly the minimum is correct + fair; under-committing fails gate #5.
Formula (simplified)
fleet_min_gb = ceil((fleet_data_gb + 5) / 10) × 10 provision_mult = clamp( ln(committed_gb / fleet_min_gb), lower = 0.0, // no bonus below floor upper = +log_growth // no cap but log scaling )
Logarithmic scaling means doubling commitment doesn’t double the reward — rewarding responsibility, not rent-seeking over-commitment. Fleet-wide minimum moves with actual chainweb data growth; operators near the floor are nudged to top up before they breach.
6.7 · Shadow mode → Light
The hub is currently in Shadow of the Stoic — scoring runs end-to-end, balances are visible, but the on-chain mint machinery hasn’t shipped yet. When ouronet-core (v0.8.x) lands, an Ancient Admin schedules a flip date or triggers the flip immediately:
- Pending survives the flip — warmup progress is preserved.
- Current + Redeemed balances zero-out on the flip. The live period starts counting from the flip timestamp.
- The flame at the top of /admin turns from purple (shadow) to gold (Light of the Stoic). Shadow countdown becomes a real-time tick-clock when a flip date is scheduled.
6.8 · Daily mint mechanics
At 06:00 UTC each day, the scoring worker runs runDailyIntegerMint:
- Every account with
floor(Current) ≥ 1is eligible. - Compute each account’s integer delta:
floor(current_points). - Reduce
current_pointsby that delta; incrementredeemed_pointsby the same. - Emit a
stoicism-mintevent onstoicism_eventsper account for audit.
Once live (v0.8.x), step 4 becomes: emit a single register-aggregation transaction per StoaChain chain carrying all per-account deltas. See the scaling plan §500k for why a 500k-account sweep fits comfortably within StoaChain’s gas ceiling.
6.9 · Precision contract (Pythagoras, v0.7.11)
Stoicism is a financial-layer record. The hub stores, computes, and audits every Stoicism balance using arbitrary-precision decimal arithmetic (decimal.js, TEXT-stored). f64 floats — the JavaScript default and the SQLite REAL type — are explicitly banned for any Stoicism balance because they silently lose precision when small accruals accumulate into large balances.
Marketing-grade claim: every Stoicism point earned is preserved exactly. Forever. Replay the events log on any other instance running the same code and migrations and you arrive at byte-identical balances. Read the v0.7.11 audit →
The numerical contract
server_score: 6 decimals (stays f64 — it’s a benchmark output, not a balance).tunneler_fee_promile: 1 decimal (= 2-decimal percent). Capped at the input layer (UIstep="0.1") and rejected by the server-side validator if finer.- Stoicism balances (
pending,current,redeemed,lifetime): 12 decimals exact. decimal.js arithmetic; SQLite TEXT storage as canonical 12-decimal strings. BASE_POINTS_PER_SEC: exact const =0.001.- Tick duration: exact const =
60s.
Smallest non-zero per-tick accrual the system can produce:
0.001 × 60 × 1e-6 (server_score) × 1e-4 (1-dec promile / 1000) = 6e-12
Fits in 12 decimals exactly, by design. Anything finer is unreachable through the input layer.
6.10 · Tunneler fee architecture
A Tunneler is a server with a public IPv4 + port-triplet allocator that hosts Tunnelees — CGNAT’d home boxes whose chainweb traffic relays through frps tunnels. One Tunneler can host many Tunnelees; each Tunnelee gets its own port triplet (ssh, p2p, service) from the Tunneler’s pool.
The Tunneler operator sets a fee in promile (1/1000) — their infrastructure-rent rate. Every tip-tick a Tunnelee earns, the fee fraction goes to the Tunneler:
tunnelee_share = N × (1 - promile / 1000) tunneler_share = N × (promile / 1000)
Routing rule:the Tunneler’s fee credit respects the Tunneler’sown warmup state, not the Tunnelee’s. A warmed-up Tunneler’s fee lands inaccount.current; a non-warmed Tunneler’s lands in account.pending.
Worked example:Spartacuz (Tunnelee, server_score 3.0) accrues 0.18 points/tick. StoaTunnelZero (Tunneler, fee 10 promile = 1%) gets 0.0018 of that, every tick. With the v0.7.11 precision contract, this 0.0018 lands in StoaTunnelZero’s account.pending exactly — no f64 truncation.
6.11 · Multi-container servers (segregated mode)
A standalone server can host either ONE full-machine chainweb container OR multiple segregated chainweb containers (port-isolated, independent of each other). Mutual exclusion is enforced both directions: the install wizard refuses full-machine if segregated children exist; the self-container creator refuses segregation when full-machine is installed.
Minimum requirements per segregated container (operator-locked):
- 3 vCPU dedicated
- 6 GB RAM
- SSD-backed storage (HDD rejected at the install wizard — chainweb random-read IOPS exceeds rotational disk capability by 2-3 orders of magnitude)
- Allocated commit space (per the existing
committed_gbrule)
Each segregated container gets its own ServerScore (its own benchmark + commitment) and accrues Stoicism independently. Multiple containers on one box mean multiple scoring rows in the operator’s ledger; the same f64-banned exact-decimal rules apply to each.
6.11a · Warmup mechanics & identity rules
Warmup gates a chainweb’s "earnings count toward the realized bucket" status. The bar: 24 hours of cumulative eligible time at tip. Gate 4 of the seven eligibility checks (§6.3). Until cleared, accruals route to the Pending bucket; on completion they sweep into Current and stay there.
Counters tracked per chainweb container
scoring_warmup_since— first observation at tip. Set once per chainweb identity. Acts as the "earning since X" anchor.warmup_cumulative_seconds— total time at tip. Advances by 60s every successful scoring tick where the chainweb is at tip. Never decremented.warmup_last_tick_at— most recent successful tick. Used by the offline-detection display gate (§6.3, gate 6).scoring_warmup_completed_at— stamped once when cumulative crosses the 24 h threshold. Permanent.
What does NOT reset warmup
- Brief drops(chainweb temporarily off-tip, single-tick miss). Cumulative pauses but doesn’t lose ground.
- Benchmarks (auto-stop + restart, ~3-5 min). The chainweb is hub-paused; warmup state is preserved.
- Prime ↔ Slave conversions(~30 s rebind downtime). The chainweb’s identity moves with the chainweb across the conversion; warmup, lifetime, mining and Ouronet account all carry over to the new row.
- Operator-driven container restarts (Stop + Start from the Control tab). Same data dir, same chainweb identity, same warmup state.
What DOES start a fresh warmup
- Adding a new slave to a segregated host (Add SLAVE 002, etc.). The new chainweb is a genuinely new identity with a fresh data dir, separate sync from peers, and its own benchmark. Starts at warmup zero. Existing slaves are unaffected.
- A wholesale reinstall— operator deletes the chainweb data dir + reseeds. The chainweb’s peer- identity and on-chain history reset; treated as a new commitment.
- Long unplanned downtime(planned for v0.7.13a) — when chainweb is unreachable for > 1 hour outside any hub-induced operation, warmup_cumulative_seconds resets to zero. Hub actions (rebind, bench, conversion) stamp a planned- downtime window so they don’t count against the operator.
Identity rule (the core invariant)
Warmup is a property of the chainweb identity, not the database row or the docker container. As long as the chainweb’s data dir, P2P key, mining pubkey, and Ouronet account remain the same, the warmup counter persists across any operational change to the wrapping container.
Concretely: a Prime → Slave → Prime → Slave round trip is identity-preserving. Each conversion moves the four warmup fields (plus lifetime + pending Stoicism, plus mining / Ouronet) from the source row to the destination row. The wrapper changes; the chainweb is the same.
6.12 · Operator FAQ
- My node is online but not earning. Why?
- Open the node\’s Scoring card in /admin/nodes/[id]. Each of the 7 gates is listed with its current state; the failing one tells you exactly what to fix.
- I re-benchmarked. Will my warmup reset?
- No. Benchmarks change the rate, not the warmup clock. The only things that reset warmup are: staying off-tip for > tolerance, or an explicit warmup-reset from an Ancient Admin (emergency tool).
- If I unmanage a node, do I lose my Stoicism?
- No. Stoicism is keyed to your Ouronet account, not the node. Adding and removing nodes doesn\’t affect any Stoicism already earned. The node\’s own lifetime_points counter stops at the value it had when unmanaged.
- When does the mint go on chain?
- Once v0.8.x (ouronet-core) ships. Until then the mint runs daily in shadow mode — the Redeemed counter grows, but no on-chain tx is emitted yet. When scoring flips live, Redeemed zeros out; new on-chain mints start from that moment.
- Why does committing more storage help?
- Nodes with comfortable commitment headroom are less likely to hit the provisioning gate during chainweb growth, which means steadier accrual. The multiplier is logarithmic — diminishing returns past ~2× the fleet minimum — to avoid rent-seeking.