Skip to content

[PARKED] EIP-8198: make slot-duration changes schedule-driven - #4

Open
chugarchugarr wants to merge 6 commits into
eip8198-refresh-basefrom
eip8198-slot-time-agnostic-review
Open

chugarchugarr wants to merge 6 commits into
eip8198-refresh-basefrom
eip8198-slot-time-agnostic-review

Conversation

@chugarchugarr

@chugarchugarr chugarchugarr commented Aug 26, 2026 •

Copy link
Copy Markdown
Owner

Status — PARKED / evidence-only

This PR is retained as an executable generality and falsification proof for EIP-8198. It is not requesting merge or protocol acceptance.

Reality sync — 2026-09-23

The current upstream consensus-spec direction in ethereum/consensus-specs#5592 now explicitly avoids tight coupling between CL slot-duration scheduling and the EL. The stated EL direction is fork-local re-parameterisation: update the base-fee rule for the new cadence, re-parameterise the blob schedule, and coordinate the gas-limit target around the fork rather than exporting SLOT_DURATION_SCHEDULE into execution.

That changes the activation condition for this proof.

The executable schedule-driven EL implementation below is not currently the presumptive upstream implementation shape. A runtime EL slot-duration schedule is only needed if the narrower fork-local approach fails to preserve an execution invariant across repeated duration changes, or if upstream later chooses to expose slot-duration eras directly to the EL.

The composability constraint established here still matters:

  • one-time capacity scaling composes as new_duration / old_duration at each boundary;
  • persistent base-fee responsiveness must preserve the cumulative wall-clock scaling, not reset to a fresh adjacent-duration ratio as though the new era were the original baseline;
  • equivalently, a fork-local implementation can remain schedule-free if each new parameterization carries forward the prior effective coefficient, e.g. k_new = k_old * new_duration / old_duration, which composes to k_base * active_duration / base_duration.

So the current falsifier is narrow:

Reactivate this proof only if an upstream EL implementation/test demonstrates that fork-scoped parameter updates cannot preserve the cumulative wall-clock invariant across a second slot-duration reduction, or if an EL rule needs historical duration-era knowledge at runtime.

No such falsifier is presently established.

Relevant upstream evidence:

Current comparison boundary:

  • base eip8198-refresh-base = e5b6e3b5ccd68eb47f2cba35da16cd2b240cb8b8
  • head = 82acb3e5559fa1e18559ac12fd097cc62f8260d1
  • candidate delta = 1 commit / 8 files

Current exact-head validation:

  • run 33466789390 checks out exact head 82acb3e5559fa1e18559ac12fd097cc62f8260d1
  • just static — PASS
  • just spec-tools — PASS (22 passed; 32 warnings)
  • focused additional-duration proof — PASS (3 passed)
  • full tests/evm_tools/eip8198_quick_slots suite — PASS (12 passed)
  • comparison against refreshed base e5b6e3b5ccd68eb47f2cba35da16cd2b240cb8b8 remains exactly 1 commit / 8 files

Validation run: https://github.com/chugarchugarr/execution-specs/actions/runs/33466789390

The previous exact-head validation artifact at 4f748a001c772e643b4a7314c70656b65c06f053, including run 33326674593, remains historical evidence only and is not being represented as current-head CI.

CI provenance

What the proof tests

The executable claim is architectural: repeated synthetic duration eras can use shared duration/transition machinery without adding duration-specific execution branches.

The historical reference behavior is the 12s -> 10s implementation. Synthetic 10s -> 8s -> 6s entries are test data only; they are not a proposal to activate 8- or 6-second slots without the consensus-layer performance work EIP-8198 requires.

The candidate tests that:

  • gas-limit scaling derives from parent/current duration eras so a boundary applies once;
  • repeated capacity scaling composes 60M -> 48M -> 36M;
  • base-fee responsiveness stays keyed to the pre-schedule wall-clock baseline across repeated eras;
  • blob capacity/pricing helpers resolve the active duration era from the same schedule;
  • no 8-second- or 6-second-specific execution branch is introduced.

Current interpretation

This PR establishes that a schedule-driven EL can satisfy the repeated-era invariant. It does not establish that the EL must own the schedule.

The present upstream CL design has found a narrower architecture that may satisfy the same invariant while preserving CL/EL separation of concerns. Until that architecture fails a repeated-era execution test, this PR remains parked as executable evidence and a ready-made falsification harness.

@chugarchugarr
chugarchugarr force-pushed the eip8198-slot-time-agnostic-review branch from 396ac9d to 577ff91 Compare August 27, 2026 00:43
@chugarchugarr chugarchugarr changed the title EIP-8198: make repeated slot-duration changes schedule-driven EIP-8198: make the 10s -> 6s slot reduction schedule-driven Aug 27, 2026
@chugarchugarr
chugarchugarr force-pushed the eip8198-slot-time-agnostic-review branch from 577ff91 to 396028d Compare August 27, 2026 00:51
@chugarchugarr chugarchugarr changed the title EIP-8198: make the 10s -> 6s slot reduction schedule-driven EIP-8198: make slot-duration changes schedule-driven Aug 27, 2026

