Skip to content

feat(l1): pluggable sequencer reward calculator (AZIP-28) - #25571

Merged
spalladino merged 12 commits into
spl/azip28-1-rollback-overridesfrom
spl/azip28-2-sequencer-reward-calculator
Oct 2, 2026
Merged

spalladino merged 12 commits into
spl/azip28-1-rollback-overridesfrom
spl/azip28-2-sequencer-reward-calculator

Conversation

@spalladino

@spalladino spalladino commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Implements AZIP-28: the rollup calls a governance-set ISequencerRewardCalculator once per epoch proof to get one sequencer reward per newly proven checkpoint.

Rollup changes

  • sequencerRewardCalculator in the namespaced reward storage; setSequencerRewardCalculator (owner only, emits SequencerRewardCalculatorUpdated(old, new)), getSequencerRewardCalculator, optional initial value via RollupConfigInput.sequencerRewardCalculator / AZTEC_SEQUENCER_REWARD_CALCULATOR (default zero). Setter/getter go through RewardExtLib for bytecode size.
  • Proposers are derived from the committee the proof already verifies (slot + sample seed). Escape-hatch epochs and empty committees skip the calculator.
  • SequencerRewardCalculatorLib: staticcall with exactly CALCULATOR_GAS_BASE + n * CALCULATOR_GAS_PER_CHECKPOINT (200k + 100k·n). Nothing is copied unless returndatasize == 64 + 32n; the head must be offset 32 / length n; every value <= MAX_SEQUENCER_REWARD_PER_CHECKPOINT (1e24). Any failure pays the default to every checkpoint.
  • Distribution: no calculator, skipped, or rejected response uses the pre-AZIP arithmetic exactly. An accepted response draws n × (checkpointReward − default) + Σ rewards, scales sequencer rewards by available / desired under shortfall, and gives the prover the remainder. Prover rewards are now written to storage once per proof.

