Skip to content

Proto Sling node#272

Open
GCdePaula wants to merge 5 commits into
next/3.0from
feature/sling-node
Open

Proto Sling node#272
GCdePaula wants to merge 5 commits into
next/3.0from
feature/sling-node

Conversation

@GCdePaula

Copy link
Copy Markdown
Collaborator

What this is

A ground-up rewrite of the rollups node, landed as five reviewable commits on top of next/3.0. The headline: the node becomes a single crate where one spec-oracled engine serves both the machine runner's forward schedule and the dispute path's random access — previously two hand-maintained implementations of the same consensus-critical leaf semantics, kept in agreement only by e2e luck. It also ports the node to the staged settlement protocol (stage / sentry claim / accept) that landed on this base branch.

  • feat(node)! — the node: one crate, one engine, the boundary store, the staged settlement port. Absorbs prt/client-rs and common-rs (deleted; the node was their only consumer).
  • test(e2e) — the Lua harness: 23 scenarios (kill/respawn points, concurrent multi-sybil matches, on-chain timeout deletion), a parallel battery runner, hardened primitives. The Lua client stays an independent commitment oracle.
  • build ×2 — the just gate (just check, just doctor), devnet fingerprinting, CI triggers + emulator build caching, and just logged (true-exit-code runner).
  • docs — the knowledge base (docs/) and the campaign ledger (docs/plans/): design decisions with reasons, incident reports, and an internal audit ledger.

Where review attention pays most

In order of consensus-criticality:

  1. src/engine/ — the meta-cycle geometry and leaf conventions (ustep spans, checkpoints, idle churn, revert). This is THE trust core. Read docs/computation-hash.md first; the conventions are pinned by 15 spec tests against a brute-force oracle, and the revert semantics were verified against AdvanceStatus.sol directly (the previous node and the Lua oracle shared a wrong assumption for months — contracts are the only source of truth).
  2. src/epoch_manager/ — the staged settlement port: three guarded steps per tick; sentries claim the locally computed post-epoch hash, never the staged value. The winner asserts are deliberate panics ("notify all users").
  3. src/storage/ — the trust boundaries in the schema itself: four mutation classes enforced by SQL triggers, write-once collision tripwires that panic (never retry), the frontier's strict prefix-bounding, and the boundary store's stage+rename crash discipline (docs/plans/snapshots.md).
  4. src/tournament/ — reader/sender/witness encodings vs the contracts. docs/plans/node-audit.md records an internal adversarial audit: 10 findings with dispositions and 56 explicit clean checks (every sender argument order and witness byte layout traced against contract consumption order).

The e2e harness (prt/tests/rollups/) deserves a pass on its trust story: the oracle is self-anchored (own machine lineage, chain inputs only) and judges the node strictly from outside.

How it's verified

just check (fmt, luacheck, clippy -D warnings, unit + integration tests) green; the full 23-scenario battery green multiple times, including after the rebase onto this base (perf at parity with pre-rebase baselines). Layered nets: the spec oracle on enumerable structures, golden fixtures, committed chain recordings decoded through production bindings, and the independent Lua commitment oracle on every e2e epoch. Consensus-critical migrations were characterization-first: the old implementation's outputs were pinned as fixtures before each switch, and the differentials retired with their subjects.