Copy link
Copy Markdown
Owner Author

Final exact-head proof is green: https://github.com/chugarchugarr/execution-specs/actions/runs/33028230600

@CarlBeek @barnabemonnot — requesting one narrow review of the execution-layer property: after the existing 12s→10s reference implementation, can a later synthetic 10s→6s era be expressed through schedule data without another duration-specific execution path while preserving the intended wall-clock behavior?

The synthetic six-second era is test data only. This does not propose six-second activation without EIP-8198's consensus-layer performance work. Canonical evidence boundary: https://github.com/chugarchugarr/-x402-resolution-receipt/issues/2

Copy link
Copy Markdown
Owner Author

Added a second synthetic future duration so the claim is no longer only 10s -> 6s: current head 4f748a001c772e643b4a7314c70656b65c06f053 now exercises 12s -> 10s -> 8s -> 6s through the same schedule-driven production helpers, including 60M -> 48M -> 36M gas-capacity scaling and blob-schedule derivation.

The final added test content passes the repository-pinned Ruff formatter and focused pytest in run https://github.com/chugarchugarr/execution-specs/actions/runs/33325824901. Full fork-native workflows on the PR head are still running/queued.

The review question stays narrow: does this establish the EL property that later slot-duration changes can remain schedule data rather than require another duration-specific branch?

@chugarchugarr
chugarchugarr force-pushed the eip8198-slot-time-agnostic-review branch from 4f748a0 to b95caf4 Compare August 31, 2026 12:14
@chugarchugarr
chugarchugarr changed the base branch from eip8198-quick-slots-base to eip8198-refresh-base August 31, 2026 20:06
@chugarchugarr chugarchugarr changed the title EIP-8198: make slot-duration changes schedule-driven [PARKED] EIP-8198: make slot-duration changes schedule-driven Aug 31, 2026
@chugarchugarr
chugarchugarr force-pushed the eip8198-slot-time-agnostic-review branch 5 times, most recently from 108aee1 to 47edf92 Compare September 1, 2026 12:47
danceratopz and others added 3 commits September 1, 2026 17:16
* feat(tests): add type-0 transaction RLP validity tests

Port the core malformation classes of the legacy TransactionTests
suites (ttWrongRLP, ttNonce, ttValue, ttRSValue, ttVValue, ttAddress),
which were never converted because the ported-static pipeline only
handles state-test fillers and the raw malformed bytes cannot
round-trip through a structured transaction model.

A local RLP encoder builds each corruption deliberately, since a
correct encoder cannot emit non-canonical forms: per-field leading
zeros, 33-byte field overflows, 19 and 21 byte addresses, fields
encoded as lists, structural corruptions of the outer list (truncation,
trailing bytes, wrong element counts, header size mismatches, size
with leading zeros), and well-encoded but invalid signature values.
A valid re-encoded control case anchors the encoder to the framework's
byte-exact output.

The transaction_test fixture format records the declared exception
without consulting the transition tool, so all 30 cases were verified
externally by feeding the generated fixture bytes through EELS
decode_transaction, recover_sender and validate_transaction at
Frontier, London and Cancun: every invalid vector is rejected and the
control is accepted with the matching sender. Notably the gas limit
and gas price are unbounded scalars in the spec, so their oversized
encodings are valid at the transaction level; the overflow cases cover
the 256-bit bounded fields (nonce, value, r, s) only.

* fix(tests): accept client-divergent transaction RLP exceptions

Declare exception lists where clients legitimately report different
errors for the same malformed transaction:

- `header_declares_less`: the mutation leaves both a truncated final
  field and a trailing byte at the top level, so clients report it as
  either an EOF or a size error.
- `v_29`: post EIP-155 clients may derive a chain id from any v other
  than 27 or 28 and reject the mismatch instead of the signature, as
  already documented in `test_bad_v_r_s`.

* chore(tests): correct the transaction field overflow docstring

The nonce is decoded as a 256-bit scalar by the spec; the 64-bit bound
is an EIP-2681 validation rule, not a decoding one. Also note that the
signature v is a bounded 256-bit field whose oversized encoding is
uncovered only because no field-specific decoding exception exists.

* feat(tests): add r and s field-as-list transaction RLP cases

Extend `test_field_as_list` to the signature r and s fields, porting
`TRANSCT_rvalue_GivenAsListCopier` and `TRANSCT_svalue_GivenAsListCopier`
with the same `RLP_INVALID_SIGNATURE_R`/`_S` exceptions the legacy
suite declares. The gas price and v fields remain uncovered for lack
of a field-specific decoding exception.

* feat(tests): add a non-canonical single-byte transaction RLP case

Encode the single-byte nonce payload behind a one-byte string header
(0x8101) instead of as the byte itself. This ports the
`RLPIncorrectByteEncoding{00,01,127}Copier` legacy tests, which corrupt
the nonce this way and declare `RLP_LEADING_ZEROS_NONCE_SIZE`.