Deviations from the AZIP text (spec should be amended)

  • The rollup reverts with SequencerRewardCalculatorLib__InsufficientGas if the transaction cannot forward the full stipend (EIP-150 63/64 rule plus a 10k reserve). Otherwise the prover could starve the calculator and force defaults. The requirement depends on constants only (≈3.46M at n = 32), so eth_estimateGas covers it.
  • Under a distributor shortfall the prover's payout depends on the calculator's values (it is a consequence of the AZIP's proportional rule); "prover share MUST NOT depend on the calculator" holds only without a shortfall.
  • A calculator that returns exactly the default can differ from the zero-calculator split by at most 1 wei per checkpoint, only under a shortfall and only when checkpointReward * bps is not a multiple of 10,000.

Gas (partial epoch proof, mock verifier): no calculator 656,493 / 954,823 / 1,240,004 / 1,717,873 for 1 / 8 / 16 / 32 checkpoints (−14.9k at 32 vs. the previous PR). Rollup's own overhead with a calculator: ~14k + ~1.3k per checkpoint.

Rollup bytecode: 24,131 bytes (445 spare). Every AZIP "Test Cases" bullet maps to a test (unit, fuzz, through-the-rollup, escape hatch, zero-size committee, deploy config, gas rows at 1/8/16/32). forge test: 1164 passed, 0 failed.

RollupConfigInput gains a trailing address; no labs change needed. Client mirrors (node-side reward prediction) are left for a follow-up in aztec-node, since no predictor exists today.

@spalladino
spalladino added this pull request to stack #25574 October 1, 2026 23:13
@spalladino spalladino changed the title spl/azip28 2 sequencer reward calculator feat(l1): pluggable sequencer reward calculator (AZIP-28) Oct 1, 2026
@spalladino spalladino added the ci-draft Run CI on draft PRs. label Oct 1, 2026
@spalladino
spalladino marked this pull request as ready for review October 2, 2026 12:36
@spalladino
spalladino force-pushed the spl/azip28-2-sequencer-reward-calculator branch from aa82c68 to a7b833d Compare October 2, 2026 18:42
@spalladino
spalladino removed this pull request from stack #25574 October 2, 2026 18:43
@spalladino
spalladino added this pull request to stack #25584 October 2, 2026 18:43
@spalladino
spalladino force-pushed the spl/azip28-2-sequencer-reward-calculator branch from a7b833d to 1eb366c Compare October 2, 2026 19:47
Adds a governance-set sequencer reward calculator to the rollup. When an
epoch proof pays checkpoint rewards, the rollup derives the proposer of
each newly proven checkpoint from the verified committee and makes one
staticcall to the calculator with exactly
CALCULATOR_GAS_BASE + CALCULATOR_GAS_PER_CHECKPOINT * n gas. The response
is accepted only if returndatasize is exactly 64 + 32n (checked before
anything is copied), the ABI head is offset 32 / length n, and every value
is at most MAX_SEQUENCER_REWARD_PER_CHECKPOINT. Any failure, a zero
calculator, an escape-hatch epoch or a zero-size committee pays the default
with the unchanged calculator-less arithmetic.

With an accepted response the rollup claims only
n * (checkpointReward - default) + sum(rewards) and, under a distributor
shortfall, scales each sequencer reward by available / desired with the
remainder going to the prover pool.

The rollup reverts with RewardLib__InsufficientGasForCalculator when the
transaction cannot forward the full stipend, so a submitter cannot starve
the calculator into paying defaults.

- ISequencerRewardCalculator, SequencerRewardCalculatorLib (constants and
  the defensive call), calculator address in RewardStorage
- setSequencerRewardCalculator (owner only, emits
  SequencerRewardCalculatorUpdated) and getSequencerRewardCalculator,
  routed through RewardExtLib
- RollupConfigInput.sequencerRewardCalculator and the
  AZTEC_SEQUENCER_REWARD_CALCULATOR deploy variable (default zero)
- prover fees are accumulated and written to storage once per proof
- ISequencerRewardCalculator ABI exported by l1-artifacts
- calculatorCall.t.sol: the defensive call in isolation: well-formed
  responses at n = 1/8/16/32, too little/too much data, wrong offset,
  wrong length, MAX accepted and MAX + 1 rejected, revert, revert and
  return bombs not copied, gas burn bounded by the stipend, state changes,
  accounts without code, the exact stipend, the smallest sufficient gas
  (cold, including an EIP-7702 delegated calculator), and fuzzed raw and
  structured responses against an oracle.
- sequencerRewardCalculator.t.sol (RewardLib): zero calculator, empty
  committee and every failing calculator against an independent oracle of
  the calculator-less split (shortfall rounding included); below, equal
  and above default values and premiums up to MAX paid exactly; repeated
  proposers passed once per checkpoint; proposer derivation, also for
  partial-epoch extensions; proportional shortfall; nothing desired;
  fuzzed distribution invariants.
- Rollup setter/getter/constructor, getter without writes, escape-hatch
  epochs skipping the calculator.
- Partial epoch proof gas rows with a table calculator, proposer
  derivation through the rollup, compact extension equivalence, the
  stipend seen by the calculator at n = 1/8/16/32, and a gas-burning
  calculator with fresh coinbases landing given enough gas.
…tfall rounding

Adds an independent oracle for checkpoint rewards together with nonzero
protocol, prover and sequencer fees on every reward path, including a
compact extension, pins the 1 wei rounding difference of a
default-returning calculator under a shortfall and the prover share's
dependence on the calculator under a shortfall, and documents that the
stipend check bounds the calculator, not the gas of the whole proof.
@spalladino
spalladino force-pushed the spl/azip28-2-sequencer-reward-calculator branch from 1eb366c to 1d34881 Compare October 2, 2026 20:33
@spalladino
spalladino merged commit c85ce19 into next Oct 2, 2026
19 of 21 checks passed
@spalladino
spalladino deleted the spl/azip28-2-sequencer-reward-calculator branch October 2, 2026 21:15
@AztecBot AztecBot mentioned this pull request Oct 2, 2026
15 tasks done
AztecBot pushed a commit that referenced this pull request Oct 4, 2026
Implements AZIP-28: the rollup calls a governance-set
`ISequencerRewardCalculator` once per epoch proof to get one sequencer
reward per newly proven checkpoint.

**Rollup changes**
- `sequencerRewardCalculator` in the namespaced reward storage;
`setSequencerRewardCalculator` (owner only, emits
`SequencerRewardCalculatorUpdated(old, new)`),
`getSequencerRewardCalculator`, optional initial value via
`RollupConfigInput.sequencerRewardCalculator` /
`AZTEC_SEQUENCER_REWARD_CALCULATOR` (default zero). Setter/getter go
through `RewardExtLib` for bytecode size.
- Proposers are derived from the committee the proof already verifies
(slot + sample seed). Escape-hatch epochs and empty committees skip the
calculator.
- `SequencerRewardCalculatorLib`: `staticcall` with exactly
`CALCULATOR_GAS_BASE + n * CALCULATOR_GAS_PER_CHECKPOINT` (200k +
100k·n). Nothing is copied unless `returndatasize == 64 + 32n`; the head
must be offset 32 / length n; every value `<=
MAX_SEQUENCER_REWARD_PER_CHECKPOINT` (1e24). Any failure pays the
default to every checkpoint.
- Distribution: no calculator, skipped, or rejected response uses the
pre-AZIP arithmetic exactly. An accepted response draws `n ×
(checkpointReward − default) + Σ rewards`, scales sequencer rewards by
`available / desired` under shortfall, and gives the prover the
remainder. Prover rewards are now written to storage once per proof.

**Deviations from the AZIP text (spec should be amended)**
- The rollup reverts with
`SequencerRewardCalculatorLib__InsufficientGas` if the transaction
cannot forward the full stipend (EIP-150 63/64 rule plus a 10k reserve).
Otherwise the prover could starve the calculator and force defaults. The
requirement depends on constants only (≈3.46M at n = 32), so
`eth_estimateGas` covers it.
- Under a distributor shortfall the prover's payout depends on the
calculator's values (it is a consequence of the AZIP's proportional
rule); "prover share MUST NOT depend on the calculator" holds only
without a shortfall.
- A calculator that returns exactly the default can differ from the
zero-calculator split by at most 1 wei per checkpoint, only under a
shortfall and only when `checkpointReward * bps` is not a multiple of
10,000.

**Gas (partial epoch proof, mock verifier)**: no calculator 656,493 /
954,823 / 1,240,004 / 1,717,873 for 1 / 8 / 16 / 32 checkpoints (−14.9k
at 32 vs. the previous PR). Rollup's own overhead with a calculator:
~14k + ~1.3k per checkpoint.

Rollup bytecode: 24,131 bytes (445 spare). Every AZIP "Test Cases"
bullet maps to a test (unit, fuzz, through-the-rollup, escape hatch,
zero-size committee, deploy config, gas rows at 1/8/16/32). `forge
test`: 1164 passed, 0 failed.

`RollupConfigInput` gains a trailing `address`; no labs change needed.
Client mirrors (node-side reward prediction) are left for a follow-up in
aztec-node, since no predictor exists today.

(cherry picked from commit c85ce19)
IlyasRidhuan added a commit that referenced this pull request Oct 4, 2026
Rolling integration PR for changes labelled `port-to-v6` on `next`. Each
merged source PR is cherry-picked onto `cb/port-to-v6` as its own
commit, keeping `(#N)` in the title.

## Ported

- [x]
[#25536](#25536)
fix(kernels): charge the teardown call's AVM startup gas (pick applied
without conflicts, plus two `fix(port)` commits)
- `fix(port)` 1 drops
`labs-patches/0001-fix-pxe-charge-the-teardown-call-s-AVM-startup-gas-i.patch`,
which the pick brings along. The labs pin on `v6` (`a0d73c0aed`) already
carries that PXE change upstream as aztec-labs-eng/aztec-node#364, so
the patch has nothing to apply to. The Noir side is `gas_meter.nr` and
`validate_gas_used_tests.nr`, both identical to `next`.
- `fix(port)` 2 adds labs patch
`0001-test-pin-testnet-compatibility-to-the-v6-kernel-VK-t.patch`, which
re-pins the VK tree root in
`labs/yarn-project/aztec/src/testnet_compatibility.test.ts`.
- [x]
[#25576](#25576)
fix(p2p): require exact contract class log length in DataTxValidator
(labs patch) (clean pick)
- Adds labs patch
`0010-fix-p2p-require-exact-contract-class-log-length-in-D.patch`. Both
files it touches (`data_validator.ts`, `data_validator.test.ts`) have
the same pre-image blobs on the `v6` labs pin as on `next`'s.
- [x]
[#25577](#25577)
fix(l1): include the Noir compiler in the l1-contracts cache hash (clean
pick)
- `noir/bootstrap.sh hash` is what the other Noir consumers on `v6`
already use (`avm-transpiler`, `noir-protocol-circuits`, `acir_tests`).
- [x]
[#25578](#25578)
fix(circuits): key the VK cache on its real inputs and never cache the
L1 verifier (clean pick)
- With #25577 and this one applied,
`noir-protocol-circuits/bootstrap.sh` and `scripts/circuit_kind.test.sh`
are identical to `next` at b0a7559.
- [x]
[#25579](#25579)
fix(private-kernel): a surviving nullifier link may only resolve to a
non-revertible note hash (pick applied without conflicts, plus one
`fix(port)` commit)
- It changes the `private-kernel-reset-tail-to-public` circuits, so the
VK tree root moves again. The `fix(port)` commit updates labs patch 0001
to the new root.
- [x]
[#23587](#23587)
fix: anchor Grumpkin SRS to pinned chunk hashes on load (clean pick)
- All eight files end up identical to `next` at 08f90e6, as does the
rest of `barretenberg/cpp/src/barretenberg/srs`. No later commit on
`next` touches them.
- [x]
[#25580](#25580)
test(private-kernel): reject a duplicate nullifier index hidden behind
an inactive squashing hint (clean pick)
- Test-only: one test and its import in
`validate_transient_data_squashing_hints.nr`.
- With #25536, #25579 and this one applied, the `private-kernel-lib`
crate is identical to `next` at b1b6871.
- [x]
[#25530](#25530)
chore: move away from auto-close-issues.yml (clean pick)
- Deletes `.github/workflows/auto-close-issues.yml` and
`scripts/auto_close_issues.py`. Nothing else on `v6` invokes either.
- [x]
[#25566](#25566)
docs(types): document that poseidon2_hash_bytes does not commit the byte
length (clean pick)
- A doc comment and three unit tests in `types/src/hash.nr`, which ends
up identical to `next` at 4f4bef8.
- [x]
[#25582](#25582)
fix: Avoid early proof submission prover griefing (clean pick)
- [x]
[#25585](#25585)
test: cover prover registration upgrade paths (clean pick)
- Review follow-up to #25582: forge tests, a test wrapper
simplification, and one corrected comment in `RewardLib.sol`. No
contract logic changes.
- [x]
[#25570](#25570)
refactor(l1): remove the built-in checkpoint reward overrides (clean
pick)
- `v6` carries the override stack this removes (#25312, #25426, #25461)
and the proof-submission optimizations it keeps (#25404, #25406,
#25419).
- Nothing outside `l1-contracts` references what it removes
(`registryRewardOverrides`, `AZTEC_REGISTRY_REWARD_OVERRIDE_*`,
`getRegistryRewardOverrides`, the four `RewardLib__*` errors): no hits
in this repo or in the `v6` labs pin `a0d73c0aed`.
- [x]
[#25571](#25571)
feat(l1): pluggable sequencer reward calculator (AZIP-28) (clean pick)
- Adds `ISequencerRewardCalculator`, `SequencerRewardCalculatorLib`, the
`sequencerRewardCalculator` rollup config field,
`setSequencerRewardCalculator` / `getSequencerRewardCalculator`, and the
optional `AZTEC_SEQUENCER_REWARD_CALCULATOR` deploy variable (zero
address by default).
- Nothing in the `v6` labs pin references the calculator. Labs imports
`network-defaults.json` directly, where the new key is an added default.
- [x]
[#25572](#25572)
test(l1): reference registry reduction sequencer reward calculator
(clean pick)
- Test-tree only (`l1-contracts/test/reward-calculators`, a fork test
and its fixture), plus the `foundry.toml` read permission for the
fixture and regenerated gas reports.
- [x]
[#25573](#25573)
test(l1): reference premium sequencer reward calculator with
provenance-tracking ATPs (clean pick)
- Test-tree only (`l1-contracts/test/reward-calculators/premium`), plus
regenerated gas reports.
- With #25577, #25578, #25582, #25585, #25570, #25571, #25572 and this
one applied, the whole `l1-contracts` directory is identical to `next`
at 551aa41.

## Protocol impact

- #25536 and #25579 both change private kernel circuits, so the VK tree
root that `v6` builds moves:
- from
`0x2d89003cc2dc62b06f07d83d3635c66c63fc43668369d30e7ee516f908ee10e3`
(the testnet deployed from `v6`)
- to
`0x05b95d9ef57c61d1c6626545101db55ae2d1f98ecb618d1c220610c049ee522b`
(taken from this PR's failing CI run on `34e0b24f`), which is what labs
patch 0001 pins
- the intermediate root with #25536 alone was
`0x21f06c3b82320ea5f80646751cdd9fa023dfd61400a42b8c952aa32e8f155793`
(from the failing CI run on `bed8264`)
- After this merges, `v6` no longer matches the currently deployed
testnet until it is redeployed. The re-pin follows the decision recorded
on #25549 (a breaking kernel change ported to `v6` re-pins testnet in
the same PR).
- The protocol contracts hash and the genesis root are unchanged; those
two assertions passed on `34e0b24f`.
- #25570 and #25571 change how the L1 rollup pays sequencers:
- the per-registry checkpoint reward overrides built into the rollup are
gone, along with `RollupConfigInput.registryRewardOverrides`,
`getRegistryRewardOverrides` and the `AZTEC_REGISTRY_REWARD_OVERRIDE_*`
deploy variables
- sequencer reward policy is delegated to an optional governance-set
calculator contract; with none configured every proposer gets the
default sequencer share
- #25572 and #25573 add reference calculators under `l1-contracts/test`
only; no calculator ships in `src` or is configured by default
- #25582 changes the L1 rollup contracts: `RewardLib` reward handling
for early proof submissions, and a new `getHasSubmittedFullEpoch` view
on `IRollup` / `Rollup`.
- Per #25585, the prover node (`prover-node-publisher.ts` in
`aztec-labs-eng/aztec-node`) still skips submission when
`getHasSubmitted` is true. It has to use `getHasSubmittedFullEpoch` for
full-epoch proofs before the fix helps honest provers; that change is
not in this PR or in the `v6` labs pin's patch series.
- The L1 changes take effect only on a rollup deployed from this code.
- #25536 is a repricing: a public tx with a teardown call is charged
20_000 more L2 gas. The PXE on `v6` already estimates that amount.
- #25579 rejects, in tail-to-public only, a nullifier whose note hash
link resolves to a revertible note hash. No honest client produces that
witness; the private-only tail circuit is unchanged.
- #25576 tightens p2p tx validation: a contract class log whose `length`
exceeds its trimmed length is now rejected. Honest producers already
emit the trimmed length.
- #23587 makes bb check a loaded Grumpkin SRS against pinned chunk
hashes. It changes the bb binary, not any circuit.
- #25580 and #25566 add unit tests (and a doc comment) and change no
circuit.
- #25530 removes a GitHub workflow: issues referenced by commits pushed
to `v6` are no longer closed by the script.
- #25577 and #25578 are build-cache only and change no circuit:
  - the l1-contracts cache key now follows the Noir commit
- the VK cache key now covers the circuit kind and the bootstrap script,
so every VK is regenerated once
- the Solidity verifier is written on every build instead of restored
from the cache
- l1-contracts gains a test that `generated/HonkVerifier.sol` equals the
circuits-side verifier

## Testing

- CI3 passed on `fb097a89` (the first eleven ports, through #25585),
including the testnet compatibility test against the re-pinned root and
the l1-contracts forge tests.
- CI3 on `34e0b24f` (the first nine ports, before the second re-pin) ran
about 10,400 tests; the only failure was the VK tree root assertion that
the second re-pin fixes.
- `./labs-patches/bootstrap.sh check`: the series (0001, 0010) applies
cleanly to `a0d73c0aed`. Patch 0001 was produced with `bootstrap.sh
apply` / `export`.
- #25577 / #25578: `bash -n` passes on both bootstrap scripts and
`scripts/circuit_kind.test.sh` passes locally. `v6` has no
`pinned-build.tar.gz`, so the pinned-build path is not exercised.
- No circuits, bb or L1 contracts were built locally (no `nargo`, no bb
build and no pinned `solc` in the port environment). The four AZIP-28
ports (#25570 to #25573) have no CI result yet: the forge suite, the
labs build against the changed rollup ABI and the deploy-script tests
run on this PR's CI.
- The branch is based on `v6` at cf7ea33; `v6` has since gained
#25551 (a notify workflow change), which merges without conflicts.

---
*Created by
[claudebox](https://claudebox.work/v2/sessions/134efca9a11ee14f/jobs/7)
· group: `slackbot` · [Slack
thread](https://aztecprotocol.slack.com/archives/C0AGN2WT3CP/p1790609320989739?thread_ts=1790609320.989739&cid=C0AGN2WT3CP)*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on draft PRs. port-to-v6

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants