mirror of
https://github.com/logos-blockchain/research.git
synced 2026-08-08 20:23:28 +00:00
Documentation sweep: make every finding reachable from the docs, not just the commits
Audited the report against this session's artifacts. All 37 figures are referenced and none is orphaned, sec 8.3 items 1-19 are contiguous, and no internal anchor is dead. Two knobs were measured but undocumented, and the simulator README had drifted behind the code: - sec 7 now documents f_precision alongside fixed_point, with the three measured arms (0.99997 exact / 1.01026 at the spec's 1e3 / 0.99990 at 1e6) rather than just the closed form, and says plainly that the default is the DESIGN choice while a spec-faithful arm needs both flipped. - sec 7 gains deep_orphan_share, with its three regimes: 0.25% honestly, 3.3% at 8 slots of per-recipient jitter, 19-41% under a private chain. It is the quantity p_ref conflates with "eligible but never picked up", which is the distinction that answered item 5. - The simulator README lists the four new scripts and the new configs, describes all three adversary strategies (the selfish one was undocumented there), adds the new fork-structure metrics, and carries a short "modelling the DEPLOYED chain rather than the mechanism" table -- the two defaults that are deliberately not spec-faithful, and when to flip them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a82e4cb706
commit
18c15d329c
@ -793,7 +793,7 @@ Every parameter a protocol designer or operator can set, in three groups: **prot
|
||||
| `w_u`, `w_n` — uncle / nephew rewards | compensation for referenced orphans / for referencing them | fairness: honest recovery 0.61 → 1.00 as `w_u` 0 → 1 (at `p_ref` = 1); hiding forfeits both rewards; safety invariant **`w_u + w_n < 1`** (else uncle farming pays); raising `w_n` alone marginally *helps* the attacker | [§6.7](#s6-7)/6.8, figs 14, 15 |
|
||||
| inclusion rule | whether references are incentivised or mandated | **soft** (reward-weighted) only — a hard validity mandate cannot be encoded fork-safely (censorship or consensus fork) | [§6.8](#s6-8) |
|
||||
| `genesis_d_factor`, `init_dest` | the initial `D̂` | a *common* wrong guess self-corrects in ~2 epochs (fig1); a *heterogeneous* init is preserved forever (fig21) — genesis `D̂` must be a shared constant | [§3.2](#s3-2), [Appendix C](#sC) |
|
||||
| `fixed_point` | on-chain integer-f truncation `f_p = ⌊f·1000⌋/1000` | the **only** residual bias after slot-counting: ≈ +1 % (`f/f_p`), removed by higher-precision `f` ([Appendix A](#sA)) | [§2.2](#s2-2), [§5](#s5) |
|
||||
| `fixed_point`, `f_precision` | whether the estimator quantises its target rate as the on-chain integer algorithm does, and at what scale (`f_p = ⌊f·f_precision⌋/f_precision`) | the **only** residual bias after slot-counting. Measured at the deployment's operating point: `D̂/D` = 0.99997 with exact `f`, **1.01026** at the spec's `f_precision` = 10³, 0.99990 at the recommended 10⁶. Default off, because a design question wants the mechanism isolated — but a *spec-faithful* arm must set `fixed_point: true, f_precision: 1000`, and that arm is the one that says what a deployed chain would read | [§2.2](#s2-2), [§5](#s5), [Appendix A](#sA) |
|
||||
|
||||
<a id="s7-2"></a>
|
||||
### 7.2 Network / environment parameters
|
||||
@ -814,6 +814,7 @@ Every parameter a protocol designer or operator can set, in three groups: **prot
|
||||
| knob | probes | result | where |
|
||||
|---|---|---|---|
|
||||
| `adversary_strategy: selfish` | private-chain (SM1) override in the per-node engine | the profitable lever, now measurable end-to-end: revenue tracks Eyal–Sirer at sub-slot latency (0.0356 vs 0.0356 at α = 0.1) and exceeds it as natural forking lifts `α_eff`; deflates `D̂` to 0.76 at α = 0.3 (δ = 8) with **no** cap able to recover it ([§6.8](#s6-8)) | [§6.6](#s6-6), [§6.8](#s6-8) |
|
||||
| `deep_orphan_share` (engine output) | share of in-window orphans sitting *below* the first block of their fork | the structural observable behind the first-fork cost, and the one `p_ref` conflates with "eligible but never picked up": these blocks are unreferenceable by construction ([§2.1](#s2-1)). 0.25 % honestly at the deployment's point, 3.3 % at 8 slots of per-recipient jitter ([§6.1](#s6-1)), 19–41 % under a private-chain attack ([§6.8](#s6-8)) | [§6.1](#s6-1), [§6.8](#s6-8) |
|
||||
| `p_ref_honest` (engine output) | reference rate over orphans produced *outside* the coalition | equals `p_ref` under suppression; diverges sharply under a private chain (0.45–0.69 vs ≈ 0.99), which is the quantity the estimator repair actually depends on | [§6.8](#s6-8) |
|
||||
| `adversary_frac` (β_adv), `adversary_strategy` | uncle suppression / abstention withholding | suppression weak at ρ < 1, a cheap lever only at ρ > 1 (1.43× at ρ = 1.36, β_adv = 0.5); withholding → `D̂ ≈ (1−β_adv)` — the *correct* active-stake answer, topology-independent | [§6.3](#s6-3)/6.4, figs 8, 9 |
|
||||
| `adversary_period`, `adversary_withhold_epochs` | dynamic withhold-rejoin schedules | unprofitable at every duty ψ > 0; griefing bounded (`deflation = β_adv·ψ`); no persistence | [§6.5](#s6-5), figs 10–12 |
|
||||
|
||||
@ -48,8 +48,18 @@
|
||||
the pre-redesign model unchanged — window = `uncle_window` slots, any-depth orphans
|
||||
referenceable, every baked reference counted — and **bit-reproduces historical runs** (the
|
||||
old model's RNG key is byte-identical to the pre-`uncle_model` key).
|
||||
- **Adversaries** (`adversary_strategy`, over a coalition holding `adversary_frac` of stake,
|
||||
selected at random or `adversary_selection: whale` for the largest holders at matched stake):
|
||||
- `suppress` — produces normally but references no uncles, starving the recovered density.
|
||||
- `withhold` — never gossips its blocks; abstention, a dead loss to the attacker.
|
||||
- `selfish` — mines a **private chain** and releases it under Eyal–Sirer SM1 rules, orphaning
|
||||
honest work. Only visibility is modelled: a coalition member's fork choice builds on the
|
||||
private tip whenever it leads, so the chain forms and is abandoned emergently. Forces the
|
||||
exact full scan, since a hidden block breaks the windowed horizon's premise.
|
||||
- **Metrics:** per-node `D_est` spread (`range`, `IQR`), canonical-chain **agreement**
|
||||
(window prefix vs current tip), mean accuracy, and — with `init_dest=heterogeneous` —
|
||||
(window prefix vs current tip), mean accuracy, fork structure (`fork_rate`, reorg depth,
|
||||
`p_ref` and `p_ref_honest`, and `deep_orphan_share` — the share of orphans below their fork's
|
||||
first block, i.e. unreferenceable by construction), and — with `init_dest=heterogeneous` —
|
||||
transient re-convergence.
|
||||
|
||||
## Headline result
|
||||
@ -157,6 +167,9 @@ src/tsi_sim/ constants config rng stake lottery topology blocktree(+build_tree
|
||||
configs/ smoke.yaml default.yaml fullscale.yaml
|
||||
countable-vs-old.yaml absorption-window.yaml (countable-model studies)
|
||||
fine-delay.yaml (delay 1-5 at 40 replicates: the design band, high precision)
|
||||
uncle-selection.yaml (the spec's oldest-first rule vs a deviating proposer)
|
||||
spec-point-{n5000,window,jitter}.yaml (the DEPLOYED operating point: delta_max=4
|
||||
from the spec's Blend profile — size, window and per-recipient-variance arms)
|
||||
tests/ test_{pernode,config,rng,lottery,blocktree,uncles,tsi_counting,stake,
|
||||
theory,latency,theory_convergence,countable_counting,
|
||||
countable_selfish,...}.py
|
||||
@ -164,4 +177,20 @@ scripts/ plot_countable_vs_old.py (countable-vs-unrestricted comparison f
|
||||
plot_fine_delay.py (design-band accuracy + model gap with 95% CIs)
|
||||
countable_selfish.py (first-fork ceiling under the selfish MDP; fig36)
|
||||
adversary_variants.py (whale/jitter/slow-beta variants + the withhold-load sweep)
|
||||
deflation_frontier.py (how far a PAID adversary can deflate D_est; fig37)
|
||||
selfish_uncle_margin.py (does the uncle cap need margin under a private chain?)
|
||||
spec_point.py (the deployed operating point; the three f-precision arms)
|
||||
spec_jitter.py (per-recipient delay variance — the transport diagnostic)
|
||||
```
|
||||
|
||||
### Modelling the *deployed* chain rather than the mechanism
|
||||
|
||||
Two defaults are deliberately **not** spec-faithful, because the report's job is to isolate
|
||||
mechanisms. Flip both for any run meant to answer "what would the deployed chain read":
|
||||
|
||||
| knob | default (design) | spec-faithful | why it matters |
|
||||
|---|---|---|---|
|
||||
| `fixed_point` / `f_precision` | `False` / `1e6` — exact `f` | `True` / `1000` | the spec quantises the target rate at `1e3`, which reads **+1.0 %** high; this is the largest error in the deployed estimator |
|
||||
| `uncle_model` | `countable` — the spec's rules | (same) | `--old` is an unreachable **ceiling**, not an alternative: the spec *rejects* a block carrying a reference that fails the counting rules |
|
||||
|
||||
`scripts/spec_point.py` runs both arms side by side.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user