* feat(tests): add a data size leading zeros transaction RLP case

Encode the size of the data field's long-form string header with a
leading zero byte, porting `RLPArrayLengthWithFirstZerosCopier` with
the `RLP_LEADING_ZEROS_DATA_SIZE` exception it declares. This covers
the string-header variant of the list-header case already tested by
the `list_size_leading_zeros` mutation.

* feat(tests): add a zero v transaction signature case

A zero v is well-encoded (empty payload) but is neither 27, 28 nor an
EIP-155 value. Declare `INVALID_CHAINID` as an acceptable alternative
for the same reason as the other invalid v cases: post EIP-155 clients
may derive a chain id from any v other than 27 or 28.

* chore(tests): cite more covered legacy transaction test fillers

Add `ported_from` references for legacy fillers whose malformation
class is already exercised by an existing case:

- Leading zeros: the `tt{Nonce,GasPrice,GasLimit,Value}` zero-prefixed
  fillers and the `TRANSCT_*_Prefixed0000` copiers.
- Overflow: the `TRANSCT_{r,s}value_TooLarge` copiers.
- Address size: `AddressMoreThan20` and the `TRANSCT_to_*` copiers.
- Field as list: the remaining `TRANSCT_*_GivenAsList` copiers.
- Structure: `RLPTransactionGivenAsArray`, matching the
  `tx_as_byte_string` mutation.

All referenced fillers were inspected at the pinned commit to confirm
the corruption and declared exception match the covering case.

* fix(tests): fund only senders that send in transaction RLP tests

In execute mode, `pre.fund_eoa()` defers the funding amount until the
EOA sends a transaction; an EOA that never sends one fails the run
with "Sender balance must be set before sending". The senders of the
corrupted transactions never send: only their raw serialization is
submitted, expecting rejection. Fund them with `amount=0` so execute
mode derives an address without scheduling a funding transaction.

The signing keys are derived from the account content, so the
corrupted vectors' bytes change; all vectors were re-verified against
EELS decoding and validation at Frontier, London and Cancun.

* chore(tests): mark transaction RLP tests as inclusion tests

Each case asserts whether one transaction can be included in a block,
which is what the `inclusion_test` marker denotes.

* fix(tests): accept a type error for a transaction given as a byte string

EIP-2718 reads a byte string in the transaction list as a typed
transaction, so from Berlin on the corruption is reported as an
unsupported transaction type rather than an RLP header error. Verified
against EELS decoding at Frontier, Berlin and Cancun.

---------

Co-authored-by: danceratopz <danceratopz@gmail.com>
No spec-specific constants were useful to add here. This may change but
the import from the relevant spec is preferred over adding them here if they
are not BALs specific.
@chugarchugarr
chugarchugarr force-pushed the eip8198-slot-time-agnostic-review branch from 47edf92 to 4bef25e Compare September 1, 2026 18:31
ethereum#3490)

* feat(tests): pin cross-frame state gas refund placement and settlement

* feat(tests): EIP-8037 cross-frame refund split across a child's own spill

Test that one frame's refund both repays a different slot's borrow and
puts the excess in the reservoir, that the split state merges cleanly
on success, and that it is fully unwound on revert and halt.

* chore(tests): use fork transaction gas limit cap, not constant val

* fix: apply comments from PR ethereum#3490

---------

Co-authored-by: fselmo <fselmo2@gmail.com>
@chugarchugarr
chugarchugarr force-pushed the eip8198-slot-time-agnostic-review branch from 4bef25e to 26473fe Compare September 1, 2026 20:25
@chugarchugarr
chugarchugarr force-pushed the eip8198-slot-time-agnostic-review branch from 26473fe to 739c870 Compare September 1, 2026 21:15

Copy link
Copy Markdown
Owner Author

Completed the activation-gate experiment: #5

Exact head: 4cecc230422ad01815c0535d20d877dca4525d34
Focused proof: https://github.com/chugarchugarr/execution-specs/actions/runs/35881396301

Result:

  • Ruff check — PASS
  • Ruff format — PASS
  • fork-local falsification suite — 109/109 PASS
  • repository-native just static and packaging hosted gates — PASS

The strongest schedule-free competitor carried fixed EL parameters per synthetic 12s -> 10s -> 8s -> 6s fork and contained no runtime slot/epoch/duration-schedule lookup. It exactly reproduced the oracle's base-fee behavior, composed gas targets, blob constants, and blob pricing across the tested matrix.

The discrete blob-rounding probe also did not establish a need for runtime history: later fork constants can be selected explicitly against the wall-clock objective rather than being forced to inherit sequential rounding.

Therefore the falsifier required to reactivate this runtime-schedule implementation was not produced. This PR remains PARKED as executable oracle/regression evidence. The activation condition is unchanged: revive only if an upstream EL path exposes an invariant that valid fork-local reparameterization cannot preserve, or an EL rule genuinely needs historical duration-era state at runtime.

No Ethereum upstream repository was modified by this experiment.

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.

6 participants