Breaking / operational notes

  • Node state dirs from earlier prototypes are incompatible: the schema refuses them loudly (wipe and rebuild). No deployed-network impact; the node is pre-release.
  • prt/client-rs and common-rs are gone (absorbed).
  • CI now triggers on pull_request plus pushes to main/next/*/tags — feature branches get CI through PRs (forks finally get CI at all). First run populates the emulator cache; the speedup shows from the second run.

Deliberately not here

The halt/exception contracts rework and its node-side dependents (the runner's halted-input wedge is a deliberate stopgap until that semantics exists on-chain); the settle-revert taxonomy and the rest of audit round 2; the per-scenario CI matrix. All tracked with their reasons in docs/plans/.

The rollups node becomes a single crate: worker modules synchronize
through the storage module (the only SQL surface), and one
spec-oracled engine (src/engine: structure, stf, ruler, and the
dispute facade) serves both the runner's forward schedule and the
dispute path's random access.

- One leaf semantics: process_input and the second geometry
  implementation are gone. The runner schedules the engine's
  collect() per input window; the window-root quartet row is the
  only durable level-0 artifact; settlement and dispute serving
  read the same rows (frontier fold, strict and prefix-bounded).
- The boundary store (stage+rename, write-once cells, clone-based
  revert) carries both regimes' revert insurance; corruption
  tripwires panic through the loud process exit, never retry.
- Revert on RX_REJECTED only, matching AdvanceStatus.sol - the
  chain never reverts an exception.
- The staged settlement protocol: the epoch manager drives sentry
  claim, stage, and accept per tick, each step guarded and
  idempotent; a sentry always claims the locally computed
  post-epoch hash, never the staged value. settlement_info carries
  final_state, captured from the boundary store at roll (the new
  epoch's initial boundary IS the post-epoch state).
- Absorbs prt/client-rs (the tournament reader/sender/gc and the
  hero's react loop, traced against the contracts - the audit
  ledger records verdicts and clean checks) and common-rs (merkle,
  arithmetic, and kms become node modules; the node was their only
  consumer).
- Chain recordings - raw devnet log ranges captured after e2e
  disputes settle - are committed fixtures for the tournament
  fold, decoded through the production bindings.

Replaces the epoch-manager/state-manager/blockchain-reader/
prt-node crates, prt/client-rs, and common-rs.
23 scenarios (echo, the honeypot stf suite, kill/respawn lifecycle
points, multi_sybil's concurrent matches, kill_join), orchestrated
on hardened primitives: drive loops advance one block per poll,
Env.fast_forward is chess-clock-safe (sleep first), sybils
auto-allocate signing accounts and refuse the node's, scenario
deadlines convert hangs to failures. battery.sh runs the suite in
lanes and records power provenance. The env deploys with the
node's wallet as the sole sentry (claim staging period 1000), so
every scenario exercises the staged protocol's claim-agreement
fast path. test_env's run_epoch records the chain after settle
(RECORD_CHAIN_FIXTURE) - the capture hook for the node's fold
fixtures. The Lua client stays the independent commitment oracle;
the harness reads the node's claim from settlement_info, never
from node internals.
just check is the pre-commit gate (fmt, luacheck, clippy -D
warnings, unit and integration tests) and preflights docker
itself; just doctor diagnoses the checkout and names the fixing
command for every gap. Generated bindings are gitignored and
rebuilt by just bind; devnet artifacts carry a fingerprint.
Contracts formatting joins the gate.
The knowledge base (docs/): computation-hash, dimensioning,
epoch-lifecycle (the staged settlement protocol), node-architecture,
test-harness, glossary, build-system. The campaign ledger
(docs/plans/): sling-design, snapshots, one-engine, node-audit and
friends - decisions with their reasons, incident reports, and open
leads, including the tombstones for the rejected D.2 sub-window
tier and gap-1 default, and the promoted setup/run split. AGENTS.md
maps the repo for agent sessions; prt/contracts/AGENTS.md carries
the contracts-specific context.
CI: pull_request joins the triggers (a bare push trigger gives
forks no CI at all) and push narrows to the long-lived branches
plus release tags, deduped by the existing concurrency group. The
from-source emulator build - the build job's dominant cost - gets
a cache keyed on the submodule commit: the recipes are idempotent
(make no-ops on a warm tree, the diff apply detects an
already-patched one), so a hit skips the work and an emulator bump
rebuilds for real. Cargo caching already existed via
setup-rust-toolchain's embedded rust-cache. Two stale gap-1
comments updated to the gap-2 harness default.

Tooling, per the DX doctrine (fix the trap, not the docs): shell
pipelines like `cmd | tail` report the LAST stage's status and
have laundered real failures into green output more than once this
campaign. `just logged <file> <cmd...>` writes full output to the
file and reports the true exit code; recipe lines now run under
bash pipefail so in-recipe pipes fail honestly too (no recipe
pipes to head/tail, where pipefail would surface benign SIGPIPEs).

The CI step chained `just bundle-boost apply-generated-files-diff
build-emulator`, and just's CLI grammar feeds words following a
parameterized recipe into its arguments: apply-generated-files-diff
ran with VERSION="build-emulator", downloaded release
"build-emulator", and 404ed - silently under wget -q (exit 8, two
runs), legibly once curl started naming the error. The line was
this branch's own CI dedup and had never executed before this PR;
next/3.0's green job used a raw inline wget. Both old and new just
versions consume the argument - the 1.56->1.57 upgrade between
runs was a red herring.

Three layers so the class dies:
- The workflow calls `just setup` - dependency form passes no
  arguments and is immune to the grammar.
- The recipe guards its VERSION (must look like a release tag) and
  names the trap in its error, so any future arg-eating fails in
  one legible line instead of a mute 404.
- CI's just is pinned like rust and foundry already were; a
  floating "latest" upgrading mid-hunt muddied the evidence.
@GCdePaula
GCdePaula force-pushed the feature/sling-node branch from e7b0efd to d8cc329 Compare July 21, 2026 13:55
@GCdePaula
GCdePaula requested a review from stephenctw July 21, 2026 17:06
@GCdePaula GCdePaula self-assigned this Jul 21, 2026
@GCdePaula
GCdePaula marked this pull request as ready for review July 23, 2026 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant