Repository navigation
Description
Summary
Two follow-ups from the PR No. 197 re-review (verification comment, findings No. 6 and No. 4), each widened from PR No. 197 to every contract it applies to:
- Part A: contract size. Once PR No. 197 is merged,
DINTaskCoordinatorexceeds EIP-170 and can't be deployed. Nothing in CI or local tooling catches this, and the other large contract (DINTaskAuditor) has only about 2 KB left. We need a size budget with real headroom for all deployable contracts, and a gate that enforces it. - Part B: slash reason for committed-but-unrevealed. In both commit-reveal flows (auditor scoring and T1/T2 aggregation), a validator who commits but never reveals is slashed as a liveness miss (30%), not as a wrong answer (100% of
minStake). This is a mechanism-owner decision, tied to the No. 155 S1/S2 fraction decision and the No. 38 slashing taxonomy.
Part A: EIP-170 headroom for all contracts
Current sizes (runtime, via_ir, solc 0.8.28, optimizer_runs = 200)
| Contract | develop @ 4658bf8 |
Margin | With PR No. 197 (b3ff1b9) |
Margin |
|---|---|---|---|---|
DINTaskCoordinator |
22,689 B | 1,887 B | 24,585 B | −9 B |
DINTaskAuditor |
22,567 B | 2,009 B | 22,567 B | 2,009 B |
DinValidatorStake / V2 |
9,881 / 9,919 B | 14,695 / 14,657 B | unchanged | |
DINModelRegistry / V2 |
6,436 / 6,474 B | 18,140 / 18,102 B | unchanged | |
DinFeeRouter |
5,160 B | 19,416 B | unchanged | |
DinToken / V2 |
4,208 / 4,246 B | 20,368 / 20,330 B | unchanged | |
DinFairLaunchDistributor |
3,928 B | 20,648 B | unchanged | |
DinCoordinator / V2 |
3,697 / 3,736 B | 20,879 / 20,840 B | unchanged | |
DinEmission |
3,353 B | 21,223 B | unchanged | |
DinTreasury |
1,646 B | 22,930 B | unchanged |
The two per-model task contracts are the ones at risk. Both are already about 92% of the limit, and every mechanism-design item on the P3 roadmap (No. 38, No. 155, No. 192, No. 193, No. 194) adds code to one or the other. PR No. 191 and PR No. 197 each fitted on their own; merged together, they don't.
Why nothing caught it
.github/workflows/ci.ymlruns plainforge build/forge testwith no size check, and Solidity CI is green on PR No. 197'sb3ff1b9.forge testdoesn't enforce the limit: suite results were identical with and withoutFOUNDRY_DISABLE_CODE_SIZE_LIMIT=true.foundry/anvil.shstarts anvil with--code-size-limit 4294967295, so the local devnet deploys an oversized contract without complaint.forge build --sizesleavesDINTaskAuditorout of its table entirely (reproduced on both trees above; the figure here comes fromout/DINTaskAuditor.sol/DINTaskAuditor.json'sdeployedBytecode). So simply adding--sizesto CI would leave one of the two at-risk contracts ungated.
It would first surface as a revert when DeployPlatform.s.sol / the task-contract deploy runs against Optimism Sepolia.
Proposal
- Budget: a minimum runtime margin every deployable
foundry/srccontract must keep. Proposed: ≥ 1,024 B; to be confirmed. Also check initcode against EIP-3860's 49,152 B, currently far from binding. - CI gate: a step after
forge buildthat reads everyfoundry/out/<src contract>artifact directly (not the--sizestable, because of the omission above), and fails if any runtime size exceeds24,576 − budget. The log should print the full table so reviewers can see each contract's margin in every PR. - Bring
DINTaskCoordinatorback under budget. The immediate blocker for PR No. 197. Candidates, roughly cheapest first:- fold the near-duplicate T1/T2
commit…Aggregation/reveal…Aggregation/start…AggregationRevealbodies (PR No. 197,DINTaskCoordinator.solL807–1041 atb3ff1b9) into tier-parameterised internal functions, with external signatures unchanged; - the same for the other T1/T2 pairs (
finalize…, theslashAggregatorsT1/T2 branches); - collapse per-tier custom errors into tier-agnostic ones where the tier is already implied by the call;
- move large pure/view logic (shuffles, batch construction) into an external library;
- as a last resort, lower
optimizer_runsfor this contract only (via a compilation restriction), trading gas for size.
- fold the near-duplicate T1/T2
- Give
DINTaskAuditorthe same review before the next feature lands on it. It has the same shape of per-phase duplication. - Remove or document the
--code-size-limitoverride inanvil.sh, so local deploys fail the way a real chain would. At minimum, add a comment saying why it's there.
Acceptance
- CI fails when any
foundry/srccontract's runtime size is over24,576 − budgetB, and it coversDINTaskAuditor. DINTaskCoordinator(with PR No. 197) andDINTaskAuditorboth meet the budget.- The chosen budget is recorded in
Developer/CONTRIBUTING.md(or the Foundry README).
Part B: committed-but-unrevealed slash reason (all commit-reveal flows)
Current behaviour
| Flow | Commit-but-no-reveal is treated as | Slash | Revealed-but-wrong is treated as | Slash |
|---|---|---|---|---|
Auditor scoring (DINTaskAuditor, PR No. 63) |
AUD_NO_VOTE (S1 liveness) |
s1SlashFractionBps (default 3000 = 30% of minStake) |
AUD_SCORE_DEVIATION (S3) |
full minStake |
T1/T2 aggregation (DINTaskCoordinator, PR No. 197) |
AGG_T1_NO_SUBMISSION / AGG_T2_NO_SUBMISSION (S2 liveness) |
s2SlashFractionBps (default 3000 = 30%) |
AGG_T1_BAD_CONSENSUS / AGG_T2_BAD_CONSENSUS |
full minStake |
In both flows, "committed and then withheld the reveal" can't be told apart from "never showed up".
The problem
Reveals land one at a time within the reveal window. A validator who has committed can watch peers' reveals, see that their own answer will end up in the minority, and choose not to reveal. They then pay the 30% liveness slash instead of the full-minStake slash for a wrong answer. Before commit-reveal, a wrong submission was irrevocable. So commit-reveal closes the copy-the-leader attack (No. 156 M-1) but opens a 70% discount on being wrong. The same holds on the auditor side, where S3 deviation is currently disabled by default (s3SlashingEnabled = false) but is intended to be turned on.
Options (mechanism-owner call)
- Distinct reason codes (
AGG_T*_NO_REVEAL,AUD_NO_REVEAL) with their own fraction, set between the liveness fraction and fullminStake, or equal to the wrong-answer slash. - Treat committed-but-unrevealed as the wrong-answer case (full
minStake). Simplest, but harsh on honest aggregators who miss the window through a genuine outage or a client-side bug (compare the retry/salt-overwrite bug, finding No. 1 on PR No. 197). - Keep as-is and document it as an accepted trust assumption, calibrated through the No. 155 S1/S2 fraction decision.
Whichever is chosen, it should be applied uniformly to both flows, and to any future commit-reveal flow (e.g. No. 178's multi-party commit-reveal seed, if adopted).
Related
No. 155 (S1/S2 fractions), No. 38 (slashing taxonomy and penalty tiers), No. 156 (M-1 aggregation commit-reveal), No. 192 (auditor commit hash sender binding), No. 193 (S5 recidivism). This should also get a row in the adversarial threat model (Developer/design/adversarial-threat-model.md).
cc @abrahamnash for Part B.
Activity
umeradl commentedon Sep 30, 2026
Decision (2026-09-30): PR No. 197 merges with the overflow; Part A is now a hard blocker for any deploy from
develop.PR No. 197 is being merged into
developwithDINTaskCoordinatorat 24,585 B runtime, 9 B over EIP-170, rather than holding the PR for the size fix. Consequences until Part A lands:developto Optimism Sepolia (or any real chain), including DevNet 3.0.DINTaskCoordinatoris deployed per model by each model owner, and the deploy will revert.foundry/anvil.shlifts the code-size limit), and neither will CI orforge test. A green local run is not evidence that the contract is deployable.DINTaskCoordinatorbefore Part A lands make the gap bigger. Reviewers should postforge build --sizesfor it until the CI gate exists.Part A's acceptance criteria are unchanged: the contract must get back under the limit with the agreed margin (proposed ≥ 1,024 B), not just by 9 B.
docs(tasks-plan): apply PR InfiniteZeroFoundation#209 review amendmen…
docs(tasks-plan): record reviewer decisions 1-4 in task plan 021026-1
docs(tasks-plan): add umermjd11 task plan 021026-1 (#201 A, #206, #192,
docs(tasks): add task_021026_19 — #201 A size gate, #206, #192, #202, #…
fix(task-coordinator): bring DINTaskCoordinator back under EIP-170 an…
umeradl commentedon Oct 3, 2026
Status update: not closable yet
Checked on
origin/develop@4ec42d4. Part A landed with PR No. 211, merged intodevelopas84d0eef(size work inc96a063).developcan deploy task contracts to a real chain again, so the hard-blocker decision above no longer applies. Part B and theDINTaskAuditorreview (Part A, proposal item 4) are still open..github/scripts/contract_size_gate.py:30-31(EIP3860 = 49_152,FAIL_MARGIN = 1_024); also warns below 2,048 BDINTaskAuditor.github/workflows/ci.yml:69runs the gate afterforge build. The gate's table in CI run for7785acflists both task contractsDINTaskCoordinatorunder budgetDINTaskAuditormeets the budgetDINTaskAuditorgets "the same review" (per-phase duplication)DINTaskCoordinatoronly, and PR No. 212 has since added bytes to the auditoranvil.sh--code-size-limitoverride documentedfoundry/anvil.sh:9-12comment points at the CI gateCONTRIBUTING.mdDeveloper/CONTRIBUTING.md:50("Contract size budget")Remaining
*_NO_REVEALcodes with their own fraction, treat as wrong-answer, or keep and document), then apply it to both commit-reveal flows. This needs the No. 155 S1/S2 fraction decision. cc @abrahamnashDINTaskAuditordedup review: the auditor is 61 B short of the 2,048 B warn line, and issues No. 205 (test-data dispute rework, task_021026_19 Part E) and the S3/scoring work will add to it. The review should happen before No. 205 lands, and it isn't tracked anywhere else yet.docs(tasks-plan): narrow 051026-1 to contract follow-ups (InfiniteZer…
docs(tasks-plan): umermjd11 task plan 051026-1 — DINTaskAuditor size (#…
docs(tasks): add task_061026_20 and task_061026_21 (forwarded from ta…
refactor(task-auditor): DINTaskAuditor size review (#201 Part A item 4)
merge: PR No. 235 (umermjd11/feat/task-061026-20-auditor-size-dual-ro…
umeradl commentedon Oct 8, 2026
Status update: Part A done, Part B open
Checked on
origin/develop@7eb558d. Part A is now complete. The size gate, the coordinator fix andanvil.shcame in PR No. 211 (84d0eef). The last open item, theDINTaskAuditorreview, came in PR No. 235 (e66d7bc). This supersedes the previous status update. Part B is still open, so this issue stays open.Sizes are from the size-gate table in the
developpush CI run for7eb558d, which passed..github/scripts/contract_size_gate.py:30-32(EIP3860 = 49_152,FAIL_MARGIN = 1_024,WARN_MARGIN = 2_048). PR No. 211DINTaskAuditor.github/workflows/ci.yml:69runs the gate afterforge build. Both task contracts are in the gate table of the run above. PR No. 211DINTaskCoordinatorunder budgetwarn, still below 2,048 B). PR No. 211DINTaskAuditormeets the budgetok, now out of the warn band)DINTaskAuditorgets "the same review"auditorGIWeight,dinAuditors,auditBatchesandIs_testdataCIDs_Assignedinternal(DINTaskAuditor.sol:95,:103,:227,:262). It also added the shared helpers_batchAt(:491) and_storeTestData(:1008), and made_burnAndForwardforward through_forwardToTreasury. The auditor went from 22,718 B to 21,188 B (−1,530 B) before the No. 180 guard, which added +102 Banvil.sh--code-size-limitoverride documentedfoundry/anvil.sh:9-12: the comment says the flag lifts EIP-170 locally and points at the CI gate. PR No. 211CONTRIBUTING.mdDeveloper/CONTRIBUTING.md:50("Contract size budget")NO_REVEALreason code infoundry/src. A committer who doesn't reveal is still slashed as a liveness miss (AUD_NO_VOTE/AGG_T*_NO_SUBMISSION)Remaining
Part B: blocked on No. 155 (the S1/S2 slash fractions) and No. 38 (the slashing taxonomy). Once No. 155 is decided, pick one of the three options:
*_NO_REVEALcodes with their own fraction;Then apply the choice to both commit-reveal flows, and add a row to the adversarial threat model. cc @abrahamnash
Not blocking:
DINTaskCoordinatorpasses the gate but is still in the warn band (1,079 B margin). The next feature that adds code to it should plan for that.refactor(task-auditor): DINTaskAuditor size review (InfiniteZeroFound…
abrahamnash commentedon Oct 26, 2026
Status check, 25 Oct (develop @ 55c4b52, fresh via_ir build with the repo's size gate):
DINTaskCoordinatoris now 23,507 B runtime, 1,069 B under EIP-170.DINTaskAuditorhas 3,279 B; everything else has 13 KB+.Several pre-testnet fixes add code to
DINTaskCoordinator(#222 stuck-GI recovery, #194 upheld-dispute CID fix, Part B of this issue, #181 decentralised adjudication), so the next of them will very likely trip the gate. Suggest planning the size reduction (e.g. moving dispute or aggregation logic into a library or a separate contract) before starting those, rather than discovering it mid-PR.umeradl commentedon Oct 29, 2026
@abrahamnash thanks, agreed. Re-measured today on
develop@6e73dcawith.github/scripts/contract_size_gate.py(via_ir build):DINTaskCoordinatorDINTaskAuditorSo it's slightly better than 25 Oct (+10 B, from the post-
55c4b52coordinator changes), but the same picture. Open PRs that touch the coordinator, as measured by their own CI on their own branches:Each fits on its own, but they won't all fit together, and the pre-testnet fixes you listed (No. 222, No. 194, Part B here, No. 181) will push it over. I'll plan the size reduction (moving dispute or aggregation logic into a library or a separate contract) as its own task before those land, and order PR No. 259 ahead of the others since it gives back headroom.