From d95d9467227efe303094e64911191d225358a442 Mon Sep 17 00:00:00 2001 From: umermjd11 Date: Tue, 6 Oct 2026 10:18:00 +0500 Subject: [PATCH 1/2] docs(tasks): add task_061026_20 and task_061026_21 (forwarded from task-plan-051026-1/-2); close task_021026_19 - task_061026_20: contract follow-ups (#201 A4 DINTaskAuditor getter trim + required fold review, #180 dual-role guard, #193 two-level S5). Approved in PR No. 219 (amendments 1-5, decisions 1-3). Tracking: Discussion No. 230. - task_061026_21: full-GI alignment (contracts check, three new GIstates with an every-batch test-data commitment gate, dincli commands closing No. 223, tests/dincli on foundry running a complete GI, GI docs). Approved in PR No. 229 (amendments 1-6, decisions 1-4). Tracking: Discussion No. 231. - task_021026_19: Status -> Closed, linking Discussion No. 216 (PR No. 219 review amendment 1). Co-Authored-By: Claude Opus 5.5 --- Developer/tasks/task_021026_19.md | 2 +- Developer/tasks/task_061026_20.md | 174 ++++++++++++++++ Developer/tasks/task_061026_21.md | 316 ++++++++++++++++++++++++++++++ 3 files changed, 491 insertions(+), 1 deletion(-) create mode 100644 Developer/tasks/task_061026_20.md create mode 100644 Developer/tasks/task_061026_21.md diff --git a/Developer/tasks/task_021026_19.md b/Developer/tasks/task_021026_19.md index b9f5ecdb..81b0bf3a 100644 --- a/Developer/tasks/task_021026_19.md +++ b/Developer/tasks/task_021026_19.md @@ -3,7 +3,7 @@ **ID:** task_021026_19 **Assigned to:** Umer Majeed (@umermjd11) **Created:** 2026-10-02 -**Status:** Open (assigned) +**Status:** Closed (completed 2026-10-05). All six Parts landed (PRs #211, #212, #214, #215; wiki revision on #207). Closed in [Discussion #216](https://github.com/InfiniteZeroFoundation/DevNet/discussions/216#discussioncomment-18761447) **Dates:** Oct 2 – Oct 12, 2026 (about 9 working days, per-Part estimates below). Parts A+B and C can start immediately. D and E are gated on earlier PRs merging (see §Sequencing). If those slip, say so early in the tracking discussion. **Repo:** https://github.com/InfiniteZeroFoundation/DevNet **Base branch:** `develop` — spec written against commit `84d8c38` (2026-10-02); re-pull before starting regardless of when you begin. `foundry/`, `dincli/`, `tests/` and `.github/` are unchanged from `6ccc28c`, the commit the source plan was verified against. diff --git a/Developer/tasks/task_061026_20.md b/Developer/tasks/task_061026_20.md new file mode 100644 index 00000000..810c8115 --- /dev/null +++ b/Developer/tasks/task_061026_20.md @@ -0,0 +1,174 @@ +# Task: Contract Follow-ups: `DINTaskAuditor` Size (#201 A4), Dual-Role Guard (#180), Cross-Model S5 (#193) + +**ID:** task_061026_20 +**Assigned to:** Umer Majeed (@umermjd11) +**Created:** 2026-10-06 +**Status:** Open (assigned) +**Dates:** Oct 6 – Oct 9, 2026 (about 3 working days; per-Part estimates below). Parts A and C can start right away. Part B goes with Part A (same contract and byte budget). If anything slips, say so early in the tracking discussion. +**Repo:** https://github.com/InfiniteZeroFoundation/DevNet +**Base branch:** `develop`. The spec was written against `a1fcce2` (2026-10-05). The task contracts and `DinValidatorStake` are unchanged since `740a613`, where the source plan was verified. Re-pull before starting. +**Roadmap ref:** P3-6.3a (gas/size), P3-6.3b (audit preparation, open findings), P3-4.2 (penalty tiers, S5) +**Source plan:** `Developer/tasks-plan/umermjd11/task-plan-051026-1.md`, reviewed in [PR #219](https://github.com/InfiniteZeroFoundation/DevNet/pull/219) ([verification review](https://github.com/InfiniteZeroFoundation/DevNet/pull/219#issuecomment-6001172350), [reviewer decisions](https://github.com/InfiniteZeroFoundation/DevNet/pull/219#issuecomment-6001173454), [decisions applied](https://github.com/InfiniteZeroFoundation/DevNet/pull/219#issuecomment-6009815981)) +**Companion task:** [task_061026_21](task_061026_21.md) (full-GI alignment). See [Coordination](#coordination-with-task_061026_21). +**Tracking:** +- **Part A:** [#201](https://github.com/InfiniteZeroFoundation/DevNet/issues/201) Part A, item 4 (the `DINTaskAuditor` review). #201 Part B stays open. +- **Part B:** [#180](https://github.com/InfiniteZeroFoundation/DevNet/issues/180) (closes, pending review). +- **Part C:** [#193](https://github.com/InfiniteZeroFoundation/DevNet/issues/193) (closes, pending review). +- [Discussion #230](https://github.com/InfiniteZeroFoundation/DevNet/discussions/230) (progress updates, questions, PR links) + +--- + +## Status check at `a1fcce2` + +| Item | State | +|---|---| +| #201 A4 | `DINTaskAuditor` is 22,718 B runtime (1,858 B margin, so the CI gate **warns**). It has 16 public mappings. Four of them either have no reader outside the contract or duplicate an existing view | +| #180 | `registerDINAuditor` (`DINTaskAuditor.sol:667-698`) and `registerDINaggregator` (`DINTaskCoordinator.sol:401-434`) have no cross-role check. The PR #182 review ruled dual-role **not** intended (`Developer/design/adversarial-threat-model.md`, Judgment call 2; Row 6 = KNOWN GAP). Stale NatSpec remains at `DinValidatorStake.sol:121`, `:451` and `:462` | +| #193 | The S5 ring is `_partialSlashGIs[validator][msg.sender]` (`DinValidatorStake.sol:146`; `slashPartial` at `:294-322`), so it is counted per slasher **contract**. That splits S1 (auditor contract) and S2 (coordinator) even within one model. `Developer/design/MECHANISM_DESIGN.md:81` defines S5 per validator, across both roles | + +--- + +## Sequencing + +| Part | PR | Touches | Conflicts with | Rule | +|---|---|---|---|---| +| A | PR 1, commit 1 | `DINTaskAuditor.sol` (getter visibility, folds), `dincli/abis/DINTaskAuditor.json`, `DINTaskAuditor.md` §3 | B (same contract and budget); task_061026_21 Part B (`DINTaskAuditor` bytes) | **Start right away** | +| B | PR 1, commit 2 | `DINTaskAuditor.registerDINAuditor`, `IDINTaskCoordinator` + new error (`DINShared.sol`), `DinValidatorStake.sol` NatSpec, tests, threat model Row 6 | A; task_061026_21 Part B (`DINShared.sol` enum) | Same PR as A, so the gate proves both fit | +| C | PR 2 | `DinValidatorStake.sol` (S5 storage + `slashPartial`), S5 tests, deploy-script S5 keys, `DinValidatorStake.md`, `MECHANISM_DESIGN.md`, threat model Row 11 | — | **In parallel with PR 1**, since it's a different contract | + +**PR #218** (`P3Adversarial.t.sol`, #154 Part 2) encodes Row 6 and Row 11 as `test_knownGap_dualRoleRegistration` / `test_knownGap_perSlasherS5Evasion`. If it merges first, PR 1 and PR 2 each flip their row's test to `test_defended_…`. Otherwise PR #218 rebases and flips them. No test may be left asserting a closed gap. Row 11's test calls `slashPartial` directly as each task contract, which makes it a good regression check for Part C. + +Rebase each PR on `develop` after the previous one merges; no stacked branches. + +--- + +# Part A — #201 Part A item 4: `DINTaskAuditor` size review — PR 1, commit 1 + +Shrink the contract in place, with no library, split or deploy change. Only **getter visibility** changes: no state-changing function, event or storage slot changes. Prototyped in the plan and re-measured in the PR #219 review (`via_ir`, 200 runs): + +| Getter → `internal` | Readers outside the contract | Saving | +|---|---|---| +| `auditBatches` | none (only a comment, `RewardEngine.t.sol:895`). `getAuditorsBatch` already returns the batch | −100 B | +| `dinAuditors` | none. `getDINtaskAuditors` already returns the list | −83 B | +| `Is_testdataCIDs_Assigned` | none. It is written at `:1028` and read only by its own guard at `:1026` | −58 B | +| `auditorGIWeight` | none | −79 B | +| **The four together** (Decision 1) | | **−320 B → 22,398 B** (2,178 B margin) | + +**Keep public:** `rewardClaimed`, `testDataDisputes` and `giRewardSnapshot`. task_061026_21's claim and dispute commands read them. + +**Scope:** +- Make the four getters `internal`. No test reads them, so no test changes. +- **Fold review: required.** #201 item 4 asks for "the same review" of per-phase duplication that the coordinator got. Measure folds of the near-duplicate dispute and reassignment paths. Commit a fold only if it shrinks the contract: in task_021026_19, `via_ir` made the coordinator's commit/reveal/finalize folds **grow** it (+177 B / +166 B). Report every measurement in the PR, including the ones not taken. +- Regenerate `dincli/abis/DINTaskAuditor.json` (`dincli system dump-abi --artifact foundry/out/DINTaskAuditor.sol/DINTaskAuditor.json --output dincli/abis --official`) and update the `DINTaskAuditor.md` §3 tables. +- Check PR #29's subgraph for reads of the four getters, and post an ABI note there. Don't push to that branch. + +**`DINTaskAuditor` budget across both tasks** (Decision 1). Measured on `a1fcce2`: + +| Step | Runtime | Margin | Band | +|---|---|---|---| +| `develop` | 22,718 B | 1,858 B | warn | +| + Part A | 22,398 B | 2,178 B | ok | +| + Part B (+102 B) | 22,500 B | 2,076 B | ok (28 B above the warn line) | +| + task_061026_21 Part B's every-batch commitment check (+75 B) | 22,575 B | 2,001 B | **warn** (still far above the 1,024 B fail line) | + +There are two ways back out of the warn band: a fold that actually saves bytes, and removing `Is_testdataCIDs_Assigned` once task_061026_21's `AuditTestDataAssigned` coordinator state guards the double-set. Whichever of the two tasks lands second reports the combined size. + +## Deliverables (Part A) + +- [ ] The four getters are `internal`, with no change to state-changing functions, events or storage layout +- [ ] A size table from **one** build of the implementation, plus every fold measured (kept or not) +- [ ] Bundled ABI regenerated, `DINTaskAuditor.md` §3 updated, ABI note posted on PR #29 +- [ ] `cd foundry && npm ci && forge build && python ../.github/scripts/contract_size_gate.py && forge test` is green, including `UpgradeValidation.t.sol`. `pytest -m "not integration"` is green + +**Estimate:** 1 day. + +--- + +# Part B — #180: one address can't hold both roles in a GI — PR 1, commit 2 + +**Decision 2: a per-address guard in `registerDINAuditor`.** A second address with its own stake gets around it (Sybil), but the attack then costs a second stake and is visible on-chain. + +- **Where.** Aggregator registration (states 6–7) always comes before auditor registration (8–9) (`DINShared.sol:17-20`), so the auditor side is the only place the guard can fire: + ```solidity + if (dintaskcoordinatorContract.isDINAggregator(_GI, msg.sender)) revert TA_DualRoleNotAllowed(); + ``` + Add `isDINAggregator(uint256,address) returns (bool)` to `IDINTaskCoordinator` (`DINShared.sol:110-121`). The coordinator's public mapping `isDINAggregator` (`DINTaskCoordinator.sol:34`) already provides it. Add `TA_DualRoleNotAllowed` to `DINShared.sol`. +- **Cost:** +102 B on `DINTaskAuditor`, measured. The coordinator doesn't change. +- **NatSpec:** + - `DinValidatorStake.sol:451` and `:462` say "(not yet enforced)". Both are enforced now, in the two registration functions. + - `:121` says "decremented at endGI time". The decrement now happens in `releaseGIRegistrationSlots`. +- **Tests** (next to the `StakingEnforcement.t.sol` registration tests): + - an aggregator registering as an auditor in the same GI reverts with `TA_DualRoleNotAllowed` + - the same address registering as an auditor in a different GI succeeds + - a different address with its own stake succeeds, which documents the Sybil limit +- **Docs:** + - threat model Row 6 changes from KNOWN GAP to DEFENDED (with the Sybil note), and its stale line refs are refreshed (`:386` → `:401`, `:660` → `:667`) + - in `DINTaskAuditor.md`, update the registration checks and the §13 caveat + - add a `DINShared.md` error row + +## Deliverables (Part B) + +- [ ] Guard, interface entry and error added, with the three tests +- [ ] NatSpec fixed at `DinValidatorStake.sol:121`, `:451`, `:462` +- [ ] Threat model Row 6 updated (and PR #218's Row 6 test flipped if it has merged) +- [ ] The gate is green, and the PR shows the A + B size + +**Estimate:** 0.5 day. + +--- + +# Part C — #193: S5 escalation across models — PR 2 + +**Decision 3: a two-level check.** + +- **The per-slasher GI ring stays as it is,** with the same per-model escalation and the same tests. +- **Add a per-validator ring of `block.timestamp` values**, `_partialSlashTimes[validator]`, with `s5GlobalWindow` (seconds) and `s5GlobalThreshold`. + - Timestamps only increase, across every slasher, so the ascending-order trim that forced per-contract keying (`DinValidatorStake.sol:136-146`) stays safe. + - `slashPartial` escalates (full `MIN_STAKE` slash + jail) when **either** level reaches its threshold, and then clears both rings. +- This also closes the same-model split: one validator's S1 and S2 misses now add up. + +**Scope:** +- **Storage.** Append the new variables before `__gap` (`:174`, 50 slots) and shrink the gap by the slots used. `DinValidatorStakeV2` inherits them. `UpgradeValidation.t.sol` and the `DeployPlatform.t.sol` upgrade tests must stay green. +- **Setter.** `setS5GlobalParams(window, threshold)`, validated like `setS5RecidivismParams` (`:583-594`). +- **Defaults.** `s5GlobalWindow = 7 days` and `s5GlobalThreshold = 6` (2 × `s5RecidivismThreshold`). These are placeholders until #155. + - Set them in `initialize`. + - On an upgraded proxy, **0 means off**; no `reinitializer`. Nothing on `develop` is deployed, and DevNet 2.0 is a fresh `DeployPlatform.s.sol` run. + - Add optional deploy-script env keys `S5_GLOBAL_WINDOW` / `S5_GLOBAL_THRESHOLD`, matching the existing `S5_*` keys. Add them to `DeployPlatform.md` and its env-override tests. +- **Event.** `ValidatorEscalatedS5` gets a level flag, or a sibling event is added, so indexers can tell which level fired. +- **Tests:** + - two task contracts each slash one validator (threshold − 1) times within the window, and the global level escalates + - when the window expires, the global count resets + - the existing S5 tests (`SlashingInvariants.t.sol:488`, `:518`, `:540`) and `test_crossModelGICollision_slashPartialDoesNotUnderflow` (`PR146SlashingRegression.t.sol:321`) stay green + - the default and override deploy tests cover the new keys +- **Docs:** + - `DinValidatorStake.md` + - the `Developer/design/MECHANISM_DESIGN.md` S5 row + - threat model Row 11 (KNOWN GAP → DEFENDED) + - record, but don't change, the separate discrepancy: `MECHANISM_DESIGN.md:87` says S5 is "entire slashable stake + blacklist", while the code does a `MIN_STAKE` slash + a `s5JailDuration` jail (7 days) + +## Deliverables (Part C) + +- [ ] Two-level S5 with setter, defaults, "0 means off", event and deploy-script keys +- [ ] The new tests, with the existing S5 and upgrade-validation tests green +- [ ] Docs updated (and PR #218's Row 11 test flipped if it has merged) + +**Estimate:** 1.5 days. + +--- + +## Coordination with task_061026_21 + +- **`DINShared.sol`.** Part B adds `isDINAggregator` to `IDINTaskCoordinator`. task_061026_21 Part B edits the `GIstates` enum. The sections differ, and whichever PR merges second rebases. +- **`dincli/abis/DINTaskAuditor.json`.** Both tasks regenerate it. The second to merge regenerates on top. +- **The `DINTaskAuditor` budget** is tracked in Part A's table. Whichever task lands second reports the combined size. +- **The #180 guard and the integration suite.** The suite uses separate accounts for each role (aggregators 11–22, auditors 50–58), so it isn't affected. task_061026_21 adds a negative check once Part B lands. +- **#193** doesn't affect a single-model GI. + +--- + +## Out of scope + +- **#201 Part B** (slash reason for committed-but-unrevealed): a mechanism decision tied to #155 / #38. +- **#194, #78, #181, #178:** each needs a design note or a decision first, or is mainnet-grade. +- **dincli, the integration suite and the GI docs:** [task_061026_21](task_061026_21.md). +- **Don't split `DINTaskAuditor`** to win bytes. If the budget can't be met with the levers above, stop and raise it in the tracking discussion. diff --git a/Developer/tasks/task_061026_21.md b/Developer/tasks/task_061026_21.md new file mode 100644 index 00000000..0bd4ae16 --- /dev/null +++ b/Developer/tasks/task_061026_21.md @@ -0,0 +1,316 @@ +# Task: Full-GI Alignment: Contracts Check + Richer GI States, dincli Commands, Integration Suite on Foundry, GI Docs + +**ID:** task_061026_21 +**Assigned to:** Umer Majeed (@umermjd11) +**Created:** 2026-10-06 +**Status:** Open (assigned) +**Dates:** Oct 6 – Oct 17, 2026 (about 8.5 working days; per-Part estimates below). The Parts run in order: A → B → C → D → E. If anything slips, say so early in the tracking discussion. +**Repo:** https://github.com/InfiniteZeroFoundation/DevNet +**Base branch:** `develop`. The spec was written against `a1fcce2` (2026-10-05). Re-pull before starting. +**Roadmap ref:** P3 onboarding (dincli), P3-6.3b (audit preparation), DevNet 2.0 launch readiness +**Source plan:** `Developer/tasks-plan/umermjd11/task-plan-051026-2.md`, reviewed in [PR #229](https://github.com/InfiniteZeroFoundation/DevNet/pull/229) ([verification review](https://github.com/InfiniteZeroFoundation/DevNet/pull/229#issuecomment-6000550646), [reviewer decisions](https://github.com/InfiniteZeroFoundation/DevNet/pull/229#issuecomment-6000552418), [decisions applied](https://github.com/InfiniteZeroFoundation/DevNet/pull/229#issuecomment-6009816222)) +**Companion task:** [task_061026_20](task_061026_20.md) (contract follow-ups #201 A4, #180, #193). See [Coordination](#coordination-with-task_061026_20). +**Tracking:** +- **Part C:** [#223](https://github.com/InfiniteZeroFoundation/DevNet/issues/223) (closes, pending review): BL-27 deploy constructors and BL-28 release slots. +- **Parts C and E:** the [Discussion #216](https://github.com/InfiniteZeroFoundation/DevNet/discussions/216#discussioncomment-18761447) follow-ups left by task_021026_19 (mapped [below](#discussion-216-follow-ups)). +- **Follow-up, not in this task:** [#228](https://github.com/InfiniteZeroFoundation/DevNet/issues/228), running the integration suite in its own CI job once Part D passes. +- [Discussion #231](https://github.com/InfiniteZeroFoundation/DevNet/discussions/231) (progress updates, questions, PR links) + +--- + +## Why + +The task contracts on `develop` now have: +- commit-then-reveal in all three scoring and aggregation phases +- future-block batch seeds +- encrypted test data +- per-GI reward pools with pull claims +- disputes +- the `modelId` constructor argument + +dincli and the full-GI integration suite never caught up: + +- **The integration suite (`tests/dincli/`) can't pass with either toolchain.** + - **Phase 1 assertion.** It asserts a `proxyAdmin` key (`test_01_platform.py:135-137`, `:164`). `DeployPlatform.s.sol` writes seven per-contract `proxyAdmin*` keys instead. + - **Old task contracts.** It deploys the **hardhat** task contracts (`constants.py:50`, `ARTIFACT_BASE = hardhat/artifacts/contracts`). Those predate foundry: no commit-reveal, rewards, seed lock or encrypted test data, and a 23-member `GIstates`, while dincli mirrors foundry's 26. + - **ABI overwrite.** `dump-abi --official` (`test_01_platform.py:167-197`, `test_02_task_contracts.py:74-107`) overwrites the tracked foundry ABIs in `dincli/abis/`. + - **Missing steps.** `test_04_gi.py` never funds the pool, registers auditor keys or runs any reveal phase. Its final check (`:478`) passes on the name but keeps a stale `or "23"` fallback; `GIended` is 25. +- **dincli can't drive a full GI.** + - `model-owner deploy` sends the old constructors (`deploy.py:35`, `:77`) and never calls `setDinToken`. + - These have no command: + - `depositRewards` / `DinEmission.fundGI`, so `gi start` reverts with `TC_GIRewardPoolNotFunded` + - `registerEncryptionKey`, so `create-testdataset --submit` fails. The error message at `auditor.py:39` names a `dincli auditor register-encryption-key` that doesn't exist + - `releaseGIRegistrationSlots`, claims, and both dispute families +- **The GI state machine hides progress.** Three steps change no state: + - audit seed waiting vs locked + - batches created vs test data assigned + - aggregation seed waiting vs locked + + Worse, `startLMsubmissionsEvaluation` (`DINTaskCoordinator.sol:532-538`) **doesn't check** that test data was assigned. The auditor-side flag (`DINTaskAuditor.sol:1017-1029`) is one-way, but it's only the owner's own claim; nothing checks that every batch actually has test data. +- **The public GI docs are stale**: wrong command names, and the funding, key, seed and reveal steps are missing. + +### Discussion #216 follow-ups + +| Follow-up | Part | +|---|---| +| `model-owner deploy` still uses the old constructors (no `modelId`) | C (closes #223 with BL-28) | +| No dincli commands for depositing/claiming rewards, `registerEncryptionKey` or disputes | C | +| `din-workflow.md` still lists 4 contracts and `withdraw` | E | +| Old command names in `roles/clients.md`, `roles/auditors.md`, `roles/model-owner.md`, `model-workflow.md` | E | +| `setup.md`'s broken `@main#subdirectory=dist` install line | E | +| `ROADMAP.md:19` deploy-blocker sentence (wrong since PR #211) | E | + +--- + +## Sequencing + +| Part | PR | Touches | Conflicts with | Rule | +|---|---|---|---|---| +| A | with B | Read-only audit, recorded in this spec. Two text fixes: `DINShared.sol:30-34`, and the `utils.py` state-24 text | — | First | +| B | PR 1 | `DINShared.sol` enum + new error, `DINTaskCoordinator.sol` (3 transitions + gates), `DINTaskAuditor.setTestDataAssignedFlag` (commitment check), foundry tests, `dincli/cli/utils.py` mirrors and every dincli state gate, `dincli/abis/`, `DINShared.md`, `DINTaskCoordinator.md`, `DINTaskAuditor.md` | task_061026_20 PR 1 (`DINShared.sol` interface; `DINTaskAuditor` bytes and ABI); PR #29 (subgraph enum); PR #218 (lifecycle test ordinals) | After A. **Before** C/D, so commands and the suite are built on the final state machine | +| C | PR 2 | `dincli/cli/modelownerd/deploy.py`, new commands, `dincli/abis/DinEmission.json`, `cli/context.py` helper, `dinrep` approval check, unit tests | — | After B | +| D | PR 3 | `tests/dincli/**`, `tests/dincli/NOTES.md`, `dincli-testing-guide.md` | — | After C | +| E | PR 4 | `Documentation/public/**`, `CLAUDE.md`, `DINShared.md` §2.2 diagram, `ROADMAP.md:19` | — | Last | + +Rebase each PR on `develop` after the previous one merges; no stacked branches. + +--- + +# Part A — Contracts check: what a complete GI needs — with PR 1 + +This is a read-only pass over every owner and role GI function in `DINTaskCoordinator`, `DINTaskAuditor`, `DinValidatorStake` and `DinEmission`, checked against `DINTaskCoordinator.md` §6 and the `GIstates` enum. The result below is the reference for Parts B–E. Update it in PR 1 if anything has moved. + +**Preconditions for a complete GI:** + +| Precondition | Where | Without it | +|---|---|---| +| `modelId` constructor argument on both task contracts | `DINTaskCoordinator.sol:290`, `DINTaskAuditor.sol:406` | Deploy fails at ABI encoding (BL-27) | +| `setDinToken` on the auditor (and the coordinator, for dispute bonds) | `DINTaskAuditor.sol:440`, `DINTaskCoordinator.sol:1307` | `depositRewards`, claims and bonds can't move DIN | +| The GI's reward pool funded before each `startGI` | `DINTaskCoordinator.sol:379` → `DINTaskAuditor.depositRewards` (`:481`) or `DinEmission.fundGI` (`DinEmission.sol:174`) | `TC_GIRewardPoolNotFunded` | +| Every batch auditor has an X25519 key on `DinValidatorStake` | `registerEncryptionKey` (`DinValidatorStake.sol:501`), checked at `DINTaskAuditor.sol:1000-1001` | `TA_AuditorEncryptionKeyNotRegistered` when test data is assigned | +| Seed blocks get mined | `disputeSeedDelay` = 7 blocks; dincli polls (`utils.py:998-1080`); anvil `--block-time 2` mines | The seed lock hangs | +| The owner opens each of the three reveal windows | `start*Reveal` | `close` / `finalize` revert | + +**dincli coverage at `a1fcce2`:** + +| GI step | Contract function | dincli command | +|---|---|---| +| Deploy + wire | task-contract constructors; `setDINTaskAuditorContract` | `model-owner deploy task-coordinator / task-auditor` (**old constructors**) | +| Slashers | `DinCoordinator.addSlasherContract`; task-side slasher flags | `dinrep add-slasher`; `model-owner add-slasher` | +| Genesis, registry | `setGenesisModelIpfsHash`; `requestModelRegistration` / `approveModel` | `model-owner model submit-genesis-model`; `task model-owner register-request`; `dinrep registry approve-*` | +| Wire DIN token | `setDinToken` (both) | **missing** | +| Fund pool | `depositRewards` / `DinEmission.fundGI` | **missing** | +| Start, registration | `startGI`; registration windows; `registerDINaggregator` / `registerDINAuditor` | `gi start`; `gi reg …`; `aggregator register`; `auditor register` | +| Encryption key | `DinValidatorStake.registerEncryptionKey` | **missing** | +| LMS | `start/closeLMsubmissions`; `submitLocalModel` | `lms open/close`; `client train-lms` + `submit-lm` | +| Seeds | `lockAuditSeed` / `lockAggSeed` | `auditor lock-seed` / `aggregator lock-seed`, and automatic in batch creation | +| Audit batches, test data | `createAuditorsBatches`; `assignAuditTestDataset` + `setTestDataAssignedFlag` | `auditor-batches create`; `auditor-batches create-testdataset --submit` | +| Score commit/reveal/close | `startLMsubmissionsEvaluation`, `commitAuditScore`, `startLMsubmissionsEvaluationReveal`, `revealAuditScore`, `closeLMsubmissionsEvaluation` | `lms-evaluation start / start-reveal / close`; `auditor lms-evaluation evaluate --submit / reveal` | +| T1/T2 | `autoCreateTier1AndTier2`; `start/commit/startReveal/reveal/finalize` T1 and T2; `setTier2Score` | `aggregation create-t1nt2-batches`, `T1/T2 start / start-reveal / close`, `T2 set-score`; `aggregator aggregate-t1/t2 --submit`, `reveal-t1/t2` | +| Slash, end | `slashAuditors`, `slashAggregators`, `endGI` | `slash auditors / aggregators`; `gi end` | +| Release slots | `releaseGIRegistrationSlots` | **missing** (BL-28) | +| Claim | `claimReward(gi)` / `claimRewards()` | **missing** | +| Disputes | coordinator `openDispute` … `claimDisputeBond`; auditor `openTestDataDispute` … `reassignAuditTestDataset` | **missing** | +| Owner parameter setters | `setDisputeParams`, `setS1/S2/S3*`, `setRewardSplit`, `setNetworkFeeFloor`, … | missing (out of scope) | + +**Text fixes (land in PR 1):** +- `DINShared.sol:30-34` says the table has "24 members". There are 26 today, and more after Part B. +- The `dincli/cli/utils.py` `stateDescription` entry for state 24 says "Validators slashed"; it should say aggregators slashed. + +If the check turns up any other blocker to a complete GI, fix it in Part B, or raise it on its own issue if it needs a decision. Don't work around it in dincli. + +## Deliverables (Part A) + +- [ ] Preconditions and coverage tables re-checked at the PR's base and updated here if needed +- [ ] Both text fixes in PR 1 + +**Estimate:** 0.5 day. + +--- + +# Part B — Richer GI states — PR 1 + +Each new state is **set by the function that already does the step**, so a GI needs no extra owner transactions, and `dincli task gi show-state` (and the subgraph, and dashboards) can say exactly where a GI is. **Decision 1, option B:** add all three. If the coordinator budget runs short, keep them in this priority: **`AuditTestDataAssigned` first** (it closes a real gap), then `AuditSeedLocked`, then `AggSeedLocked`. + +| New state (lifecycle / enum order) | Inserted | Set by | Gate change | +|---|---|---|---| +| `AuditSeedLocked` | between `LMSclosed` and `AuditorsBatchesCreated` | `lockAuditSeed` (`DINTaskCoordinator.sol:1483`, anyone). Only on a successful lock, never on a re-anchor | `createAuditorsBatches` requires `AuditSeedLocked` | +| `AuditTestDataAssigned` | between `AuditorsBatchesCreated` and `LMSevaluationStarted` | `setTestDataAssignedFlag` (`:519`) | `startLMsubmissionsEvaluation` requires it. **The auditor side (`DINTaskAuditor.sol:1017-1029`) checks that every batch of the GI has a stored commitment** (`testDataCommitments[gi][b] != 0`, written by `assignAuditTestDataset`), else it reverts with a new `TA_TestDataNotAssigned`. The flag is already one-way (`TA_FlagMustBeTrue`, `TA_FlagAlreadySet`) | +| `AggSeedLocked` | between `LMSevaluationClosed` and `T1nT2Bcreated` | `lockAggSeed` (`:1459`) | `autoCreateTier1AndTier2` requires `AggSeedLocked` | + +**Not added**, and why: +- **A "reward pool funded" state.** Funding lives on the auditor contract, anyone can fund, and it targets the *next* GI. dincli reads `giRewardPool(gi)` instead. +- **A "test-data dispute pending" state.** Disputes are per batch and can overlap evaluation. +- **A "rewards settled" state.** `endGI` settles the pool, so `GIended` already means that. + +**Constraints:** +- **Insert at the lifecycle position, not at the end**, as PR #63 and #197 did. Every later ordinal shifts; with all three, `GIended` goes from 25 to 28. +- **In the same PR**, update everything that encodes ordinals or names: + - the `dincli/cli/utils.py` `states` / `stateDescription` mirrors + - every dincli state gate (grep for `GIstateToStr` and name comparisons) + - `DINShared.md` §2.1 / §2.2 + - `DINTaskCoordinator.md` §6 + - foundry tests that assert ordinals or names + - the bundled ABIs (`dump-abi --official`) +- **Post the new ordinal table on PR #29** (the subgraph regenerates its `GIstates` mapping). Don't push to that branch. If PR #218 has merged, update any ordinals its lifecycle test asserts. +- **Size:** + - **Coordinator:** `DINTaskCoordinator` has a 1,079 B margin. Measure each state alone and all three together. Anything that doesn't fit with the gate green follows the priority order above and becomes a view; say so in the PR. + - **Auditor:** the commitment check costs `DINTaskAuditor` **+75 B** (measured). The combined auditor budget, and the way back out of the warn band, is in [task_061026_20 Part A](task_061026_20.md#part-a--201-part-a-item-4-dintaskauditor-size-review--pr-1-commit-1). Once `AuditTestDataAssigned` guards the double-set, `Is_testdataCIDs_Assigned` can be removed. +- **`lockAuditSeed` / `lockAggSeed` stay permissionless.** The state change happens after the seed is stored. + +**Tests:** +- each transition happens +- `createAuditorsBatches` / `autoCreateTier1AndTier2` revert before the lock +- a re-anchor leaves the state unchanged +- `startLMsubmissionsEvaluation` reverts until test data is assigned (regression test for the gap) +- with one batch unassigned, `setTestDataAssignedFlag` reverts with `TA_TestDataNotAssigned`, and evaluation can't start +- the full lifecycle test walks every ordinal + +## Deliverables (Part B) + +- [ ] Three states (or the subset that fits, by priority), the commitment check and the gates, with the tests above +- [ ] dincli mirrors and gates, docs, ABIs and foundry tests updated in the same PR. Ordinal table posted on PR #29 +- [ ] Coordinator and auditor sizes in the PR (combined with task_061026_20 if that landed first). Gate green, `forge test` and `pytest -m "not integration"` green + +**Estimate:** 1.5 days. + +--- + +# Part C — dincli commands for a complete GI — PR 2 + +**Closes #223** (BL-27 + BL-28). + +**Deploy (BL-27).** +- `model-owner deploy task-coordinator` / `task-auditor` get `--model-id`, defaulting to `DINModelRegistry.totalModels()`. That's the ID the next approval assigns (`DINModelRegistry.sol:237`, 0-based). Warn that the guess only holds if no other request is approved first. +- The auditor deploy reads `modelId()` from the coordinator and refuses a mismatch. +- Both deploys call `setDinToken`. +- Fix the latent `NameError` when the `stake` entry is missing (`deploy.py:27-28`, `:61-62`). +- **`modelId` check at approval (Decision 2: dincli-side).** `dinrep registry approve-registration-request` compares the requested contracts' `modelId()` with `totalModels()` and refuses on a mismatch unless `--force` is passed. A contract-side check in `DINModelRegistry.approveModel` is a mainnet-registry follow-up, in the same area as BL-34 / #224. + +**New commands:** + +| Command | Calls | Notes | +|---|---|---| +| `dincli model-owner rewards deposit --gi N --amount ` | approve + `depositRewards` | Anyone can fund | +| `dincli model-owner rewards fund-emission --gi N` | `DinEmission.fundGI` | Adds `dincli/abis/DinEmission.json` and `get_deployed_din_emission_contract` (`din_info` already has `emission`) | +| `dincli rewards claim --gi N` / `dincli rewards withdraw ` | `claimReward(gi)` / `claimRewards()` | All roles. First checks `giRewardSnapshot(gi).settled` and `rewardClaimed` | +| `dincli auditor register-encryption-key` | `DinValidatorStake.registerEncryptionKey` | Generates the X25519 key **per wallet** (e.g. `auditor_x25519_
.key`, chmod 600), replacing today's single shared `auditor_x25519.key`, which breaks several `--demokey` auditors on one machine. Updates `_load_auditor_x25519_key` (`auditor.py:33-41`) to match. The owner key (`auditor_batches.py:170-177`) also gets chmod 600 | +| `dincli model-owner gi release-slots --gi N` | `releaseGIRegistrationSlots` | BL-28 | +| `dincli auditor dispute-test-data`, `dincli model-owner disputes resolve-test-data / reassign-test-data`, `… disputes close-expired` | `openTestDataDispute` (`DINTaskAuditor.sol:1480`), `resolveTestDataDispute` (`:1524`), `closeExpiredDispute` (`:1557`), `reassignAuditTestDataset` (`:1601`) | **Decision 4: in this task.** Built against the PR #215 shape: only batch auditors open a dispute, only the owner resolves, an unanswered dispute is upheld on expiry, there's no penalty after settlement, and `TA_RewardsAlreadySettled` applies. Bond approval comes first | +| `dincli aggregator dispute`, `dincli model-owner disputes resolve-aggregation / settle-recomputation`, `… expire`, `… claim-bond` | `openDispute` (`DINTaskCoordinator.sol:1368`), `resolveDispute` (`:1535`), `settleRecomputation` (`:1609`), `expireDispute` (`:1671`), `claimDisputeBond` (`:1575`) | S4 | + +**Fail fast instead of reverting:** +- `gi start` checks `giRewardPool(next GI) > 0` and points to `rewards deposit`. +- `create-testdataset --submit` checks every batch auditor's key and names any that are missing. + +**Reuse:** +- `build_and_send_tx` (`dincli/cli/utils.py:947`) +- the `ctx.obj.get_deployed_din_task_*_contract(model_id)` lookups (`cli/context.py:339`, `:357`) +- a new `approve_din(ctx, spender, amount)` helper, taken from the inline approve in `dintoken.stake_dintokens` (`dincli/cli/dintoken.py:71-128`) + +**Tests:** one pytest per command group, in the `tests/test_dinrep_add_slasher.py` style (`SimpleNamespace` context, monkeypatched `build_and_send_tx`). They cover: +- call arguments +- approve before act +- the fail-fast checks +- the `modelId` mismatch refusal + +## Deliverables (Part C) + +- [ ] Deploy with `--model-id` + `setDinToken`, `NameError` fixed, approval-time `modelId` check +- [ ] Rewards, encryption-key, release-slots and both dispute command families, plus the fail-fast checks +- [ ] Unit tests. `pytest -m "not integration"` green +- [ ] BL-27 / BL-28 status in `Developer/BACK_LOG.md`, and the "dincli lags" caveats removed (`DINTaskCoordinator.md` §10 No. 10, `DINTaskAuditor.md` §13 No. 8) + +**Estimate:** 3 days. + +--- + +# Part D — The integration suite runs a complete GI on the foundry contracts — PR 3 + +**Toolchain:** +- Point `ARTIFACT_BASE` at `foundry/out`. It's the same `X.sol/X.json` layout, and `get_contract_instance` already reads `bytecode.object` (`contract_utils.py:150-152`). +- Run `npx hardhat compile` only when `PLATFORM_DEPLOY_TOOLCHAIN=hardhat`. Hardhat task contracts leave the GI path. +- The `dump-abi` tests write to `DIN_TEMP` (`--output`), never `--official`. +- Phase 1 asserts the per-contract `proxyAdmin*` keys. + +**`test_04_gi.py` walks one complete GI (Decision 3).** Assert the state after every phase with the existing, unused `_gi_state` helper (`:52-58`): + +1. `setDinToken` (from deploy) → `rewards deposit` (or `fund-emission`) → `gi start` +2. aggregator and auditor registration → `auditor register-encryption-key` for each auditor +3. LMS → `auditor lock-seed` (`AuditSeedLocked`) → `auditor-batches create` → `create-testdataset --submit` (`AuditTestDataAssigned`) +4. `lms-evaluation start` → `evaluate --submit` → `lms-evaluation start-reveal` → `auditor lms-evaluation reveal` → `close` +5. `aggregator lock-seed` (`AggSeedLocked`) → `create-t1nt2-batches` +6. `T1 start` → `aggregate-t1 --submit` → `T1 start-reveal` → `reveal-t1` → `T1 close`; the same for T2; then `T2 set-score` +7. `slash auditors` → `slash aggregators` → `gi end` (assert `GIended` by name and its new ordinal; drop the `or "23"` fallback) +8. `rewards claim` / `withdraw` for one client, one auditor and one aggregator (assert each DIN balance rises) → `gi release-slots` + +Once task_061026_20 Part B has landed, add a negative check: an aggregator trying to register as an auditor reverts. + +**Optional second GI:** fund GI 2, then `gi start` from `GIended`. This proves the loop and slot reuse. Mark it `integration` + slow and keep it out of CI. Add it only after the single-GI run passes. + +**Docs:** update `tests/dincli/NOTES.md` (drop the INTERIM hardhat notes, refresh the GI map) and `Documentation/technical/testing/dincli-testing-guide.md`: +- 7 platform contracts +- no hardhat compile +- the new phases +- client accounts are really `range(2, 11)` + +## Deliverables (Part D) + +- [ ] Suite on foundry artifacts, no tracked-file writes, Phase 1 assertions fixed +- [ ] One complete GI with state asserted after every phase, claims and release slots +- [ ] A local `pytest tests/dincli/ -v -x -m integration --tb=short` run (anvil, IPFS, Docker), passing end to end, with its summary pasted in the PR +- [ ] `NOTES.md` and the testing guide updated + +**Estimate:** 2 days. + +--- + +# Part E — GI docs — PR 4 + +Bring each doc in line with the final commands and states: + +| Doc | Main fixes | +|---|---| +| `Documentation/public/workflows/model-workflow.md` | Foundry artifacts + `--model-id`; `create-genesis-model` / `submit-genesis-model`; `task model-owner register-request` + DIN-Rep approval; `update-manifest-request`; funding before `gi start`; `train-lms` → `submit-lm`; auditor key prerequisite; the three reveal windows; seed and test-data states; claim and release slots after `gi end` | +| `Documentation/public/roles/model-owner.md` | `get-registry-fee`; `task model-owner …` registry commands (replacing the nonexistent `model-owner registry …`); genesis names; funding; `start-reveal` for evaluation, T1 and T2; `create-testdataset --submit`; claim; release slots; disputes | +| `Documentation/public/roles/auditors.md` | `register-encryption-key`, `lms-evaluation reveal`, claim, disputes | +| `Documentation/public/roles/clients.md` | `train-lms` then `submit-lm`, claim | +| `Documentation/public/roles/aggregators.md` | claim, `reveal-t2 --batch`, dispute | +| `Documentation/public/getting-started.md` | `aggregator show-t1/t2-batches`; auditor key + reveal + `lock-seed`; `submit-lm`; the outdated "rewards not the focus" line | +| `Documentation/public/manifest.md`, `guides/keystore-migration.md` | genesis command name; `train-lms --submit` | +| `Documentation/public/workflows/din-workflow.md` | 7 contracts; `withdraw` → `sweep-fees`; the fee-value conflict | +| `Documentation/public/setup.md` | Option B's `pip install git+…@main#subdirectory=dist` can't build: `dist/` on `main` holds only wheels and sdists, with no `pyproject.toml`. Replace it with a working install, e.g. `pip install "git+https://github.com/InfiniteZeroFoundation/DevNet.git@main"` from the repo root, or a direct wheel URL. Bring Option A's wheel name (`dincli-0.1.0`) to the current version | +| `Developer/ROADMAP.md:19` | Rewrite the deploy-blocker sentence ("24,585 B … 9 B over EIP-170") for the PR #211 sizes and the CI size gate. Flag the "DevNet 3.0" vs "DevNet 2.0" naming in the PR for Umer to decide | +| `Documentation/technical/contracts/DINShared.md` §2.2 | Diagram with the funding gate and the seed and test-data states | +| `CLAUDE.md` | 7 platform contracts; GI summary with funding, seed locks, keys, reveals, claim and release slots | + +Flag the node README's "local Hardhat devnet" line in the PR; don't change it. + +After merge, follow up on the wiki pages that still say "no dincli command yet". + +## Deliverables (Part E) + +- [ ] Every doc in the table updated +- [ ] `python3 .github/scripts/check_doc_links.py Documentation` and `… Developer` green +- [ ] Wiki follow-up listed in the PR + +**Estimate:** 1.5 days. + +--- + +## Coordination with task_061026_20 + +- **`DINShared.sol`.** Part B edits the `GIstates` enum and adds `TA_TestDataNotAssigned`. task_061026_20 Part B adds `isDINAggregator` to `IDINTaskCoordinator` and `TA_DualRoleNotAllowed`. The sections differ; whichever PR merges second rebases. +- **`DINTaskAuditor` bytes and ABI.** Part B's commitment check (+75 B) counts against the shared budget in task_061026_20 Part A. Both tasks regenerate `dincli/abis/DINTaskAuditor.json`; the second to merge regenerates on top of the first. +- **Getters.** task_061026_20 keeps `giRewardSnapshot`, `rewardClaimed` and `testDataDisputes` public for Part C. Once Part B's state guards the double-set, `Is_testdataCIDs_Assigned` can go entirely. Settle that in whichever PR lands second. +- **#180 guard.** The suite uses disjoint role accounts. Part D adds the negative check once task_061026_20 Part B lands. + +--- + +## Out of scope + +- **[#228](https://github.com/InfiniteZeroFoundation/DevNet/issues/228):** the integration-suite CI job. It follows once Part D passes. +- **#201 A4, #180, #193:** covered by [task_061026_20](task_061026_20.md). +- **Owner parameter setters in dincli** (`setDisputeParams`, `setS1/S2/S3*`, `setRewardSplit`, `setNetworkFeeFloor`): revisit with #155. +- **A contract-side `modelId` check in `DINModelRegistry`:** a mainnet follow-up (BL-34 / #224). +- **BL-29 to BL-33, #194, #78, #181, #178:** each needs a design decision first, or is mainnet-grade. From 261e923d963402c064ff35c2a61858ce2ef6e79a Mon Sep 17 00:00:00 2001 From: umermjd11 Date: Tue, 6 Oct 2026 20:33:02 +0500 Subject: [PATCH 2/2] =?UTF-8?q?docs(tasks):=20task=5F061026=5F21=20?= =?UTF-8?q?=E2=80=94=20PR=20No.=20232=20amendment=201:=20claimDisputeBond?= =?UTF-8?q?=20at=20:1583?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Part C table (:200): claimDisputeBond() is at DINTaskCoordinator.sol:1583; :1575 is _burnAndForward(d.bond) inside resolveDispute. Same fix as PR No. 229. - :187 (nit): the auditor-side stake guard in deploy.py is at :63-64, not :61-62. Co-Authored-By: Claude Opus 5.5 --- Developer/tasks/task_061026_21.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Developer/tasks/task_061026_21.md b/Developer/tasks/task_061026_21.md index 0bd4ae16..572f5498 100644 --- a/Developer/tasks/task_061026_21.md +++ b/Developer/tasks/task_061026_21.md @@ -184,7 +184,7 @@ Each new state is **set by the function that already does the step**, so a GI ne - `model-owner deploy task-coordinator` / `task-auditor` get `--model-id`, defaulting to `DINModelRegistry.totalModels()`. That's the ID the next approval assigns (`DINModelRegistry.sol:237`, 0-based). Warn that the guess only holds if no other request is approved first. - The auditor deploy reads `modelId()` from the coordinator and refuses a mismatch. - Both deploys call `setDinToken`. -- Fix the latent `NameError` when the `stake` entry is missing (`deploy.py:27-28`, `:61-62`). +- Fix the latent `NameError` when the `stake` entry is missing (`deploy.py:27-28`, `:63-64`). - **`modelId` check at approval (Decision 2: dincli-side).** `dinrep registry approve-registration-request` compares the requested contracts' `modelId()` with `totalModels()` and refuses on a mismatch unless `--force` is passed. A contract-side check in `DINModelRegistry.approveModel` is a mainnet-registry follow-up, in the same area as BL-34 / #224. **New commands:** @@ -197,7 +197,7 @@ Each new state is **set by the function that already does the step**, so a GI ne | `dincli auditor register-encryption-key` | `DinValidatorStake.registerEncryptionKey` | Generates the X25519 key **per wallet** (e.g. `auditor_x25519_
.key`, chmod 600), replacing today's single shared `auditor_x25519.key`, which breaks several `--demokey` auditors on one machine. Updates `_load_auditor_x25519_key` (`auditor.py:33-41`) to match. The owner key (`auditor_batches.py:170-177`) also gets chmod 600 | | `dincli model-owner gi release-slots --gi N` | `releaseGIRegistrationSlots` | BL-28 | | `dincli auditor dispute-test-data`, `dincli model-owner disputes resolve-test-data / reassign-test-data`, `… disputes close-expired` | `openTestDataDispute` (`DINTaskAuditor.sol:1480`), `resolveTestDataDispute` (`:1524`), `closeExpiredDispute` (`:1557`), `reassignAuditTestDataset` (`:1601`) | **Decision 4: in this task.** Built against the PR #215 shape: only batch auditors open a dispute, only the owner resolves, an unanswered dispute is upheld on expiry, there's no penalty after settlement, and `TA_RewardsAlreadySettled` applies. Bond approval comes first | -| `dincli aggregator dispute`, `dincli model-owner disputes resolve-aggregation / settle-recomputation`, `… expire`, `… claim-bond` | `openDispute` (`DINTaskCoordinator.sol:1368`), `resolveDispute` (`:1535`), `settleRecomputation` (`:1609`), `expireDispute` (`:1671`), `claimDisputeBond` (`:1575`) | S4 | +| `dincli aggregator dispute`, `dincli model-owner disputes resolve-aggregation / settle-recomputation`, `… expire`, `… claim-bond` | `openDispute` (`DINTaskCoordinator.sol:1368`), `resolveDispute` (`:1535`), `settleRecomputation` (`:1609`), `expireDispute` (`:1671`), `claimDisputeBond` (`:1583`) | S4 | **Fail fast instead of reverting:** - `gi start` checks `giRewardPool(next GI) > 0` and points to `rewards deposit`.