mirror of
https://github.com/logos-blockchain/research.git
synced 2026-08-08 20:23:28 +00:00
Keep the deployed rule as the default; make the proposal an explicit arm
I had planned to flip uncle_window_anchor's default to "parent" so new configs would measure the proposed design by default. Tried it, and it breaks a documented guarantee: key() appends the anchor only when it is not "uncle", so with "parent" as the default an --old run's key is no longer byte-identical to the pre-redesign key and --old stops bit-reproducing historical runs (sec 9). o.key() == o._base_key() fails outright. Reverted, and on reflection the default was wrong for a second reason anyway. The report's job is to describe the protocol as deployed and to RECOMMEND changes; the default should therefore be the deployed rule, with the proposal as an explicit arm. That is exactly the convention fixed_point already follows (default exact f = the analysis convention, explicit True = spec-faithful). Both reasons are recorded on the field. To make the distinction visible rather than implicit, the spec-as-is studies now pin uncle_window_anchor: uncle explicitly -- spec_point.py, spec_jitter.py and the three spec-point-*.yaml configs answer "what does the DEPLOYED chain do", so they must not drift onto a proposal if a default ever moves. Adds uncle_window_anchor as a sweep axis (SweepConfig field plus _SWEEP_AXES), and configs/absorption-window-anchor.yaml: the sec 3.4 absorption sweep re-run under both anchors at three delays. That study is the one that can move a recommendation -- the W >= 7/f floor was measured against the uncle gap, and the parent gap runs about one block-interval longer, so the floor should sit higher and the margin behind W = 10/f shrink. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
f1433cbbb3
commit
525d081a3c
@ -0,0 +1,37 @@
|
||||
# Does anchoring the reference window to the uncle's PARENT move the window floor? (§3.4, §6.12)
|
||||
#
|
||||
# The `W >= 7/f` recovery floor was measured against the UNCLE's slot. Under the §6.12 proposal
|
||||
# the window is measured to the uncle's PARENT, and the parent gap runs about one block-interval
|
||||
# longer (measured: median 54 slots against ~30), so the same numeric W is an effectively tighter
|
||||
# window. The floor should therefore sit roughly one block-interval higher — which matters,
|
||||
# because W = 10/f is a recommendation whose justification is its margin over that floor. If the
|
||||
# floor moves 7 -> 8, the margin falls from ~1.43x to ~1.25x and the recommendation needs
|
||||
# restating even though the value does not change.
|
||||
#
|
||||
# This is the direct re-measurement: the same absorption sweep, both anchors, side by side.
|
||||
# U = 1 isolates the window — with more uncle slots the queue drains faster and the window stops
|
||||
# being the binding constraint, which would hide the knee.
|
||||
#
|
||||
# Note the two anchors draw independent RNG streams (uncle_window_anchor is in the key when it is
|
||||
# not the default), so this is an UNPAIRED comparison and the knee position, not a per-cell
|
||||
# difference, is what it resolves. Latency is in SLOTS (1 slot = 1 s).
|
||||
n_nodes: [1000] # network size
|
||||
stake_dist: [pareto] # heavy-tailed (realistic) stake distribution
|
||||
topology: [blend] # Blend mixnet (delay stresses the window)
|
||||
degree: [6] # peering degree of the d-regular graph
|
||||
link_latency_mean: [0.5] # natural geographic transport (sub-slot)
|
||||
link_latency_dist: [geo] # real-world geographic band mixture
|
||||
blend_hops: [3] # fixed hop count; delay is the swept knob
|
||||
blend_delay_max: [4.0, 8.0, 16.0] # deployed point, design point, the load boundary
|
||||
window_absorption: [3, 5, 6, 7, 8, 9, 10, 12, 15, 20] # W in block-intervals; w_u = W/f slots
|
||||
uncle_window_anchor: [uncle, parent] # THE comparison: spec rule vs the §6.12 proposal
|
||||
max_uncles: [1] # FIXED at one uncle: the question is about W
|
||||
uncle_strategy: [oldest] # spec Uncle Selection
|
||||
init_dest: [common] # per-node initial D_est from agreement
|
||||
replicates: 12 # enough to place a knee to ~1 block-interval
|
||||
base: # per-run settings shared by every cell
|
||||
k: 2160 # true security parameter
|
||||
epochs: 20 # equilibrium within ~2 epochs; burn 50%
|
||||
f: 0.03333333333333333 # slot activation coefficient (1/30)
|
||||
genesis_d_factor: 0.5 # start near true stake (cheap epoch 0)
|
||||
early_stop: true
|
||||
@ -34,6 +34,7 @@ blend_hops: [3] # the spec's Blend cascade length
|
||||
blend_delay_max: [4.0] # the spec's operating point (rho ~ 0.27)
|
||||
max_uncles: [0, 1, 2, 4] # 0 = negative control; 4 = the spec's MAX_UNCLES
|
||||
uncle_strategy: [oldest] # spec Uncle Selection
|
||||
uncle_window_anchor: [uncle] # SPEC AS DEPLOYED, not the sec 6.12 proposal
|
||||
init_dest: [common] # per-node initial D_est from agreement
|
||||
replicates: 12 # exact-oracle runs are ~17 s each; 12 x 40 cells
|
||||
base: # per-run settings shared by every cell
|
||||
|
||||
@ -25,6 +25,7 @@ blend_hops: [3] # the spec's Blend cascade length
|
||||
blend_delay_max: [4.0] # the spec's 2 s dwell, matched in the mean
|
||||
max_uncles: [0, 1, 2, 4] # 0 = the C3 column; 4 = the spec's MAX_UNCLES
|
||||
uncle_strategy: [oldest] # spec Uncle Selection
|
||||
uncle_window_anchor: [uncle] # SPEC AS DEPLOYED, not the sec 6.12 proposal
|
||||
init_dest: [common] # per-node initial D_est from agreement
|
||||
replicates: 12 # N = 5000 at true k is heavy; 12 gives ~±0.2 pp
|
||||
base: # per-run settings shared by every cell
|
||||
|
||||
@ -24,6 +24,7 @@ blend_delay_max: [4.0] # the spec's operating point
|
||||
window_absorption: [1, 2, 3, 5, 7, 10, 15, 20] # W in expected block-intervals; w_u = W/f slots
|
||||
max_uncles: [1] # FIXED at one uncle: the question is about W
|
||||
uncle_strategy: [oldest] # spec Uncle Selection
|
||||
uncle_window_anchor: [uncle] # SPEC AS DEPLOYED, not the sec 6.12 proposal
|
||||
init_dest: [common] # per-node initial D_est from agreement
|
||||
replicates: 12 # enough to place the knee, not to resolve 0.1 pp
|
||||
base: # per-run settings shared by every cell
|
||||
|
||||
@ -51,7 +51,8 @@ SPEC_POINT = dict(n_nodes=1000, stake_dist="pareto", topology="blend", degree=6,
|
||||
link_latency_mean=0.5, link_latency_dist="geo", blend_hops=3,
|
||||
blend_delay_max=4.0, uncle_strategy="oldest", window_absorption=10.0,
|
||||
k=2160, epochs=20, genesis_d_factor=0.5, early_stop=True,
|
||||
windowed_fork_choice=False, prune_arrival=False)
|
||||
windowed_fork_choice=False, prune_arrival=False,
|
||||
uncle_window_anchor="uncle") # SPEC AS DEPLOYED, not the §6.12 proposal
|
||||
|
||||
|
||||
def _cell(model: str, jitter: float, u: int, rep: int) -> dict:
|
||||
|
||||
@ -48,7 +48,8 @@ SPEC_POINT = dict(n_nodes=1000, stake_dist="pareto", topology="blend", degree=6,
|
||||
link_latency_mean=0.5, link_latency_dist="geo", blend_hops=3,
|
||||
blend_delay_max=4.0, max_uncles=4, uncle_strategy="oldest",
|
||||
window_absorption=10.0, k=2160, epochs=EPOCHS,
|
||||
genesis_d_factor=0.5, early_stop=True)
|
||||
genesis_d_factor=0.5, early_stop=True,
|
||||
uncle_window_anchor="uncle") # SPEC AS DEPLOYED, not the §6.12 proposal
|
||||
|
||||
ARMS = [("exact f (report convention)", False, 1_000_000),
|
||||
("spec today (PRECISION = 1e3)", True, 1_000),
|
||||
|
||||
@ -144,7 +144,12 @@ class SimConfig:
|
||||
# take the oldest candidates first, deterministically, because an uncle expires w_u slots
|
||||
# after its own slot so the oldest are the closest to expiring. Every headline result uses it.
|
||||
uncle_strategy: UncleStrategy = "oldest"
|
||||
uncle_window_anchor: UncleWindowAnchor = "uncle" # "parent" = the proposed rule
|
||||
# DEFAULT is the deployed rule, so the simulator describes the protocol as it stands and the
|
||||
# §6.12 proposal is an explicit arm — the same convention `fixed_point` follows. It must also
|
||||
# stay "uncle" for a harder reason: key() appends the anchor only when it is not "uncle", so
|
||||
# this default is what keeps an --old run's key byte-identical to the pre-redesign key and
|
||||
# lets it bit-reproduce every historical run (§9).
|
||||
uncle_window_anchor: UncleWindowAnchor = "uncle"
|
||||
# "random" is NOT a spec variant — it is the deviation probe: walk the same oldest-first
|
||||
# candidate order but include each candidate with probability uncle_random_p, so a lone
|
||||
# candidate is dropped half the time. Uncle selection is proposer-local and unvalidated, so a
|
||||
@ -436,6 +441,7 @@ class SimConfig:
|
||||
# Axes that can be swept; every SimConfig field is legal here.
|
||||
_SWEEP_AXES = (
|
||||
"n_nodes", "stake_dist", "latency", "max_uncles", "uncle_strategy", "uncle_window",
|
||||
"uncle_window_anchor",
|
||||
"window_absorption",
|
||||
"topology", "degree", "link_latency_mean", "link_latency_dist",
|
||||
"blend_hops", "blend_delay_max", "init_dest", "f",
|
||||
@ -452,6 +458,7 @@ class SweepConfig:
|
||||
max_uncles: list[int] = field(default_factory=lambda: [0, 1, 2, 4])
|
||||
uncle_strategy: list[UncleStrategy] = field(default_factory=lambda: ["oldest"])
|
||||
uncle_window: list[int] = field(default_factory=lambda: [constants.W_DEFAULT])
|
||||
uncle_window_anchor: list[UncleWindowAnchor] = field(default_factory=lambda: ["uncle"])
|
||||
window_absorption: list[float] = field(default_factory=lambda: [constants.W_ABS_DEFAULT])
|
||||
topology: list[Topology] = field(default_factory=lambda: ["regular"])
|
||||
degree: list[int] = field(default_factory=lambda: [8])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user