From e89a6a74b274259623a8a21527c9d20f4f697f29 Mon Sep 17 00:00:00 2001 From: umermjd11 Date: Thu, 5 Nov 2026 21:34:32 +0500 Subject: [PATCH] docs: bring the GI docs in line with the final commands and states (task_061026_21 Part E) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Public docs (model-workflow, roles/*, getting-started, manifest, keystore-migration, din-workflow, setup, fashion-mnist guide): - deploy from foundry/out with --model-id (and its defaults) and setDinToken; - create-genesis-model / submit-genesis-model; task directory is tasks// (no task_ prefix, as get_task_dir); - registration and manifest updates as requests the DIN-Representative approves (`task model-owner register-request`, `update-manifest-request`, `dinrep registry approve-*`), with the fees and `system get-registry-fee`; - reward-pool funding before `gi start`; auditor encryption keys; the dual-role rule; - train-lms then submit-lm; - the seed-lock and test-data states and the three reveal windows; T2 set-score before slashing; - reward claim/withdraw, gi release-slots, and both dispute families; - din-workflow: the seven platform contracts, sweep-fees instead of withdraw, and the registry fee values; - setup: Option B installs from the repo root on main; the wheel is 0.2.0. Technical: DINShared.md §2.2 shows the funding gate on startGI and that endGI settles rewards; DINTaskAuditor.md §13 No. 9 notes the per-wallet commit caches. CLAUDE.md: seven platform contracts and the full GI summary. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 6 +- Documentation/public/getting-started.md | 67 ++++- .../public/guides/fashion-mnist-cnn.md | 4 +- .../public/guides/keystore-migration.md | 4 +- Documentation/public/manifest.md | 16 +- Documentation/public/roles/aggregators.md | 43 +++- Documentation/public/roles/auditors.md | 66 ++++- Documentation/public/roles/clients.md | 39 ++- Documentation/public/roles/model-owner.md | 172 ++++++++++--- Documentation/public/setup.md | 8 +- .../public/workflows/din-workflow.md | 28 +- .../public/workflows/model-workflow.md | 243 ++++++++++++++---- .../technical/contracts/DINShared.md | 9 +- .../technical/contracts/DINTaskAuditor.md | 2 +- 14 files changed, 555 insertions(+), 152 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1d39515f..7ca31c0f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,10 +49,10 @@ dincli system register-wallet --account ### Two layers: protocol contracts vs. per-model task contracts -- **Platform-level contracts** (deployed once by the DIN-Representative): `DinCoordinator` (ETH<->DIN exchange, slasher registry admin), `DinToken` (ERC20, minted on ETH deposit), `DinValidatorStake` (validator staking/slashing), `DinModelRegistry` (model registration, open-source vs proprietary fee). See `Documentation/public/workflows/din-workflow.md`. +- **Platform-level contracts** (seven, deployed once by the DIN-Representative behind transparent proxies via `foundry/script/DeployPlatform.s.sol`): `DinCoordinator` (ETH<->DIN exchange, slasher registry admin), `DinToken` (ERC20, minted on ETH deposit), `DinValidatorStake` (validator staking/slashing, auditor encryption keys), `DinModelRegistry` (model registration requests and approvals, open-source vs proprietary fee), `DinTreasury` (custody), `DinFeeRouter` (splits swept fees), `DinEmission` (per-GI reward subsidy on a decay schedule). See `Documentation/public/workflows/din-workflow.md`. - **Task-level contracts** (deployed per model by the model owner): `DINTaskCoordinator` and `DINTaskAuditor`. These must be authorized as "slashers" on `DinValidatorStake` (via `DinCoordinator`, only callable by the DIN-Representative) *before* the model owner can register the model in `DinModelRegistry`. See `Documentation/public/workflows/model-workflow.md` for the full step-by-step (deploy → slasher auth request → genesis model → register → global iterations). -A model's lifecycle runs in **Global Iterations (GI)**: aggregator/auditor registration → Local Model Submission (LMS) by clients → auditor evaluation/scoring → two-tier aggregation (T1 sub-batches, T2 combines T1 into the new global model) → slashing of misbehaving validators → GI end. Each phase is opened/closed explicitly by the model owner via `dincli model-owner ...` subcommands, and other roles act only within an open phase. +A model's lifecycle runs in **Global Iterations (GI)**: the model owner funds the GI's reward pool (`gi start` refuses an unfunded GI) → aggregator/auditor registration (auditors also register an X25519 encryption key) → Local Model Submission (LMS) by clients → auditor batch seed lock → auditor batches → per-batch encrypted test data → auditor evaluation (commit, then reveal) → T1/T2 batch seed lock → two-tier aggregation (T1 sub-batches, T2 combines T1 into the new global model; each tier commit, then reveal) and the T2 score → slashing of misbehaving validators → GI end, which settles rewards → participants claim and the model owner releases the GI's registration slots. Each phase is opened/closed explicitly by the model owner via `dincli model-owner ...` subcommands, the seed locks are permissionless, and other roles act only within an open phase. Test-data and aggregation disputes are bonded and answered by the model owner (`dincli model-owner disputes ...`). The state names and ordinals are in `Documentation/technical/contracts/DINShared.md` §2. ### CLI structure (`dincli/`) @@ -63,7 +63,7 @@ A model's lifecycle runs in **Global Iterations (GI)**: aggregator/auditor regis ### Manifest-driven, pluggable model services -Each model owner supplies their own Python service files (not part of this repo) implementing model-specific logic: `model.py` (architecture), `modelowner.py` (genesis model, scoring, audit test data), `client.py` (local training/DP), `auditor.py` (scoring), `aggregator.py` (T1/T2 aggregation). These are uploaded to IPFS and referenced by CID in a per-model `manifest.json` at `/tasks//task_/manifest.json`. `dincli` dynamically loads and calls these functions at runtime (`DinContext.load_custom_fn`), fetching them from IPFS on demand and caching by CID. `cache_model_0/` and `cid_services/` in this repo are example/reference service implementations (MNIST-style), not framework code. +Each model owner supplies their own Python service files (not part of this repo) implementing model-specific logic: `model.py` (architecture), `modelowner.py` (genesis model, scoring, audit test data), `client.py` (local training/DP), `auditor.py` (scoring), `aggregator.py` (T1/T2 aggregation). These are uploaded to IPFS and referenced by CID in a per-model `manifest.json` at `/tasks///manifest.json`. `dincli` dynamically loads and calls these functions at runtime (`DinContext.load_custom_fn`), fetching them from IPFS on demand and caching by CID. `cache_model_0/` and `cid_services/` in this repo are example/reference service implementations (MNIST-style), not framework code. Differential privacy is opt-in per model via a nested `dp` block in the manifest; when enabled, `client.py`'s training function applies the configured DP mechanism. diff --git a/Documentation/public/getting-started.md b/Documentation/public/getting-started.md index f84b099a..b61936a1 100644 --- a/Documentation/public/getting-started.md +++ b/Documentation/public/getting-started.md @@ -173,9 +173,7 @@ The current devnet primarily focuses on: * Validation workflows * Ethereum-enforced protocol state transitions -Staking and slashing concepts exist within the protocol architecture. - -Economic and reward distribution mechanisms are still under active development and are not yet the primary focus of the current devnet phase. +Staking, slashing and rewards are part of every Global Iteration: validators stake DIN to register, misbehaving or absent validators are slashed, and each GI pays clients, auditors and aggregators from a reward pool the model owner funds before starting it. After a GI ends, claim your share with `dincli rewards claim --gi ` and `dincli rewards withdraw `. Reward splits, bond sizes and other economic parameters are not final and may change between devnet phases. --- @@ -349,12 +347,18 @@ dincli task gi show-state 0 ### Step 5: Check your Aggregation Batch (if state = `T1nT2Bcreated`) +If the state is still `LMSevaluationClosed`, lock the batch-assignment seed first (this moves it to `AggSeedLocked`; the model owner then creates the batches): + +```bash +dincli aggregator lock-seed 0 +``` + ```bash # Check T1 batch assigned to you -dincli model-owner aggregation show-t1-batches 0 --detailed +dincli aggregator show-t1-batches 0 --detailed # Check T2 batch assigned to you -dincli model-owner aggregation show-t2-batches 0 --detailed +dincli aggregator show-t2-batches 0 --detailed ``` --- @@ -395,6 +399,14 @@ dincli aggregator reveal-t2 0 > ⚠️ Aggregation is commit-then-reveal: a commit that is never revealed is slashed like a missed submission. Reveal from the same machine you committed from; the salt is cached locally. +### Step 9: Claim your reward (once state = `GIended`) + +```bash +# credit your share of GI (the GI you took part in), then withdraw it +dincli rewards claim 0 --gi +dincli rewards withdraw 0 +``` + > 💡 T1 and T2 batch assignments depend on the current Global Iteration state and protocol allocation logic. A registered aggregator may not receive a batch in every iteration. --- @@ -433,6 +445,9 @@ dincli auditor dintoken read-stake # Register as auditor dincli auditor register 0 + +# Once per wallet: register the encryption key your batch's test data is encrypted to +dincli auditor register-encryption-key ``` --- @@ -443,13 +458,19 @@ dincli auditor register 0 dincli task gi show-state 0 ``` -### Step 5: Check your Auditor Batch (if state = `AuditorsBatchesCreated`) +### Step 5: Check your Auditor Batch (if state = `AuditorsBatchesCreated` or `AuditTestDataAssigned`) + +If the state is still `LMSclosed`, lock the batch-assignment seed first (this moves it to `AuditSeedLocked`; the model owner then creates the batches): + +```bash +dincli auditor lock-seed 0 +``` ```bash dincli auditor lms-evaluation show-batch 0 ``` -If a batch is shown, you will soon be required to audit it. +If a batch is shown, you will soon be required to audit it. The model owner then assigns each batch its test data (`AuditTestDataAssigned`) and opens evaluation. --- @@ -459,14 +480,27 @@ If a batch is shown, you will soon be required to audit it. dincli task gi show-state 0 ``` -### Step 7: Audit your assigned batch (if state = `LMSevaluationStarted`) +### Step 7: Audit your assigned batch (commit if state = `LMSevaluationStarted`, reveal if `LMSevaluationRevealStarted`) ```bash # check your assigned batch dincli auditor lms-evaluation show-batch 0 -# audit your batch (scripts run automatically) +# audit your batch (scripts run automatically) and commit a hidden hash of each score dincli auditor lms-evaluation evaluate 0 --submit + +# once the model owner opens the reveal window: reveal your scores +dincli auditor lms-evaluation reveal 0 +``` + +> ⚠️ Scoring is commit-then-reveal: a commit that is never revealed is slashed as a missed vote. Reveal from the same machine you committed from; the salt is cached locally. + +### Step 8: Claim your reward (once state = `GIended`) + +```bash +# credit your share of GI (the GI you took part in), then withdraw it +dincli rewards claim 0 --gi +dincli rewards withdraw 0 ``` > 💡 Auditor batch assignments depend on the current Global Iteration state and protocol allocation logic. A registered auditor may not receive a batch in every iteration. @@ -583,17 +617,24 @@ dincli system register-wallet --account 0 # Check ETH balance dincli system --eth-balance -# Optional (Recommended Step) to ensure training is running fine locally -# Train locally without submitting +# Train a local model (nothing is sent on-chain) dincli client train-lms 0 -# Train and submit local model -dincli client train-lms 0 --submit +# Upload the trained model and submit it +dincli client submit-lm 0 # Show submitted models dincli client lms show-models 0 ``` +### Step 4: Claim your reward (once state = `GIended`) + +```bash +# credit your share of GI (the GI you took part in), then withdraw it +dincli rewards claim 0 --gi +dincli rewards withdraw 0 +``` + --- # 🧠 Final Notes diff --git a/Documentation/public/guides/fashion-mnist-cnn.md b/Documentation/public/guides/fashion-mnist-cnn.md index 60bc6615..b8228107 100644 --- a/Documentation/public/guides/fashion-mnist-cnn.md +++ b/Documentation/public/guides/fashion-mnist-cnn.md @@ -119,11 +119,11 @@ From your project root (the directory where `dincli` stores tasks): ```bash # deploy DINTaskCoordinator dincli model-owner deploy task-coordinator \ - --artifact "hardhat/artifacts/contracts/DINTaskCoordinator.sol/DINTaskCoordinator.json" + --artifact "foundry/out/DINTaskCoordinator.sol/DINTaskCoordinator.json" # deploy DINTaskAuditor dincli model-owner deploy task-auditor \ - --artifact "hardhat/artifacts/contracts/DINTaskAuditor.sol/DINTaskAuditor.json" + --artifact "foundry/out/DINTaskAuditor.sol/DINTaskAuditor.json" ``` Both contract addresses are written to your local `.env` file. Request diff --git a/Documentation/public/guides/keystore-migration.md b/Documentation/public/guides/keystore-migration.md index bbb01670..04eb1aa0 100644 --- a/Documentation/public/guides/keystore-migration.md +++ b/Documentation/public/guides/keystore-migration.md @@ -94,7 +94,7 @@ To select a named wallet at runtime, add `DIN_WALLET_NAME` to the `.env` used by `docker-compose`, or pass `--wallet` with each command: ```bash -docker compose exec din-node dincli --wallet validator client train-lms 0 --submit +docker compose exec din-node dincli --wallet validator client submit-lm 0 ``` ### Host install @@ -108,7 +108,7 @@ DIN_WALLET_NAME=validator Or use the top-level flag: ```bash -dincli --wallet validator client train-lms 0 --submit +dincli --wallet validator client submit-lm 0 ``` --- diff --git a/Documentation/public/manifest.md b/Documentation/public/manifest.md index ac31fbb6..1732327b 100644 --- a/Documentation/public/manifest.md +++ b/Documentation/public/manifest.md @@ -10,16 +10,16 @@ The manifest is a JSON file containing the metadata for your model and task. It The manifest file must be placed at: ``` -/tasks//task_/manifest.json +/tasks///manifest.json ``` For example: ``` -/tasks/sepolia_op_devnet/task_0x1e31...4b133/manifest.json +/tasks/sepolia_op_devnet/0x1e31...4b133/manifest.json ``` > [!NOTE] -> If the manifest file is absent when the genesis setup (`dincli task model-owner create-genesis`) runs, it is automatically created with default values from the default manifest CID (`bafybeibbhrefnamky7vmgcrhfx4ptxb3bdemh5dtnvwfkpualoganvnuve`). +> `dincli model-owner model create-genesis-model` needs the manifest in the task directory. To start from the reference MNIST model, run `dincli model-owner task create-task-dir` and then `dincli model-owner task cache-default-artifacts`, which fetches the default manifest, services, ABIs and requirements (their CIDs are the `default_*` entries in `dincli/config/din_info.json`). --- @@ -39,7 +39,7 @@ For example: | Field | Required | Description | |---|---|---| -| `Genesis_Model_CID` | Yes | IPFS CID of the genesis model. Set after running `dincli model-owner model create-genesis` | +| `Genesis_Model_CID` | Yes | IPFS CID of the genesis model. Set after running `dincli model-owner model create-genesis-model` | | `DINTaskCoordinator_Contract` | Yes | Address of the deployed TaskCoordinator contract | | `DINTaskAuditor_Contract` | Yes | Address of the deployed TaskAuditor contract | | `dp` | No | Nested Differential Privacy configuration block used by services at runtime. See [Differential Privacy Parameters](#differential-privacy-parameters) below. | @@ -152,8 +152,12 @@ Please find the example/template manifest file at [cache_model_0/manifest.json]( ## Updating the Manifest -Once the model is registered and assigned a model ID, the manifest file should be updated with the `Model ID` field and re-uploaded to IPFS. The following dincli command can be used to update the model CID in the DINModelRegistry contract: +Once the model is registered and assigned a model ID, the manifest file can be updated (for example, with the `Model ID` field or new service CIDs) and re-uploaded. Changing the manifest CID in `DINModelRegistry` is a request, with its own fee, that the DIN-Representative approves: ```bash -dincli task model-owner update-manifest [--modelCID ] [--manifestpath ] +# model owner: upload the manifest and submit the update request +dincli task model-owner update-manifest-request [--manifestpath | --manifestCID ] + +# DIN-Representative +dincli dinrep registry approve-manifest-update ``` diff --git a/Documentation/public/roles/aggregators.md b/Documentation/public/roles/aggregators.md index 72786b2e..aff34f4e 100644 --- a/Documentation/public/roles/aggregators.md +++ b/Documentation/public/roles/aggregators.md @@ -49,7 +49,7 @@ dincli aggregator register [--gi ] | `--gi ` | No | The Global Iteration index. Defaults to the current GI if omitted | > [!IMPORTANT] -> Aggregators Registration must be open for the current GI before to successfully register as an aggregator. +> Aggregator registration must be open for the current GI before you can register. A wallet registered as an aggregator can't also register as an auditor in the same GI. --- @@ -59,6 +59,14 @@ Aggregators operate in two tiers: - **Tier 1 (T1)** — Intermediate aggregation: combine local model batches into sub-global model updates. - **Tier 2 (T2)** — Final aggregation: combine sub-global model updates into a single global model. +### Lock the Batch-Assignment Seed (optional, recommended) + +```bash +dincli aggregator lock-seed [--gi ] +``` + +When evaluation closes, the T1/T2 batch assignment is drawn from a seed anchored to a future block. Anyone can lock it once that block is mined; locking it yourself stops the Model Owner from waiting out a draw they dislike. The command waits for the seed block, then locks (or skips if someone already has), and the GI moves to `AggSeedLocked`. `show-t1-batches` / `show-t2-batches` do the same automatically when run before batches exist. Only valid while the GI is in `LMSevaluationClosed`. + ### Tier 1 Aggregation **Lock the batch-assignment seed (optional, recommended):** @@ -138,6 +146,38 @@ dincli aggregator aggregate-t2 [--gi ] [--batch ] dincli aggregator reveal-t2 [--gi ] ``` +There is a single T2 batch, so `reveal-t2` takes no `--batch`. + +--- + +## 4. Rewards + +After the Model Owner ends the GI, credit your share of its reward pool and withdraw it: + +```bash +# Credit your share for an ended GI +dincli rewards claim --gi + +# Transfer your whole claimable balance to your wallet +dincli rewards withdraw +``` + +--- + +## 5. Disputing an Aggregation + +Any active validator can dispute a finalized T1 or T2 batch's CID within the dispute window after it was finalized. It posts the coordinator's DIN dispute bond, and each batch can be disputed only once: + +```bash +dincli aggregator dispute --tier t1|t2 --batch [--gi ] +``` + +The Model Owner either rejects the dispute (the bond is forfeited) or upholds it, which assigns a fresh subgroup of 3 aggregators to recompute the batch. If the recomputation confirms the dispute, or the fresh subgroup misses its deadline, your bond is credited back. Withdraw credited bonds with: + +```bash +dincli aggregator claim-dispute-bond +``` + --- ## Workflow @@ -149,3 +189,4 @@ dincli aggregator reveal-t2 [--gi ] 5. **Reveal T1** — Run `reveal-t1` once the Model Owner opens the T1 reveal window (`T1AggregationRevealStarted`). 6. **Aggregate and commit T2** — If assigned to the final tier, run `aggregate-t2 --submit` when the Tier 2 phase opens (`T2AggregationStarted`). 7. **Reveal T2** — Run `reveal-t2` once the T2 reveal window opens (`T2AggregationRevealStarted`). +8. **Claim** — After the GI ends, run `rewards claim` and `rewards withdraw`. diff --git a/Documentation/public/roles/auditors.md b/Documentation/public/roles/auditors.md index 8703d1d2..cc57fddf 100644 --- a/Documentation/public/roles/auditors.md +++ b/Documentation/public/roles/auditors.md @@ -51,7 +51,17 @@ dincli auditor register [--gi ] | `--gi ` | No | The Global Iteration index. Defaults to the current GI if omitted | > [!IMPORTANT] -> Registration must be open for the current GI before this command will succeed. +> Registration must be open for the current GI before this command will succeed. A wallet registered as an aggregator in the same GI can't also register as an auditor. + +### Register an Encryption Key (once per wallet) + +The Model Owner encrypts each batch's test data to its auditors' X25519 public keys, so you need a registered key before you can be given test data. + +```bash +dincli auditor register-encryption-key +``` + +The command generates this wallet's key, saves it as `/auditor_x25519_
.key` (mode 0600), and registers the public key on `DinValidatorStake`. It skips the transaction if that key is already registered. Run it from the machine you evaluate on, and keep the file: without it you can't decrypt your batch's test data. Until every auditor in a batch has a key, the Model Owner's `create-testdataset --submit` stops and names the keyless auditors. --- @@ -65,7 +75,7 @@ Once the Model Owner creates Auditor Batches and assigns you to one, you can vie dincli auditor lock-seed [--gi ] ``` -Between `closeLMsubmissions` and batch creation, the auditor batch assignment is drawn from a seed anchored to a future block. Anyone can lock it once that block is mined. If only the Model Owner locks it, they can decline to lock a draw they dislike and wait ~256 blocks for a fresh one, so locking it yourself as soon as it is available removes that option. The command waits for the seed block, then locks (or skips if someone already has). `lms-evaluation show-batch` does the same automatically when run before batches exist. Only valid while the GI is in `LMSclosed`. +Between `closeLMsubmissions` and batch creation, the auditor batch assignment is drawn from a seed anchored to a future block. Anyone can lock it once that block is mined. If only the Model Owner locks it, they can decline to lock a draw they dislike and wait ~256 blocks for a fresh one, so locking it yourself as soon as it is available removes that option. The command waits for the seed block, then locks (or skips if someone already has). `lms-evaluation show-batch` does the same automatically when run before batches exist. Only valid while the GI is in `LMSclosed`; a successful lock moves it to `AuditSeedLocked`. ### Show Your Assigned Batch @@ -93,11 +103,57 @@ dincli auditor lms-evaluation evaluate [--gi ] [--submit] [ | `--batch ` | No | Evaluate a specific batch. Defaults to your assigned batch if omitted | | `--lmi ` | No | Evaluate a single Local Model by index. Evaluates all models in the batch if omitted | +Evaluation needs your batch's test data, which the Model Owner assigns before opening evaluation (GI state `AuditTestDataAssigned`). + +### Reveal Your Scores + +Once the Model Owner closes the commit window (`lms-evaluation start-reveal`), reveal what you committed. Only revealed scores count, and a commit that is never revealed is slashed as a missed vote. + +```bash +dincli auditor lms-evaluation reveal [--gi ] [--batch ] [--lmi ] +``` + +| Option | Required | Description | +|---|---|---| +| `--gi ` | No | Global Iteration index. Defaults to the current GI if omitted | +| `--batch ` | No | Reveal only this batch. Defaults to every batch you committed in | +| `--lmi ` | No | Reveal only this Local Model | + +Reveal from the same machine you committed from: the score, vote and salt are in the local commit cache (`/audits/commits//`). + +--- + +## 4. Rewards + +After the Model Owner ends the GI, credit your share of its reward pool and withdraw it: + +```bash +# Credit your share for an ended GI +dincli rewards claim --gi + +# Transfer your whole claimable balance to your wallet +dincli rewards withdraw +``` + +--- + +## 5. Disputing Test Data + +If your batch's test data is wrong (for example, you received no key for it), open a dispute. It posts a DIN bond (100 DIN by default), and must be opened before the GI's rewards settle at `gi end`: + +```bash +dincli auditor dispute-test-data --batch [--gi ] +``` + +The Model Owner answers by revealing the batch key. If it matches the on-chain commitment, the dispute fails and the bond is forfeited. If it doesn't, or the Model Owner doesn't answer within the window (anyone can then close it with `dincli model-owner disputes close-expired`), the dispute is upheld and the bond comes back to you. + --- ## Workflow 1. **Stake** — Ensure you have enough DIN Tokens staked. -2. **Register** — Register when the Model Owner opens Auditor registration for the current GI. -3. **Wait for Assignment** — The Model Owner will create Auditor Batches and assign models to you. -4. **Evaluate** — Run `evaluate --submit` to score assigned models and record results on-chain. \ No newline at end of file +2. **Register** — Register when the Model Owner opens Auditor registration for the current GI, and register an encryption key if this wallet doesn't have one yet. +3. **Wait for Assignment** — After LMS closes, lock the seed (`lock-seed`); the Model Owner creates Auditor Batches and assigns each batch its test data. +4. **Evaluate** — Run `evaluate --submit` to score assigned models and commit the results on-chain. +5. **Reveal** — When the reveal window opens, run `lms-evaluation reveal`. +6. **Claim** — After the GI ends, run `rewards claim` and `rewards withdraw`. \ No newline at end of file diff --git a/Documentation/public/roles/clients.md b/Documentation/public/roles/clients.md index 181f04aa..ab9ce6a8 100644 --- a/Documentation/public/roles/clients.md +++ b/Documentation/public/roles/clients.md @@ -26,22 +26,45 @@ Clients contribute to the DIN network by training local models on their own data ## Commands -### Train & Submit a Local Model +### Train a Local Model -Train a local model using your dataset and optionally submit the result to the blockchain. +Train a local model on your dataset, in the worker container. Nothing is sent on-chain. ```bash -dincli client train-lms [--gi ] [--submit] +dincli client train-lms [--gi ] [--packages-dir ] [--no-cache] ``` | Argument / Option | Required | Description | |---|---|---| | `` | Yes | The ID of the model/task you are participating in | | `--gi ` | No | The Global Iteration index. Defaults to the current GI if omitted | -| `--submit` | No | Upload the trained model to IPFS and record the submission on-chain | +| `--packages-dir ` | No | Packages directory to mount into the worker | +| `--no-cache` | No | Don't use cached packages | + +### Submit the Local Model + +Upload the trained model to IPFS and record its CID on-chain. LMS must be open. + +```bash +dincli client submit-lm [--gi ] +``` > [!NOTE] -> Always include `--submit` to make your contribution visible to the network. +> Training alone doesn't count: run `submit-lm` to make your contribution visible to the network. + +--- + +### Claim Rewards + +After the Model Owner ends the GI, credit your share of its reward pool and withdraw it: + +```bash +# Credit your share for an ended GI +dincli rewards claim --gi + +# Transfer your whole claimable balance to your wallet +dincli rewards withdraw +``` --- @@ -64,5 +87,7 @@ dincli client lms show-models [--gi ] 1. **Wait for LMS Open** — The Model Owner must open the Local Model Submission (LMS) phase for the current GI. 2. **Place Dataset** — Ensure your `data.pt` file is at the correct path (see Prerequisites above). -3. **Train** — Run `train-lms` with `--submit` to process your data and record the result on-chain. -4. **Verify** — Run `show-models` to confirm your submission was recorded successfully. \ No newline at end of file +3. **Train** — Run `train-lms` to train on your data. +4. **Submit** — Run `submit-lm` to upload the model and record it on-chain. +5. **Verify** — Run `show-models` to confirm your submission was recorded successfully. +6. **Claim** — After the GI ends, run `rewards claim` and `rewards withdraw`. \ No newline at end of file diff --git a/Documentation/public/roles/model-owner.md b/Documentation/public/roles/model-owner.md index 1110d593..11ce9b89 100644 --- a/Documentation/public/roles/model-owner.md +++ b/Documentation/public/roles/model-owner.md @@ -12,13 +12,19 @@ Deploy the Task Coordinator and Task Auditor contracts specific to your task. ```bash # Deploy the Task Coordinator -dincli model-owner deploy task-coordinator --artifact +dincli model-owner deploy task-coordinator --artifact foundry/out/DINTaskCoordinator.sol/DINTaskCoordinator.json [--model-id ] # Deploy the Task Auditor -dincli model-owner deploy task-auditor --artifact +dincli model-owner deploy task-auditor --artifact foundry/out/DINTaskAuditor.sol/DINTaskAuditor.json [--taskCoordinator
] [--model-id ] ``` -The `--artifact` flag must point to the compiled Hardhat/Foundry JSON output (contains ABI and bytecode). +| Option | Required | Description | +|---|---|---| +| `--artifact ` | Yes | The compiled Foundry JSON output (ABI and bytecode), from `cd foundry && forge build` | +| `--model-id ` | No | The ID `DINModelRegistry` will assign at approval; fixed in the contract. The coordinator defaults to `DINModelRegistry.totalModels()` (the ID the next approval assigns, with a warning that this only holds if no other request is approved first). The auditor defaults to the coordinator's `modelId()` and refuses any other value | +| `--taskCoordinator
` | No | Coordinator to pair the auditor with. Defaults to `_DINTaskCoordinator_Contract_Address` in `.env` | + +Both deploys also set the platform `DinToken` on the new contract (`setDinToken`), which reward deposits, claims and dispute bonds need. The auditor deploy then links the auditor to the coordinator. --- @@ -45,19 +51,21 @@ dincli model-owner add-slasher --taskAuditor [--contract \ - --task-coordinator \ - --task-auditor \ - [--open-source] +# Check the manifest's contract addresses and genesis CID against your .env first +dincli model-owner model validate-update-manifest + +dincli task model-owner register-request \ + [--taskCoordinator ] \ + [--taskAuditor ] \ + [--manifestpath | --manifestCID ] \ + [--isOpenSource] ``` +The contract addresses default to the ones in your `.env`, and the manifest to the task directory's `manifest.json`, which is uploaded to IPFS. Without `--isOpenSource` the model is registered as proprietary. + On success you receive a **`requestId`**. Track it to monitor approval status. -### Step 2 — Wait for DAO Approval +### Step 2 — Wait for DIN-Representative Approval -The DIN-Representative reviews your request and calls `approveModel(requestId)`. You will receive a **`modelId`** once approved. +The DIN-Representative reviews your request and approves it (`dincli dinrep registry approve-registration-request `). Approval assigns the **`modelId`**, which must match the `modelId()` both task contracts were deployed with; dincli refuses a mismatch unless the DIN-Representative passes `--force`. Check the status of your request: ```bash -# TODO -dincli model-owner registry show-request +# Your pending requests (add --include-processed for approved and rejected ones) +dincli task model-owner my-requests [--type model|manifest] [--include-processed] + +# One request in detail +dincli task model-owner show-registration-request ``` > [!IMPORTANT] -> The coordinator and auditor contracts must remain registered slashers and still be owned by your address at the time the DAO approves. If either condition changes, the approval will revert and you must submit a new request. +> The coordinator and auditor contracts must remain registered slashers and still be owned by your address at the time the DIN-Representative approves. If either condition changes, the approval will revert and you must submit a new request. ### Updating a Manifest -Manifest updates also follow a request/approval flow. The model must not be disabled. +Manifest updates also follow a request/approval flow and pay the manifest-update fee. The model must not be disabled. ```bash -# TODO -dincli model-owner registry request-manifest-update --manifest +dincli task model-owner update-manifest-request [--manifestpath | --manifestCID ] + +# Track it +dincli task model-owner show-manifest-update-request ``` -The DAO reviews the request and calls `approveManifestUpdate(requestId)` to apply it. +The DIN-Representative reviews the request and applies it (`dincli dinrep registry approve-manifest-update `). --- @@ -126,12 +143,12 @@ Create and submit the initial (genesis) model to seed the task. ### Create Genesis Model -Uploads the genesis model to IPFS. +Creates the genesis model with your `modelowner.py` service's `getGenesisModelIpfs`, uploads it to IPFS and saves its CID in `.env` as `__GENESIS_MODEL_IPFS_HASH`. -> **Prerequisite** — `_DINTaskCoordinator_Contract_Address` must be set in your `.env` file. +> **Prerequisite** — `_DINTaskCoordinator_Contract_Address` must be set in your `.env` file, and the task directory must hold your manifest and services (`dincli model-owner task create-task-dir`, then `dincli model-owner task cache-default-artifacts` to start from the reference MNIST model). ```bash -dincli model-owner model create-genesis +dincli model-owner model create-genesis-model [--taskCoordinator
] ``` ### Submit Genesis Model @@ -140,10 +157,11 @@ Registers the genesis model on-chain. > **Prerequisite** — `_DINTaskCoordinator_Contract_Address` must be set in your `.env` file. > The test dataset must exist at: -> `/tasks//task_/dataset/test/test_dataset.pt` +> `/tasks///dataset/test/test_dataset.pt` +> (`dincli model-owner model add-default-test-data --default-test-data` fetches the reference MNIST one.) ```bash -dincli model-owner model submit-genesis [--taskCoordinator
] [--ipfs-hash ] [--score ] +dincli model-owner model submit-genesis-model [--taskCoordinator
] [--ipfs-hash ] [--score ] ``` | Option | Required | Description | @@ -160,7 +178,19 @@ The bulk of the work happens in repeating cycles called Global Iterations. Follo --- -### Step 1 — Start GI +### Step 1 — Fund and Start GI + +Each GI pays clients, auditors and aggregators from its reward pool, and `gi start` refuses a GI whose pool is empty. Fund it first, from your own DIN or from the protocol emission schedule: + +```bash +# Deposit DIN into a GI's reward pool (approves, then deposits) +dincli model-owner rewards deposit --amount [--gi ] + +# Or fund it from the DinEmission schedule +dincli model-owner rewards fund-emission [--gi ] +``` + +`--gi` defaults to the next GI. Buy DIN with `dincli dintoken buy `. ```bash dincli model-owner gi start [--gi ] [--threshold ] @@ -223,14 +253,14 @@ dincli model-owner lms show-models [--gi ] ### Step 4 — Auditor Assignment -Assign registered Auditors to evaluate the submitted local model batches. +Assign registered Auditors to evaluate the submitted local model batches, and give each batch its test data. The GI state moves `LMSclosed` → `AuditSeedLocked` → `AuditorsBatchesCreated` → `AuditTestDataAssigned`. ```bash -# Create Auditor batches +# Create Auditor batches (locks the batch-assignment seed first if no auditor has: `dincli auditor lock-seed`) dincli model-owner auditor-batches create [--gi ] -# Generate the test dataset used for auditing -dincli model-owner auditor-batches create-testdataset [--gi ] [--test-data-path ] +# Encrypt each batch's test data to its auditors' keys; --submit assigns it on-chain +dincli model-owner auditor-batches create-testdataset [--gi ] [--test-data-path ] [--submit] [--batch ...] # Show Auditor batches dincli model-owner auditor-batches show [--gi ] @@ -240,6 +270,10 @@ dincli model-owner auditor-batches show [--gi ] |---|---|---| | `--gi ` | No | GI index. Defaults to the current GI if omitted | | `--test-data-path ` | No | Path to the test dataset. Defaults to `//model_/dataset/test/test_dataset.pt` if omitted | +| `--submit` | No | Assign the test data on-chain. Once every batch has it, the GI moves to `AuditTestDataAssigned`, which evaluation needs | +| `--batch ` | No | Repeatable. Retry only these batches after a partial failure | + +`create-testdataset --submit` checks first that every batch auditor has registered an encryption key (`dincli auditor register-encryption-key`) and stops, naming them, if any hasn't. It saves each batch's key and plaintext hash under `/audits/testdata_keys/` (mode 0600); keep them to answer test-data disputes. --- @@ -247,12 +281,17 @@ dincli model-owner auditor-batches show [--gi ] Manage the period during which Auditors score the local models. +Scores are commit-then-reveal: auditors commit hidden scores while evaluation is open, then reveal them in a window you open. Only revealed scores count. + ```bash -# Start evaluation — Auditors begin their evaluations -dincli model-owner lms-evaluation start +# Start evaluation (opens the commit window) +dincli model-owner lms-evaluation start [--gi ] -# Close evaluation — collect results -dincli model-owner lms-evaluation close +# Close the commit window and open the reveal window +dincli model-owner lms-evaluation start-reveal [--gi ] + +# Close evaluation (after auditors have revealed) +dincli model-owner lms-evaluation close [--gi ] ``` **View evaluation results:** @@ -286,20 +325,35 @@ dincli model-owner aggregation show-t2-batches [--gi ] [--d `--detailed` is optional. When provided, includes the Aggregator address, submitted CID, and finalized CID for each batch. +`create-t1nt2-batches` locks the T1/T2 batch-assignment seed first if no aggregator has (`dincli aggregator lock-seed`); the GI moves `LMSevaluationClosed` → `AggSeedLocked` → `T1nT2Bcreated`. + +Like evaluation, each tier is commit-then-reveal: aggregators commit a hidden hash of their aggregated CID, then reveal it once you open the reveal window. Only revealed CIDs count, and a commit that is never revealed is slashed like a missed submission. + ```bash -# Start Tier 1 Aggregation — Aggregators begin combining approved local model in T1 batches +# Start Tier 1 Aggregation (opens the commit window) dincli model-owner aggregation T1 start [--gi ] -# Close Tier 1 Aggregation +# Close the T1 commit window and open the reveal window +dincli model-owner aggregation T1 start-reveal [--gi ] + +# Close Tier 1 Aggregation (finalizes each T1 batch from the revealed CIDs) dincli model-owner aggregation T1 close [--gi ] # Start Tier 2 Aggregation — Aggregators produce the final global model from finalized T1 batches dincli model-owner aggregation T2 start [--gi ] +# Close the T2 commit window and open the reveal window +dincli model-owner aggregation T2 start-reveal [--gi ] + # Close Tier 2 Aggregation dincli model-owner aggregation T2 close [--gi ] + +# Score the final global model on your test dataset and record it on-chain +dincli model-owner aggregation T2 set-score [--gi ] ``` +`set-score` doesn't change the GI state. Run it before slashing: `slash auditors` uses the score and asks you to confirm if it still reads 0. + `--gi` is optional for all commands above. Defaults to the current GI if omitted. --- @@ -318,7 +372,7 @@ dincli model-owner slash auditors [--gi ] dincli model-owner slash aggregators [--gi ] ``` -**End the GI** — finalize the iteration and advance to the next: +**End the GI** — finalize the iteration and settle its reward pool: ```bash dincli model-owner gi end [--gi ] @@ -328,6 +382,44 @@ dincli model-owner gi end [--gi ] --- +### Step 8 — Rewards and Registration Slots + +Once the GI has ended, each participant claims and withdraws its own share (`dincli rewards claim --gi `, then `dincli rewards withdraw `). + +Release the ended GI's validator registration slots, once per GI. Until you do, those registrations count against each validator's concurrent-registration cap: + +```bash +dincli model-owner gi release-slots [--gi ] +``` + +`--gi` defaults to the current GI once it has ended. To start the next GI, fund it (Step 1) and run `gi start` again. + +--- + +### Disputes + +Auditors can dispute their batch's test data, and any active validator can dispute a finalized T1/T2 batch. You answer and settle them: + +```bash +# Test data: reveal the batch key and plaintext hash (within the dispute window) +dincli model-owner disputes resolve-test-data --gi --batch +# Test data: anyone can close an unanswered dispute once the window has passed (it is upheld) +dincli model-owner disputes close-expired --gi --batch +# Test data: assign new test data to a batch whose dispute was upheld +dincli model-owner disputes reassign-test-data --batch [--gi ] [--test-data-path ] + +# Aggregation: reject, or uphold (assigns a fresh subgroup of 3 aggregators; locks the dispute seed first) +dincli model-owner disputes resolve-aggregation --gi --tier t1|t2 --batch --upheld|--rejected +# Aggregation: after the recomputation, confirm (original aggregators slashed, bond returned) or dismiss (bond forfeited) +dincli model-owner disputes settle-recomputation --gi --tier t1|t2 --batch --confirmed|--dismissed +# Aggregation: anyone, past the resolution deadline (the fresh subgroup is slashed) +dincli model-owner disputes expire --gi --tier t1|t2 --batch +``` + +`resolve-test-data` needs the key `create-testdataset --submit` saved. An upheld test-data dispute takes part of the GI's reward pool as a penalty. See [model-workflow.md](../workflows/model-workflow.md#17-disputes) for the full flow. + +--- + ## 4. Monitoring & Management ### Check GI State @@ -347,7 +439,7 @@ A quick-reference set of read commands: dincli model-owner lms show-models # Evaluation results grouped by model -dincli model-owner lms-evaluation show --models +dincli model-owner lms-evaluation show --models # Auditor batch assignments dincli model-owner auditor-batches show diff --git a/Documentation/public/setup.md b/Documentation/public/setup.md index 0faaa54a..490d1748 100644 --- a/Documentation/public/setup.md +++ b/Documentation/public/setup.md @@ -31,17 +31,19 @@ source venv/bin/activate ```bash # Download the wheel file -wget https://github.com/InfiniteZeroFoundation/DevNet/raw/refs/heads/main/dist/dincli-0.1.0-py3-none-any.whl +wget https://github.com/InfiniteZeroFoundation/DevNet/raw/refs/heads/main/dist/dincli-0.2.0-py3-none-any.whl # Install it -pip install dincli-0.1.0-py3-none-any.whl +pip install dincli-0.2.0-py3-none-any.whl ``` ### Option B — Install Directly from GitHub ```bash -pip install git+https://github.com/InfiniteZeroFoundation/devnet.git@main#subdirectory=dist +pip install "git+https://github.com/InfiniteZeroFoundation/DevNet.git@main" ``` +This builds `dincli` from the repository root (`pyproject.toml`) on `main`, the live-DevNet branch. + > for any missing dependency please install it using pip. Please see a complete dependency list in [requirements.txt](../../cache_model_0/requirements.txt) ### Verify Installation diff --git a/Documentation/public/workflows/din-workflow.md b/Documentation/public/workflows/din-workflow.md index 375ee6ed..7cb61638 100644 --- a/Documentation/public/workflows/din-workflow.md +++ b/Documentation/public/workflows/din-workflow.md @@ -4,24 +4,29 @@ In this guide we will describe the workflow of the DIN Protocol. DIN-Representative (later DIN-DAO) is an entity that is authorized to perform certain actions on behalf of the DIN Protocol. -DIN-Representative has deployed the following DIN Protocol contracts on Sepolia-Optimism testnet as part of DIN-devnet: +The DIN-Representative deploys the seven DIN platform contracts, each behind a transparent proxy (`foundry/script/DeployPlatform.s.sol`), and imports their addresses into dincli with `dincli system import-deployments`: 1. DinCoordinator 2. DinToken 3. DinValidatorStake 4. DinModelRegistry +5. DinTreasury — custodial holding contract for ETH and ERC20 assets +6. DinFeeRouter — splits the protocol fees swept to it (ETH and DIN) between the treasury and the other fee buckets +7. DinEmission — the per-GI protocol reward subsidy, on a geometric decay schedule; a model owner can fund a GI's reward pool from it (`dincli model-owner rewards fund-emission`) + +`dincli system din-info` prints the deployed addresses for the active network. ## DinCoordinator DinCoordinator is the main contract that coordinates the DIN Protocol. -1. It sets the exchange rate (1 ETH = 1M DIN tokens) between ETH and DIN tokens.(tentative workaround for now) -2. It mints DIN tokens to users (e.g. auditors / clients / aggregators) who deposit ETH via DinToken contract. -3. It allows DIN-Representative to withdraw ETH. +1. It sets the exchange rate between ETH and DIN tokens (1 ETH = 1M DIN by default; a tentative workaround for now). +2. It mints DIN tokens to users (e.g. auditors / clients / aggregators) who deposit ETH (`depositAndMint`, `dincli dintoken buy`). +3. It allows DIN-Representative to sweep the ETH received from DIN purchases to the fee router (`dincli dinrep coordinator sweep-fees`). 4. It allows DIN-Representative to add/remove slasher contracts (Model / Task level Contracts) on validator stake contract. -5. It allows DIN-Representative to update the exchange rate. -6. It allows DIN-Representative to set the validator stake contract. +5. It allows DIN-Representative to update the exchange rate, cap the total DIN that can be minted, and permanently retire the ETH faucet. +6. It allows DIN-Representative to set the validator stake, fee router and emission contracts. ## DinToken @@ -55,9 +60,8 @@ DinModelRegistry is a contract that allows users to register their models with t 2. The models have two types: a. Open-source models b. Proprietary models -3. Proprietary models have a proprietaryFee which is paid by the model-owner to the DIN Protocol, for now it is set to 0.000001 ETH. The fee is used to improve the ecosystem of the DIN Protocol. The trained proprietary models are owned by the model-owner and can be used for commercial purposes. -4. It allows DIN-Representative to update the proprietaryFee. -5. Open-source models do not have any proprietaryFee. They are free to be trained using DIN Protocol. The trained open-source models may be free for universal usage. -6. It allows model-owners to update the manifestCID of their models, potentially changing the model training logic, parameters, etc. -7. It allows to see the total number of models registered with the DIN ModelRegistry contract. -8. It allows DIN-Representative to withdraw the accumulated proprietaryFee from the DIN ModelRegistry contract. +3. Registration is a request that the DIN-Representative approves; approval assigns the model ID. Each request pays a fee in ETH, whether it is approved or rejected (spam protection). Proprietary models pay more: by default 0.00001 ETH to register (0.000001 ETH per manifest update), against 0.000001 ETH (0.0000001 ETH) for open-source models. The fees are used to improve the ecosystem of the DIN Protocol. The trained proprietary models are owned by the model-owner and can be used for commercial purposes, while trained open-source models may be free for universal usage. +4. It allows DIN-Representative to update all four fees (`dincli dinrep registry set-fees`). `dincli system get-registry-fee` shows the current values. +5. It allows model-owners to request an update to the manifestCID of their models (potentially changing the model training logic, parameters, etc.), which the DIN-Representative approves. +6. It allows to see the total number of models registered with the DIN ModelRegistry contract. +7. It allows DIN-Representative to sweep the accumulated fees from the DIN ModelRegistry contract to the fee router (`dincli dinrep registry sweep-fees`). diff --git a/Documentation/public/workflows/model-workflow.md b/Documentation/public/workflows/model-workflow.md index affdd3c0..2e568c33 100644 --- a/Documentation/public/workflows/model-workflow.md +++ b/Documentation/public/workflows/model-workflow.md @@ -38,20 +38,28 @@ In current DIN Protocol, the model owner needs to deploy a taskCoordinator contr ## 1. Deploy TaskCoordinator - Model Owner -Model Owner deploys a taskCoordinator contract specific to each model. +Model Owner deploys a taskCoordinator contract specific to each model, from the Foundry build output (`cd foundry && forge build`): ```bash -dincli model-owner deploy task-coordinator --artifact "/path/to/devnet/hardhat/artifacts/contracts/DINTaskCoordinator.sol/DINTaskCoordinator.json" +dincli model-owner deploy task-coordinator \ + --artifact "/path/to/devnet/foundry/out/DINTaskCoordinator.sol/DINTaskCoordinator.json" \ + [--model-id ] ``` +`--model-id` is the ID `DINModelRegistry` will assign when your registration is approved. It is fixed in the contract and can't be changed later. If you leave it out, dincli uses `DINModelRegistry.totalModels()`, the ID the next approval assigns, and warns you that this only holds if no other registration request is approved before yours. The deploy also points the contract at the platform `DinToken` (`setDinToken`), which dispute bonds need. + dincli will store the taskCoordinator contract address in the .env file as `SEPOLIA_OP_DEVNET_DINTaskCoordinator_Contract_Address` in your local project directory which we call `root_dir`. ## 2. Deploy TaskAuditor - Model Owner Model Owner deploys a taskAuditor contract specific to each model. ```bash -dincli model-owner deploy task-auditor --artifact "/path/to/devnet/hardhat/artifacts/contracts/DINTaskAuditor.sol/DINTaskAuditor.json" +dincli model-owner deploy task-auditor \ + --artifact "/path/to/devnet/foundry/out/DINTaskAuditor.sol/DINTaskAuditor.json" \ + [--model-id ] ``` +`--model-id` defaults to the coordinator's `modelId()`, and dincli refuses a value that doesn't match it. The deploy sets the auditor's `DinToken` (reward deposits and claims need it) and links the auditor to the coordinator. + dincli will store the taskAuditor contract address in the .env file as `SEPOLIA_OP_DEVNET__DINTaskAuditor_Contract_Address` in your local project directory which we call `root_dir`. ## 3. Request Slasher Authorization - Model Owner @@ -159,10 +167,17 @@ Each service file must be uploaded and pinned to IPFS. The resulting CID is refe ### 6.2. Create Manifest File -The manifest is a JSON file containing model metadata, contract addresses, and service entries. It must be placed at: +The manifest is a JSON file containing model metadata, contract addresses, and service entries. It must be placed in the task directory: ``` -/tasks//task_/manifest.json +/tasks///manifest.json +``` + +To start from the reference MNIST model, create the task directory and cache the default manifest, services, ABIs and requirements into it, then edit them for your model: + +```bash +dincli model-owner task create-task-dir +dincli model-owner task cache-default-artifacts ``` > For the full manifest schema, field descriptions, and an example manifest, see [manifest.md](../manifest.md). @@ -175,7 +190,7 @@ Model Owner creates and submits the genesis model to the TaskCoordinator contrac The following dincli command is used to create the genesis model: ```bash -dincli model-owner model create-genesis +dincli model-owner model create-genesis-model ``` > make sure that the manifest.json file is present at `/tasks/sepolia_op_devnet//manifest.json` before running the above command. The above dincli command will use `getGenesisModelIpfs` in `modelowner.py` service to create the genesis model and upload it to IPFS and store the IPFS CID in the .env file as `SEPOLIA_OP_DEVNET__GENESIS_MODEL_IPFS_HASH`. Please note that dincli can automatically fetch the service from IPFS using the coressponding entry for `getGenesisModelIpfs` in the manifest.json file. @@ -183,39 +198,77 @@ dincli model-owner model create-genesis The model owner can submit the genesis model to the TaskCoordinator contract using the following dincli command: ```bash -dincli model-owner model submit-genesis +dincli model-owner model submit-genesis-model [--ipfs-hash ] [--score ] ``` -> make sure that the appropriate test dataset for the model is available at `/tasks/sepolia_op_devnet//dataset/test/test_dataset.pt` before running the above command. The test dataset will be used to evaluate the genesis model and calculate the score. This score will set the threshold range for the final eligibility of local models. +> make sure that the appropriate test dataset for the model is available at `/tasks/sepolia_op_devnet//dataset/test/test_dataset.pt` before running the above command (`dincli model-owner model add-default-test-data --default-test-data` fetches the reference MNIST one). The test dataset will be used to evaluate the genesis model and calculate the score. This score will set the threshold range for the final eligibility of local models. > this command is safe to re-run. If the genesis model hash was already submitted on-chain (e.g. a prior run submitted the hash but failed before or during the score submission), re-running it detects that the hash is already set, verifies it still matches the CID you're scoring, and (re-)submits only the tier 2 score. If the on-chain hash doesn't match the CID you're submitting, it exits with an error instead of attaching a score to the wrong genesis model. -## 8. Register Model - Model Owner +## 8. Register Model - Model Owner & DIN-Representative + +Model Owner updates the manifest file at `/tasks/sepolia_op_devnet//manifest.json`, especially the `Genesis_Model_CID`, `DINTaskCoordinator_Contract`, and `DINTaskAuditor_Contract` fields with the IPFS CID of the genesis model, the DINTaskCoordinator contract address and the DINTaskAuditor contract address respectively. `validate-update-manifest` compares these fields with your `.env` and offers to fix any that differ: + +```bash +dincli model-owner model validate-update-manifest +``` -Model Owner updates the manisfest file at`/tasks/sepolia_op_devnet//manifest.json`, specially the `Genesis_Model_CID`, `DINTaskCoordinator_Contract`, and `DINTaskAuditor_Contract` fields with the IPFS CID of the genesis model, DINTaskCoordinator contract address and DINTaskAuditor contract address respectively. +Registration is a request that the DIN-Representative approves. It costs a fee in ETH, paid with the request; check it first: + +```bash +dincli system get-registry-fee --fee-type model-registry --model-type open-source # or proprietary +``` -Model Owner then register the model with the DIN Protocolat DINModelRegistry contract using the following dincli command: +**Model Owner** submits the registration request (uploads the manifest to IPFS and pays the fee): ```bash -dincli task model-owner register --isOpenSource [true/false] +dincli task model-owner register-request [--isOpenSource] +# check its status +dincli task model-owner my-requests --include-processed +dincli task model-owner show-registration-request ``` -Once the model is registered, the model is assigned a model ID. The manifest file may be updated with the model id field `Model ID` and uploaded to IPFS again. Other fields in manifest file can also be updated as per requirement. The following dincli command can be used to update the model CID in DINModelRegistry contract: +**DIN-Representative** reviews and approves (or rejects) it: ```bash -dincli task model-owner update-manifest [--modelCID ] [--manifestpath ] +dincli dinrep registry list-pending-requests --type model +dincli dinrep registry explore-request --type model +dincli dinrep registry approve-registration-request ``` -## 9. Start Global Iteration (GI) - Model Owner +Approval assigns the model ID, which is `totalModels()` at that moment. `approve-registration-request` checks that both task contracts' `modelId()` match it and refuses a mismatch unless `--force` is given. + +To change the manifest later (new service CIDs, new parameters), upload the edited manifest with a manifest-update request (it has its own fee, `--fee-type manifest-update`), which the DIN-Representative approves the same way: + +```bash +# model owner +dincli task model-owner update-manifest-request [--manifestpath | --manifestCID ] +# DIN-Representative +dincli dinrep registry list-pending-requests --type manifest +dincli dinrep registry approve-manifest-update +``` + +## 9. Fund and Start the Global Iteration (GI) - Model Owner After the model is registered, the Model Owner can initiate the Federated Learning process. The FL process is organized into Global Iterations (GI) where aggregators, auditors, and clients interact with the protocol. -The Model Owner starts a new Global Iteration for the specific model. +Each GI pays its participants from a reward pool, and `gi start` refuses a GI whose pool is empty. Fund the next GI first, either by depositing your own DIN or from the protocol emission schedule: + +```bash +# deposit DIN (buy some first with `dincli dintoken buy `) +dincli model-owner rewards deposit --amount [--gi ] +# or fund it from the DinEmission schedule +dincli model-owner rewards fund-emission [--gi ] +``` + +`--gi` defaults to the next GI. Then start it: ```bash -dincli model-owner gi start +dincli model-owner gi start [--threshold ] ``` +When pass scoring is enabled, `gi start` uses the test dataset at `/sepolia_op_devnet/model_/dataset/test/test_dataset.pt` to set the pass score. `--threshold` overrides the manifest's accuracy deduction (default 5). + --- ## 10. Aggregator Registration - Model Owner & Aggregators @@ -264,7 +317,7 @@ Similar to aggregators, the Model Owner opens auditor registration. Auditors sta dincli model-owner gi reg auditors-open ``` -**Auditors** buy tokens, stake, and register (repeat for each auditor): +**Auditors** buy tokens, stake, register, and register an encryption key (repeat for each auditor): ```bash # buy DIN tokens @@ -275,8 +328,12 @@ dincli auditor dintoken stake 10 dincli auditor dintoken read-stake # register auditor in current GI dincli auditor register +# once per wallet: generate an X25519 key and register its public key on DinValidatorStake +dincli auditor register-encryption-key ``` +The model owner encrypts each batch's test data to its auditors' keys, so an auditor without a registered key can't be given test data: `create-testdataset --submit` stops before sending anything and names any keyless auditor. A wallet that is an aggregator in this GI can't also register as an auditor. + **Model Owner** reviews and closes auditor registration: ```bash @@ -298,11 +355,13 @@ The Model Owner opens the LMS phase allowing clients to download the genesis/glo dincli model-owner lms open ``` -**Clients** train and submit their local models (repeat for each client): +**Clients** train and then submit their local models (repeat for each client): ```bash -# train and submit local model -dincli client train-lms --submit +# train a local model in the worker container (nothing is sent on-chain) +dincli client train-lms +# upload the trained model to IPFS and submit its CID +dincli client submit-lm # show submitted local model dincli client lms show-models ``` @@ -327,33 +386,32 @@ dincli model-owner lms close The Model Owner prepares evaluation batches and test data, then auditors evaluate the submitted local models to determine their quality and assign scores. -**Model Owner** prepares evaluation batches and starts evaluation: +Scores use commit-then-reveal: `evaluate --submit` commits a hidden hash of each score, and auditors reveal them in a separate window the model owner opens. Only revealed scores count. + +**Model Owner** prepares evaluation batches and test data, and starts evaluation. The GI state moves `LMSclosed` → `AuditSeedLocked` → `AuditorsBatchesCreated` → `AuditTestDataAssigned` → `LMSevaluationStarted`: > [!NOTE] -> `auditor-batches create` now waits for and locks an ungrindable, -> future-block-anchored seed before it creates the batches (issue #156 — -> prevents the model owner from timing this call to steer which auditors -> land in which batch). This adds a short automatic pause (a handful of -> blocks, ~seconds on Optimism Sepolia) before the command proceeds — no -> extra action needed, and if another process already locked the seed -> first, the wait is skipped entirely. Auditors lock the same seed from -> their side (`dincli auditor lock-seed`, or automatically via -> `lms-evaluation show-batch`), so the seed usually is already locked by -> the time the Model Owner runs this. On the `local` network this -> requires an anvil instance producing blocks on its own (`foundry/anvil.sh` -> passes `--block-time`) — an idle anvil started without block production -> never mines the anchor block, and the wait never ends. - -```bash -# create evaluation batches +> Auditor batches are drawn from a seed anchored to a future block when LMS +> closes (issue #156), so the model owner can't time the draw. Locking it is +> permissionless: any auditor can run `dincli auditor lock-seed ` +> once the anchor block is mined, and `lms-evaluation show-batch` does it +> automatically. A successful lock moves the GI to `AuditSeedLocked`. If +> nobody has locked it yet, `auditor-batches create` waits for the block +> (a few seconds on Optimism Sepolia) and locks it first. On the `local` +> network this needs an anvil that produces blocks on its own +> (`foundry/anvil.sh` passes `--block-time`); on an idle anvil the anchor +> block is never mined and the wait never ends. + +```bash +# create evaluation batches (locks the seed first if needed) dincli model-owner auditor-batches create # show evaluation batches dincli model-owner auditor-batches show -# create test dataset +# encrypt each batch's test data to its auditors' keys and assign it on-chain dincli model-owner auditor-batches create-testdataset --submit -# start evaluation +# start evaluation (opens the commit window) dincli model-owner lms-evaluation start -# show evaluation results +# show evaluation progress dincli model-owner lms-evaluation show --auditors --models ``` @@ -368,17 +426,35 @@ dincli model-owner lms-evaluation show --auditors --models > exits non-zero. Retry just those batches with the repeatable `--batch ` option, > e.g. `dincli model-owner auditor-batches create-testdataset --submit --batch 2 --batch 5`. > The flag itself is one-shot on-chain; re-running after it's already set is detected -> and skipped rather than treated as an error. +> and skipped rather than treated as an error. Setting it moves the GI to +> `AuditTestDataAssigned`, which `lms-evaluation start` requires. + +> [!NOTE] +> `create-testdataset --submit` saves each batch's key and plaintext hash to +> `/audits/testdata_keys/` (mode 0600). Keep them: you need them +> to answer a test-data dispute (`dincli model-owner disputes resolve-test-data`). -**Auditors** evaluate their assigned batches (repeat for each auditor): +**Auditors** evaluate their assigned batches and commit the scores (repeat for each auditor): ```bash # show the auditor its assigned auditor batches dincli auditor lms-evaluation show-batch -# evaluate the assigned auditor batches, automatically evalates all lms in assigned batch +# evaluate every LM in the assigned batches and commit the scores dincli auditor lms-evaluation evaluate --submit ``` +**Model Owner** closes the commit window and opens the reveal window: + +```bash +dincli model-owner lms-evaluation start-reveal +``` + +**Auditors** reveal their committed scores (repeat for each auditor, from the same machine the commit was made from: the salt is in the local commit cache): + +```bash +dincli auditor lms-evaluation reveal [--batch ] [--lmi ] +``` + **Model Owner** reviews and closes evaluation: ```bash @@ -388,6 +464,8 @@ dincli model-owner lms-evaluation show --models dincli model-owner lms-evaluation close ``` +An auditor who believes its batch's test data is wrong can open a bonded dispute: `dincli auditor dispute-test-data --batch `. See [Disputes](#17-disputes). + --- ## 14. Model Aggregation (T1 and T2) - Model Owner & Aggregators @@ -405,15 +483,15 @@ Eligible local models are aggregated hierarchically. Tier 1 (T1) aggregation com > and is still slashable for a missed submission, exactly as if they had > never submitted at all. -**Model Owner** generates T1 & T2 batches and starts T1 aggregation: +**Model Owner** generates T1 & T2 batches and starts T1 aggregation. The GI state moves `LMSevaluationClosed` → `AggSeedLocked` → `T1nT2Bcreated` → `T1AggregationStarted`: > [!NOTE] -> Same as `auditor-batches create` above, `aggregation create-t1nt2-batches` -> waits for and locks its own ungrindable, future-block-anchored seed -> (issue #156) before creating T1/T2 batches. Automatic short pause, no -> extra action needed — same `local`-network block-production caveat. -> Aggregators lock it from their side too (`dincli aggregator lock-seed`, -> or automatically via `show-t1-batches` / `show-t2-batches`). +> Same as auditor batches above: T1/T2 batches are drawn from a seed +> anchored when evaluation closes. Any aggregator can lock it +> (`dincli aggregator lock-seed `, or automatically via +> `show-t1-batches` / `show-t2-batches`), which moves the GI to +> `AggSeedLocked`; otherwise `create-t1nt2-batches` waits and locks it +> first. Same `local`-network block-production caveat. ```bash # create t1 and t2 batches @@ -480,15 +558,21 @@ dincli model-owner aggregation T2 start-reveal dincli aggregator reveal-t2 ``` -**Model Owner** closes T2 aggregation: +**Model Owner** closes T2 aggregation and scores the new global model: ```bash # show t2 batches dincli model-owner aggregation show-t2-batches --detailed # close t2 aggregation dincli model-owner aggregation T2 close +# score the final global model on your test dataset and record the score on-chain +dincli model-owner aggregation T2 set-score ``` +`set-score` doesn't change the GI state, so run it before slashing: `slash auditors` uses the score, and asks you to confirm if it still reads 0. + +Any active validator can dispute a finalized T1 or T2 batch's result within the dispute window by posting a bond: `dincli aggregator dispute --tier t1|t2 --batch `. See [Disputes](#17-disputes). + --- ## 15. Slashing & End Global Iteration - Model Owner @@ -502,6 +586,57 @@ dincli task gi show-state dincli model-owner slash auditors # slash aggregators dincli model-owner slash aggregators -# end global iteration +# end global iteration (settles the GI's rewards) dincli model-owner gi end -``` \ No newline at end of file +``` + +The GI is now `GIended`. Fund the next GI (step 9) to start it. + +## 16. Claim Rewards and Release Slots - Participants & Model Owner + +Ending the GI settles its reward pool. Each client, auditor and aggregator credits its share and then withdraws it: + +```bash +# credit your share of a settled GI +dincli rewards claim --gi +# transfer your whole claimable balance to your wallet +dincli rewards withdraw +``` + +**Model Owner** releases the ended GI's validator registration slots, once per GI. Until then those registrations count against each validator's concurrent-registration cap: + +```bash +dincli model-owner gi release-slots [--gi ] +``` + +## 17. Disputes + +Both kinds of dispute are bonded: the challenger posts a DIN bond, which is forfeited if the dispute fails. + +**Test data.** An auditor of a batch can dispute that batch's test data (for example, it received no key) until the GI's rewards settle at `gi end`: + +```bash +# auditor +dincli auditor dispute-test-data --batch +# model owner, within the dispute window: reveal the batch key and plaintext hash +dincli model-owner disputes resolve-test-data --gi --batch +# anyone, once the window has passed without an answer +dincli model-owner disputes close-expired --gi --batch +``` + +If the revealed key matches the commitment, the dispute fails and the bond is forfeited. If it doesn't, or the owner never answers (`close-expired`), the dispute is upheld: the bond goes back to the auditor, part of the GI's reward pool is taken as a penalty, and the owner must assign new test data with `dincli model-owner disputes reassign-test-data --batch `. + +**Aggregation.** Any active validator can dispute a finalized T1 or T2 batch's CID within the dispute window: + +```bash +# challenger +dincli aggregator dispute --tier t1|t2 --batch +# model owner: reject it (bond forfeited), or uphold it, which assigns a fresh subgroup of 3 aggregators +dincli model-owner disputes resolve-aggregation --gi --tier t1|t2 --batch --upheld|--rejected +# model owner, after the recomputation: confirm (the original aggregators are slashed) or dismiss (bond forfeited) +dincli model-owner disputes settle-recomputation --gi --tier t1|t2 --batch --confirmed|--dismissed +# anyone, past the resolution deadline: the fresh subgroup is slashed +dincli model-owner disputes expire --gi --tier t1|t2 --batch +``` + +A confirmed recomputation or an expired dispute credits the bond back to the challenger, who withdraws it with `dincli aggregator claim-dispute-bond `. A batch can be disputed only once. diff --git a/Documentation/technical/contracts/DINShared.md b/Documentation/technical/contracts/DINShared.md index d2a74807..6c0f2ec5 100644 --- a/Documentation/technical/contracts/DINShared.md +++ b/Documentation/technical/contracts/DINShared.md @@ -75,9 +75,10 @@ Value State Name Description [3] AwaitingGenesisModel │ setGenesisModelIpfsHash() ▼ -[4] GenesisModelCreated ◄───────────────────────────[28] GIended - │ startGI() ▲ - ▼ │ endGI() +[4] GenesisModelCreated ┌──────────────────────[28] GIended + │ startGI() ◄─────────┘ ▲ + │ (needs giRewardPool(gi) > 0) │ endGI() (settleRewards) + ▼ │ [5] GIstarted [27] AggregatorsSlashed │ startDINaggregatorsRegistration() ▲ ▼ │ slashAggregators() @@ -115,6 +116,8 @@ Value State Name Description (auditors: revealAuditScore) ``` +`startGI` runs from `GenesisModelCreated` (the first GI) or `GIended` (every later one), and reverts with `TC_GIRewardPoolNotFunded` until the GI's reward pool on `DINTaskAuditor` is funded (`depositRewards`, or `DinEmission.fundGI`). `endGI` calls `DINTaskAuditor.settleRewards`, after which participants can claim; `releaseGIRegistrationSlots(gi)` is a separate owner call on an ended GI and doesn't change the state. + T1/T2 aggregation submissions follow the same commit-then-reveal shape as LMS evaluation above: `commitT1Aggregation`/`commitT2Aggregation` during the `*AggregationStarted` (commit) state, then the model owner calls `startT1AggregationReveal`/`startT2AggregationReveal` to open `*AggregationRevealStarted`, during which aggregators call `revealT1Aggregation`/`revealT2Aggregation`. Only revealed CIDs are counted by `finalizeT1Aggregation`/`finalizeT2Aggregation`; a committed-but-never-revealed aggregator is excluded from finalization and remains slashable via `slashAggregators`' existing "no submission" (S2) check (issue #156 M-1, task_240926_18 Part C). --- diff --git a/Documentation/technical/contracts/DINTaskAuditor.md b/Documentation/technical/contracts/DINTaskAuditor.md index e32bbfe5..0620aed2 100644 --- a/Documentation/technical/contracts/DINTaskAuditor.md +++ b/Documentation/technical/contracts/DINTaskAuditor.md @@ -208,7 +208,7 @@ Read alongside the [foundry/src security review](../audits/foundry-src-security- - **No. 6 — Stale NatSpec and reused errors:** `slashAuditors` says S1 and S3 are both `minStake()` (S1 is now a fraction). Several comments call parameters "DAO-settable"; they are `onlyOwner`, i.e. set by the model owner. `setDisputePenaltyBps` reuses `TA_InvalidDisputeBond`, and `closeExpiredDispute` reuses `TA_DisputeWindowClosed` for "window still open". - **No. 7 — `modelId` is fixed at construction**, before the registry assigns it (see [DINTaskCoordinator §10 No. 4](DINTaskCoordinator.md#10-review-notes--open-caveats)). - **No. 8 — dincli lags this contract:** `dincli model-owner deploy task-auditor` still calls the older two-argument constructor (no `modelId`). -- **No. 9 — Fixed: a dincli auditor commit retry no longer loses the committed salt.** Rerunning `dincli auditor lms-evaluation evaluate --submit` used to generate a new salt and overwrite the local commit cache even when the on-chain commit already existed. The later reveal then failed the hash check, and the auditor was slashed for a missed vote. dincli now skips any LM whose `hasCommittedLM` is already set, leaving its cache untouched, and writes the cache before sending the commit tx (issue No. 202 Part 1). A rerun is safe. +- **No. 9 — Fixed: a dincli auditor commit retry no longer loses the committed salt.** Rerunning `dincli auditor lms-evaluation evaluate --submit` used to generate a new salt and overwrite the local commit cache even when the on-chain commit already existed. The later reveal then failed the hash check, and the auditor was slashed for a missed vote. dincli now skips any LM whose `hasCommittedLM` is already set, leaving its cache untouched, and writes the cache before sending the commit tx (issue No. 202 Part 1). A rerun is safe. The cache is also per wallet (`/audits/commits/
/`, and likewise `aggregations/commits/
/` for aggregators), so auditors sharing a batch on one machine no longer overwrite each other's salts; dincli still reads the old shared path, so a commit made before upgrading can be revealed. ---