From d157cdfc4bc9b47c3b768b7a06e08feb63a3bb25 Mon Sep 17 00:00:00 2001 From: echobt <154886644+echobt@users.noreply.github.com> Date: Wed, 21 Oct 2026 08:57:49 +0000 Subject: [PATCH 1/3] feat(ledger): add pinned production bootstrap issuance A run with ledger_mode="production" had no issuance path at all: test_genesis is test-only, shadow bootstrap is CPU/test-only, so a production run could never fund an admission lock. EconomicsPolicyV2 gains an optional bootstrap_allocation_hash (production only, omitted when unset so every existing policy digest and run ID is unchanged). EscrowV2.production_bootstrap accepts one coordinator-signed ProductionBootstrap per run: idempotent per operation_id, conflict on changed content, refused for a second bootstrap, a wrong authority, an allocation other than the pin, or when bootstrap + issued + reserved shadow units exceed max_total_issuance. Origins are issued with a NULL hotkey, so payable() never emits them; they are collateral like genesis. The manifest_v2 example gets --ledger-mode production, which pins a bootstrap allocation instead of a test genesis. Rejected: opening the shadow path to CUDA/production (it mints per trial reward rather than a pinned, capped one-time allocation). Co-Authored-By: Claude Haiku 5.5 --- src/hypertrain/ledger/escrow_v2.py | 63 +++++- src/hypertrain/ops/manifest_v2.py | 12 +- src/hypertrain/protocol/messages_v2.py | 24 ++ tests/ledger/test_production_bootstrap_v2.py | 224 +++++++++++++++++++ tests/ops/test_manifest_v2.py | 12 + 5 files changed, 327 insertions(+), 8 deletions(-) create mode 100644 tests/ledger/test_production_bootstrap_v2.py diff --git a/src/hypertrain/ledger/escrow_v2.py b/src/hypertrain/ledger/escrow_v2.py index 7564350..22d1e52 100644 --- a/src/hypertrain/ledger/escrow_v2.py +++ b/src/hypertrain/ledger/escrow_v2.py @@ -1,6 +1,7 @@ """Conserved origin units. SQLite event journal and receipts commit with bucket changes. No legacy entitlement import, external deposit, client mint or client slash exists. +Production issuance outside rewards is one coordinator-signed, policy-pinned bootstrap. The service supplies authenticated finality/replay and settlement from its own records. """ @@ -35,6 +36,7 @@ EscrowTransfer, Hex64, OriginAllocation, + ProductionBootstrap, RewardFinalize, RunManifestV2, ShadowReservationRequestV1, @@ -55,7 +57,9 @@ def digest(model: BaseModel) -> str: return body_digest(model.model_dump(mode="json")) -def authority_message(model: TestGenesis | RewardFinalize | ShadowRewardFinalizeV1) -> bytes: +def authority_message( + model: TestGenesis | ProductionBootstrap | RewardFinalize | ShadowRewardFinalizeV1, +) -> bytes: """Origin authority signature is independent of the enclosing envelope signer.""" return ( b"hypertrain/origin/2|" @@ -76,6 +80,10 @@ def genesis_origin_id(run_id: str, allocation_hash: str, index: int) -> str: return sha256_hex(f"ht-origin-genesis-v2|{run_id}|{allocation_hash}|{index}".encode()) +def bootstrap_origin_id(run_id: str, allocation_hash: str, index: int) -> str: + return sha256_hex(f"ht-origin-bootstrap-v1|{run_id}|{allocation_hash}|{index}".encode()) + + def reward_origin_id(run_id: str, w: int, hotkey: str, finalize_hash: str) -> str: return sha256_hex(f"ht-origin-reward-v2|{run_id}|{w}|{hotkey}|{finalize_hash}".encode()) @@ -306,7 +314,9 @@ def _event(self, operation_id: str, kind: str, request: str, owner: str) -> Escr self.db.execute("INSERT INTO escrow_snapshots VALUES(?,?)", (operation_id, state)) return receipt - def _authority(self, model: TestGenesis | RewardFinalize | ShadowRewardFinalizeV1) -> None: + def _authority( + self, model: TestGenesis | ProductionBootstrap | RewardFinalize | ShadowRewardFinalizeV1 + ) -> None: if model.run_id != self.run_id or not verify( decode_hotkey(self.policy.reward_authority), authority_message(model), @@ -351,6 +361,51 @@ def test_genesis(self, genesis: TestGenesis) -> EscrowReceipt: self._issue(o, None, None) return self._event(operation, "TEST_GENESIS", request, genesis.origins[0].owner) + def production_bootstrap(self, bootstrap: ProductionBootstrap) -> EscrowReceipt: + """One pinned production issuance per run; collateral like genesis, never emission.""" + self._authority(bootstrap) + with self.tx(): + request = bootstrap.model_dump_json(exclude={"authority_sig"}) + old = self._existing(bootstrap.operation_id, request) + if old is not None: + return old + if ( + self.policy.ledger_mode != "production" + or self.policy.bootstrap_allocation_hash is None + or self.db.execute( + "SELECT 1 FROM escrow_events WHERE kind='PRODUCTION_BOOTSTRAP'" + ).fetchone() + ): + raise EscrowError("PRODUCTION_BOOTSTRAP_FORBIDDEN") + alloc = [(o.owner, o.units, o.mature_at) for o in bootstrap.origins] + if ( + bootstrap.allocation_hash != self.policy.bootstrap_allocation_hash + or genesis_allocation_hash(alloc) != bootstrap.allocation_hash + ): + raise EscrowError("BOOTSTRAP_ALLOCATION") + pending = self.db.execute( + "SELECT COUNT(*) FROM records_v2 WHERE run_id=? AND kind='shadow-reservation' " + "AND json_extract(data,'$.accepted') IS NULL", + (self.run_id,), + ).fetchone()[0] + if ( + self.balances().issued + + pending * self.policy.round_reward_units + + bootstrap.total_units + > self.policy.max_total_issuance + ): + raise EscrowError("TOTAL_ISSUANCE_BUDGET") + for i, o in enumerate(bootstrap.origins): + if o.origin_id != bootstrap_origin_id(self.run_id, bootstrap.allocation_hash, i): + raise EscrowError("BOOTSTRAP_ORIGIN_DOMAIN") + self._issue(o, None, None) # hotkey NULL: payable() never emits these units + return self._event( + bootstrap.operation_id, + "PRODUCTION_BOOTSTRAP", + request, + bootstrap.origins[0].owner, + ) + def reward_allocations( self, reward: RewardFinalize | ShadowRewardFinalizeV1, evidence: FinalityEvidence ) -> tuple[OriginAllocation, ...]: @@ -973,8 +1028,8 @@ def pay(self, op: EscrowOperation, *, signer: str) -> EscrowReceipt: def payable(self, now_beacon: int) -> list[sqlite3.Row]: """Free units of live reward origins matured by now_beacon, oldest maturity first. - Shadow (bootstrap) and genesis origins are collateral, never emission. Only units still - held by the origin's issued owner pay (its emptied reward_pending row marks it): units + Shadow, production-bootstrap and genesis origins are collateral, never emission. Only units + still held by the origin's issued owner pay (its emptied reward_pending row marks it): units transferred to another owner or a referee are not the earning hotkey's to emit. """ return self.db.execute( diff --git a/src/hypertrain/ops/manifest_v2.py b/src/hypertrain/ops/manifest_v2.py index 7db2d17..b5f7835 100644 --- a/src/hypertrain/ops/manifest_v2.py +++ b/src/hypertrain/ops/manifest_v2.py @@ -153,7 +153,7 @@ def _build(args: argparse.Namespace) -> dict[str, JsonValue]: return index -def _example() -> dict[str, bytes]: +def _example(ledger_mode: str = "test") -> dict[str, bytes]: coord, auditor0, auditor1, referee, relay, cold, other = ( encode_hotkey(bytes([i]) * 32) for i in range(1, 8) ) @@ -197,8 +197,10 @@ def _example() -> dict[str, bytes]: max_object_bytes=1_000_000, max_body_bytes=65536, max_chunk_manifest_bytes=1048576 ), ) + allocation = genesis_allocation_hash([(cold, 20000, 1), (other, 10000, 1)]) + production = ledger_mode == "production" economics = EconomicsPolicyV2( - ledger_mode="test", + ledger_mode="production" if production else "test", G_max_units=100, R_collectible_units=100, S_min_units=1000, @@ -206,11 +208,12 @@ def _example() -> dict[str, bytes]: gammaV_units=0, s_lower_ppm=1_000_000, q_floor=1_000_000, - genesis_allocation_hash=genesis_allocation_hash([(cold, 20000, 1), (other, 10000, 1)]), + genesis_allocation_hash=None if production else allocation, reward_authority=coord, round_reward_units=1_000_000, max_total_issuance=20_000_000, shadow_bootstrap_rounds=12, + bootstrap_allocation_hash=allocation if production else None, ) aggregation = AggregationPolicyV2( arithmetic="flat-cclip-cap-v1", @@ -295,13 +298,14 @@ def main(argv: list[str] | None = None) -> int: build.add_argument("--state-dir", type=Path) example = sub.add_parser("example", help="write tiny CPU inputs with public placeholders") example.add_argument("--out", type=Path, required=True) + example.add_argument("--ledger-mode", choices=("test", "production"), default="test") try: args = parser.parse_args(argv) if args.cmd == "build": result = _build(args) else: _check_out(args.out) - files = _example() + files = _example(args.ledger_mode) _write(args.out, files) result = {"files": {name: sha256_hex(raw) for name, raw in files.items()}} except ValidationError as error: diff --git a/src/hypertrain/protocol/messages_v2.py b/src/hypertrain/protocol/messages_v2.py index def64c3..6fee11a 100644 --- a/src/hypertrain/protocol/messages_v2.py +++ b/src/hypertrain/protocol/messages_v2.py @@ -582,11 +582,15 @@ class EconomicsPolicyV2(WireModel): round_reward_units: U64 max_total_issuance: U64 shadow_bootstrap_rounds: Literal[12] + # Omitted when absent so every policy digest (and run ID) predating it is unchanged. + bootstrap_allocation_hash: Hex64 | None = Field(None, exclude_if=lambda v: v is None) @model_validator(mode="after") def _mode(self) -> EconomicsPolicyV2: if (self.ledger_mode == "test") != (self.genesis_allocation_hash is not None): raise ValueError("only test mode requires pinned genesis allocation") + if self.bootstrap_allocation_hash is not None and self.ledger_mode != "production": + raise ValueError("only production mode pins a bootstrap allocation") return self @@ -730,6 +734,25 @@ def _conservation(self) -> TestGenesis: return self +class ProductionBootstrap(WireModel): + """Coordinator-signed one-time production issuance, pinned by bootstrap_allocation_hash.""" + + run_id: Hex64 + operation_id: Hex64 + allocation_hash: Hex64 + total_units: Positive + origins: Annotated[list[OriginAllocation], Field(min_length=1, max_length=1024)] + authority_sig: Annotated[str, StringConstraints(pattern=r"^[0-9a-f]{128}$")] + + @model_validator(mode="after") + def _conservation(self) -> ProductionBootstrap: + if len({o.origin_id for o in self.origins}) != len(self.origins): + raise ValueError("duplicate bootstrap origin") + if sum(o.units for o in self.origins) != self.total_units: + raise ValueError("bootstrap allocations do not conserve total") + return self + + class RewardFinalize(WireModel): run_id: Hex64 w: U64 @@ -939,6 +962,7 @@ def _loser(self) -> ResolutionV2: DisputePolicyV2, AuditPolicyV2, TestGenesis, + ProductionBootstrap, RewardFinalize, EscrowLock, ShadowRewardFinalizeV1, diff --git a/tests/ledger/test_production_bootstrap_v2.py b/tests/ledger/test_production_bootstrap_v2.py new file mode 100644 index 0000000..73dfd1b --- /dev/null +++ b/tests/ledger/test_production_bootstrap_v2.py @@ -0,0 +1,224 @@ +"""Production bootstrap issuance: pinned, signed, once per run, collateral never emission.""" + +from __future__ import annotations + +import importlib.util +import sys +from dataclasses import replace +from pathlib import Path + +import pytest +from pydantic import ValidationError + +from hypertrain.ledger.escrow_v2 import ( + Balances, + EscrowError, + Settlement, + authority_message, + bootstrap_origin_id, + digest, + genesis_allocation_hash, +) +from hypertrain.protocol.messages_v2 import ( + EconomicsPolicyV2, + EscrowTransfer, + OriginAllocation, + ProductionBootstrap, + RunManifestV2, +) + +_spec = importlib.util.spec_from_file_location( + "bootstrap_escrow_fixture", Path(__file__).parent / "test_escrow_v2.py" +) +assert _spec is not None and _spec.loader is not None +E = importlib.util.module_from_spec(_spec) +sys.modules[_spec.name] = E +_spec.loader.exec_module(E) + +ALLOC = [(E.COLD.ss58, 20000, 1), (E.OTHER.ss58, 10000, 1)] +OP = "44" * 32 + + +def pinned(s, alloc=ALLOC, **update): + """Production setup whose economics pins `alloc`; the run ID follows the new policy.""" + policy = EconomicsPolicyV2.model_validate( + {**s.policy.body(), "bootstrap_allocation_hash": genesis_allocation_hash(alloc), **update} + ) + body = s.manifest.body() + body["network"]["economics_policy_hash"] = digest(policy) + return replace(s, policy=policy, manifest=RunManifestV2.model_validate(body)) + + +def bootstrap(run_id, alloc=ALLOC, operation=OP, signer=E.COORD) -> ProductionBootstrap: + ah = genesis_allocation_hash(alloc) + unsigned = ProductionBootstrap( + run_id=run_id, + operation_id=operation, + allocation_hash=ah, + total_units=sum(u for _, u, _ in alloc), + origins=[ + OriginAllocation( + origin_id=bootstrap_origin_id(run_id, ah, i), owner=h, units=u, mature_at=m + ) + for i, (h, u, m) in enumerate(alloc) + ], + authority_sig="0" * 128, + ) + return unsigned.model_copy( + update={"authority_sig": signer.sign(authority_message(unsigned)).hex()} + ) + + +def test_bootstrap_conserves_and_survives_restart(tmp_path: Path) -> None: + # Given + s = pinned(E.setup("production")) + e = E.ledger(s, tmp_path / "ledger.db") + b = bootstrap(e.run_id) + # When + e.production_bootstrap(b) + e.mature(E.H, tuple(o.origin_id for o in b.origins), 1) + # Then: per-origin and global conservation hold, also after the chain is re-verified. + assert e.balances() == Balances(30000, 30000, 0, 0, 0, 0, 0) + assert e.balances(E.COLD.ss58).available == 20000 + reopened = E.ledger(s, tmp_path / "ledger.db") + assert reopened.balances().issued == 30000 and reopened.balances().conserved() + kinds = [r["kind"] for r in e.db.execute("SELECT kind FROM escrow_events ORDER BY seq")] + assert kinds == ["PRODUCTION_BOOTSTRAP", "MATURE"] + + +def test_bootstrap_above_total_issuance_rejected(tmp_path: Path) -> None: + s = pinned(E.setup("production"), max_total_issuance=29_999) + e = E.ledger(s, tmp_path / "ledger.db") + with pytest.raises(EscrowError, match="TOTAL_ISSUANCE_BUDGET"): + e.production_bootstrap(bootstrap(e.run_id)) + assert e.balances().issued == 0 + assert e.db.execute("SELECT COUNT(*) FROM escrow_events").fetchone()[0] == 0 + + +def test_bootstrap_idempotent_per_operation_and_once_per_run(tmp_path: Path) -> None: + # Given + s = pinned(E.setup("production")) + e = E.ledger(s, tmp_path / "ledger.db") + b = bootstrap(e.run_id) + first = e.production_bootstrap(b) + # When / Then: exact replay returns the stored receipt and issues nothing more. + assert e.production_bootstrap(bootstrap(e.run_id)) == first + assert e.balances().issued == 30000 + # Same operation_id, different content. + other = [(E.COLD.ss58, 30000, 1)] + with pytest.raises(EscrowError, match="OPERATION_CONFLICT"): + e.production_bootstrap(bootstrap(e.run_id, other)) + # A second bootstrap under a fresh operation_id. + with pytest.raises(EscrowError, match="PRODUCTION_BOOTSTRAP_FORBIDDEN"): + e.production_bootstrap(bootstrap(e.run_id, operation="55" * 32)) + assert e.balances().issued == 30000 + assert e.db.execute("SELECT COUNT(*) FROM escrow_events").fetchone()[0] == 1 + + +@pytest.mark.parametrize("fault", ["signer", "run", "allocation", "unpinned", "test_mode"]) +def test_bootstrap_rejects_unpinned_or_unauthorized(tmp_path: Path, fault: str) -> None: + # Given + s = E.setup("test" if fault == "test_mode" else "production") + if fault != "unpinned" and fault != "test_mode": + s = pinned(s) + e = E.ledger(s, tmp_path / "ledger.db") + run_id = "ab" * 32 if fault == "run" else e.run_id + alloc = [(E.COLD.ss58, 30000, 1)] if fault == "allocation" else ALLOC + b = bootstrap(run_id, alloc, signer=E.OTHER if fault == "signer" else E.COORD) + # When / Then + with pytest.raises(EscrowError): + e.production_bootstrap(b) + assert e.balances().issued == 0 + + +def test_bootstrap_policy_pins_reward_authority_and_mode(tmp_path: Path) -> None: + s = E.setup("production") + # reward_authority must stay the coordinator (escrow_v2 PINNED_AUTHORITIES). + wrong = pinned(s, reward_authority=E.OTHER.ss58) + with pytest.raises(EscrowError, match="PINNED_AUTHORITIES"): + E.ledger(wrong, tmp_path / "ledger.db") + # A test-mode policy cannot carry a bootstrap pin. + test = E.setup("test") + with pytest.raises(ValidationError, match="only production mode pins"): + EconomicsPolicyV2.model_validate( + {**test.policy.body(), "bootstrap_allocation_hash": genesis_allocation_hash(ALLOC)} + ) + # An unpinned policy keeps its pre-existing digest (no new key serialized). + assert "bootstrap_allocation_hash" not in s.policy.body() + + +# One unit over half the fixture's 2e6 cap: bootstrap plus one live award cannot both fit. +BIG = [(E.COLD.ss58, 1_000_001, 1)] + + +@pytest.fixture(scope="module") +def bootstrapped_reward(tmp_path_factory): + """Real signed live w=0 reward (1e6 units) for a run whose policy pins BIG.""" + original = E.setup + try: + E.setup = lambda mode="production": pinned(original(mode), BIG) + return E.actual_reward.__wrapped__(tmp_path_factory) + finally: + E.setup = original + + +def reward_ledger(s, path, reward): + return E.ledger( + s, + path, + replay=E.verified_shadow, + settlement=lambda _: Settlement( + finality_hash=reward.finalize_hash, + closed_dispute_root=E.H, + release_beacon=20, + unresolved=False, + outcome="MATCH", + ), + ) + + +def test_reward_after_bootstrap_cannot_exceed_cap(tmp_path: Path, bootstrapped_reward) -> None: + s, evidence, reward = bootstrapped_reward + assert s.policy.max_total_issuance == 2_000_000 + e = reward_ledger(s, tmp_path / "ledger.db", reward) + e.production_bootstrap(bootstrap(e.run_id, BIG)) + with pytest.raises(EscrowError, match="TOTAL_ISSUANCE_BUDGET"): + e.reward_finalize(reward, evidence) + assert e.balances().issued == 1_000_001 and e.balances().conserved() + assert e.db.execute("SELECT COUNT(*) FROM escrow_finalized").fetchone()[0] == 0 + + +def test_bootstrap_after_reward_cannot_exceed_cap(tmp_path: Path, bootstrapped_reward) -> None: + s, evidence, reward = bootstrapped_reward + e = reward_ledger(s, tmp_path / "ledger.db", reward) + e.reward_finalize(reward, evidence) + with pytest.raises(EscrowError, match="TOTAL_ISSUANCE_BUDGET"): + e.production_bootstrap(bootstrap(e.run_id, BIG)) + assert e.balances().issued == 1_000_000 and e.balances().conserved() + # The matured live award is payable; nothing else was issued. + e.mature(E.H, tuple(reward.origin_ids), 20) + assert [r["origin"] for r in e.payable(10**9)] == reward.origin_ids + + +def test_bootstrap_units_never_payable(tmp_path: Path) -> None: + # Given: matured bootstrap units, some transferred to another owner. + s = pinned(E.setup("production")) + e = E.ledger(s, tmp_path / "ledger.db") + b = bootstrap(e.run_id) + e.production_bootstrap(b) + e.mature(E.H, tuple(o.origin_id for o in b.origins), 1) + e.transfer( + EscrowTransfer( + operation_id="33" * 32, + owner=E.COLD.ss58, + recipient=E.HOT.ss58, + units=500, + origin_ids=[b.origins[0].origin_id], + admission_id=None, + dispute_id=None, + ), + signer=E.COLD.ss58, + ) + # When / Then: free, matured units exist, yet get_weights has nothing to emit. + assert e.balances().available == 30000 + assert e.payable(10**9) == [] diff --git a/tests/ops/test_manifest_v2.py b/tests/ops/test_manifest_v2.py index 69245ba..0332ddb 100644 --- a/tests/ops/test_manifest_v2.py +++ b/tests/ops/test_manifest_v2.py @@ -277,3 +277,15 @@ def test_build_refuses_corrupt_existing_object( assert captured.err == "error: object store contains corrupt content\n" assert path.read_bytes() == b"corrupt" assert not (tmp_path / "output" / "manifest-envelope.json").exists() + + +def test_production_example_pins_bootstrap_not_test_genesis(tmp_path: Path) -> None: + from hypertrain.protocol.messages_v2 import EconomicsPolicyV2 + + out = tmp_path / "production" + assert main(["example", "--ledger-mode", "production", "--out", str(out)]) == 0 + policies = json.loads((out / "policies.json").read_text()) + economics = EconomicsPolicyV2.model_validate(policies["economics"]) + assert economics.ledger_mode == "production" + assert economics.genesis_allocation_hash is None + assert economics.bootstrap_allocation_hash is not None From 3d154952cc34671ca5c66f6ef25fa520b2e41484 Mon Sep 17 00:00:00 2001 From: echobt <154886644+echobt@users.noreply.github.com> Date: Wed, 21 Oct 2026 08:57:49 +0000 Subject: [PATCH 2/3] feat(challenge): route production bootstrap and economic-bound writer POST /v2/runs/{run_id}/admin/bootstrap hands a coordinator-signed ProductionBootstrap envelope to the escrow after the run's services resolve (production refuses the CPU backend there) and after the latest beacon round passes the admission BLS check. Nothing wrote the records_v2 economic-bound row that production eligibility reads, so no production miner could ever become eligible. POST /v2/runs/{run_id}/admin/economic-bound writes it once, coordinator-signed and bound to the economics policy hash, only when trust_v2.economic_bound holds q_floor*s*beta*(R+S) >= G on the pinned policy; a false bound answers 409 and writes nothing. Later calls return the stored record; one bound to another policy answers 409. docs/network-v2.md and docs/operator.md describe the production path and that a test-ledger run hosted on the production challenge steers real emission once its first live reward matures. Co-Authored-By: Claude Haiku 5.5 --- docs/network-v2.md | 34 ++++ docs/operator.md | 2 +- src/hypertrain/challenge/app.py | 11 ++ src/hypertrain/challenge/store.py | 48 +++++ src/hypertrain/challenge/trust_v2.py | 11 ++ .../challenge/test_production_economics_v2.py | 183 ++++++++++++++++++ 6 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 tests/challenge/test_production_economics_v2.py diff --git a/docs/network-v2.md b/docs/network-v2.md index 00f6356..1d124e2 100644 --- a/docs/network-v2.md +++ b/docs/network-v2.md @@ -166,6 +166,40 @@ No automatic migration is provided; separate operator resolution is required. Funding uses signed `EscrowLock` via `POST /v2/runs/{run_id}/escrow/lock`, not a CLI `--bond` flag. Test genesis has pinned nonfinancial origins; production mode has separate reward authority/issuance bounds and no test-genesis conversion. + +Production funding is one coordinator-signed `ProductionBootstrap`, posted as an +`ht/2` envelope to `POST /v2/runs/{run_id}/admin/bootstrap` (admin bearer). The +run's `EconomicsPolicyV2.bootstrap_allocation_hash` pins its owner/units/maturity +list (`genesis_allocation_hash` over `[owner, units, mature_at]`); only +`ledger_mode="production"` may set it, and an unset field is omitted, so earlier +policy digests and run IDs are unchanged. Origins are +`ht-origin-bootstrap-v1|run|allocation_hash|index`. The ledger accepts it once per +run: the same `operation_id` and body replay the stored receipt, the same +`operation_id` with other content answers `OPERATION_CONFLICT`, and any second +bootstrap answers `PRODUCTION_BOOTSTRAP_FORBIDDEN`. It is refused when the inner +authority signature is not `reward_authority` (pinned to `coord_pubkey`), when +the envelope signer is not the coordinator, when the allocation differs from the +pin, when bootstrap plus issued and reserved shadow units would exceed +`max_total_issuance` (`TOTAL_ISSUANCE_BUDGET`; later rewards share the same cap), +when the run has no CUDA qualification (production refuses the CPU backend) and +when the latest beacon round is not BLS-verified (`UNVERIFIED_BEACON`). +Bootstrap units mature on the beacon loop and can be locked or transferred; +like genesis units they are collateral and never pay through `get_weights`. + +Production eligibility also needs the run's `economic-bound` record. `POST +/v2/runs/{run_id}/admin/economic-bound` (admin bearer, no body) writes it once, +coordinator-signed, only when the pinned policy satisfies +`q_floor*s_lower*beta*(R_collectible+S_min) >= G_max` in exact ppm integers +(`challenge/trust_v2.py:economic_bound`); otherwise it answers 409 and writes +nothing. The record binds the economics policy hash; later calls return it +unchanged, and a stored record for another policy answers 409. + +A test-ledger run published on the production challenge steers real emission: +as soon as its first live round finalizes and its reward matures, those units +enter `get_weights` like any production reward +(`tests/challenge/test_v2_weights_bridge.py::test_v2_matured_reward_reaches_get_weights`). +`ledger_mode="test"` does not keep a run out of on-chain weights; do not host a +test-ledger run on the production challenge unless that emission is intended. Rewards are issued only through accepted finality, uniquely tracked by origin, then mature after vesting/dispute conditions. Transfers preserve origin units; fraud burns collectible exposure rather than redistributing it. Shadow work does diff --git a/docs/operator.md b/docs/operator.md index 4b82e00..5f60ece 100644 --- a/docs/operator.md +++ b/docs/operator.md @@ -202,7 +202,7 @@ uv run --frozen python -m hypertrain.ops.manifest_v2 build \ --exp-round 1000000 --state-dir /tmp/state --out /tmp/out ``` -The example's `coord_pubkey`, two auditors, referees, `reward_authority` and relay public key are **placeholder SS58 public identities, not operational keys**. Replace them before a real run; `coord_pubkey` must match the service's K_coord. The example uses a tiny decoder, `ledger_mode="test"`, a pinned genesis allocation hash and one `.test` relay. It creates no dataset, genesis funding or training round. Custom CPU/GPU runs use the same three JSON shapes; provide valid model dimensions and parameter count, an audit budget of `2H`, and the H/step-bound-derived audit lease. Build computes `init_state_hash`; an existing value must match. It also rejects economics whose `reward_authority` differs from `training.coord_pubkey` (`PINNED_AUTHORITIES`) or whose `round_reward_units` differs from `training.budget.epochs_per_round * 1_000_000` (`MANIFEST_REWARD_BUDGET`). The service's configured auditor set must match `training.auditors`; the offline CLI cannot validate that configuration. Building needs the existing `trainer` extra (`uv sync --frozen --extra trainer`); help and example do not. +The example's `coord_pubkey`, two auditors, referees, `reward_authority` and relay public key are **placeholder SS58 public identities, not operational keys**. Replace them before a real run; `coord_pubkey` must match the service's K_coord. The example uses a tiny decoder, `ledger_mode="test"`, a pinned genesis allocation hash and one `.test` relay. It creates no dataset, genesis funding or training round. `example --ledger-mode production` instead writes a production economics policy pinning a placeholder bootstrap allocation (`bootstrap_allocation_hash`, no genesis); funding then uses `POST /v2/runs/{run_id}/admin/bootstrap` and `POST /v2/runs/{run_id}/admin/economic-bound` (see [network-v2.md](network-v2.md)). A test-ledger run hosted on the production challenge steers real emission once its first live reward matures; keep test-mode runs off the production challenge unless that is intended. Custom CPU/GPU runs use the same three JSON shapes; provide valid model dimensions and parameter count, an audit budget of `2H`, and the H/step-bound-derived audit lease. Build computes `init_state_hash`; an existing value must match. It also rejects economics whose `reward_authority` differs from `training.coord_pubkey` (`PINNED_AUTHORITIES`) or whose `round_reward_units` differs from `training.budget.epochs_per_round * 1_000_000` (`MANIFEST_REWARD_BUDGET`). The service's configured auditor set must match `training.auditors`; the offline CLI cannot validate that configuration. Building needs the existing `trainer` extra (`uv sync --frozen --extra trainer`); help and example do not. The owner seed is an existing private, current-user-owned 0600 file containing 32 raw bytes or 64 hex characters; it is read through the miner's checked loader, never printed or copied. The shared loader strips leading/trailing ASCII whitespace bytes: provide hex for any raw seed whose first or last byte is ASCII whitespace. Choose an expiry drand round later than submission. Both commands require a new or empty output directory. Build writes `manifest.json`, `manifest-envelope.json`, five `policy-.json` files, `relay-registry.json` and `index.json`. The index records `run_id`, `owner_ss58`, six canonical object hashes and hashes of the eight other files; it excludes its own hash. diff --git a/src/hypertrain/challenge/app.py b/src/hypertrain/challenge/app.py index 984e787..efc9f86 100644 --- a/src/hypertrain/challenge/app.py +++ b/src/hypertrain/challenge/app.py @@ -570,6 +570,17 @@ async def genesis_v2(run_id: str, request: Request, authorization: Auth = None) admin(authorization) return await run(store.for_run(run_id).genesis_v2, run_id, await v2_raw(request)) + @app.post("/v2/runs/{run_id}/admin/bootstrap") + async def bootstrap_v2(run_id: str, request: Request, authorization: Auth = None) -> Any: + admin(authorization) + hosted = store.for_run(run_id) + return await run(hosted.production_bootstrap_v2, run_id, await v2_raw(request)) + + @app.post("/v2/runs/{run_id}/admin/economic-bound") + async def economic_bound_v2(run_id: str, authorization: Auth = None) -> Any: + admin(authorization) + return await run(store.for_run(run_id).economic_bound_v2, run_id) + @app.post("/v2/runs/{run_id}/admin/rounds") async def open_v2(run_id: str, request: Request, authorization: Auth = None) -> Any: admin(authorization) diff --git a/src/hypertrain/challenge/store.py b/src/hypertrain/challenge/store.py index 176cba1..f1f7914 100644 --- a/src/hypertrain/challenge/store.py +++ b/src/hypertrain/challenge/store.py @@ -4145,6 +4145,54 @@ def genesis_v2(self, run_id: str, raw: bytes) -> dict[str, JsonValue]: ) return receipt.body() + def production_bootstrap_v2(self, run_id: str, raw: bytes) -> dict[str, JsonValue]: + """Pinned production issuance; units mature on the beacon loop, never pay out.""" + from hypertrain.protocol.messages_v2 import ProductionBootstrap + + escrow, admission, _ = self._services(run_id) # production refuses CPU here + with self._tx(): + admission._beacon(self._now(self._db)) # production requires a BLS-verified round + model = self._authenticated_v2(run_id, raw, "ProductionBootstrap", self._coord().ss58) + assert isinstance(model, ProductionBootstrap) + return escrow.production_bootstrap(model).body() + + def economic_bound_v2(self, run_id: str) -> dict[str, JsonValue]: + """Write the immutable coordinator-signed record only when trust_v2 holds the bound.""" + from hypertrain.challenge.trust_v2 import economic_bound + from hypertrain.protocol.messages import Receipt + + escrow, _, _ = self._services(run_id) + with self._tx(): + row = self._db.execute( + "SELECT data FROM records_v2 WHERE run_id=? AND kind='economic-bound' AND id='run'", + (run_id,), + ).fetchone() + if row is not None: + stored: dict[str, JsonValue] = json.loads(row[0]) + if stored["economics_policy_hash"] != escrow.manifest.network.economics_policy_hash: + raise ChallengeError(409, "immutable economic-bound record conflicts") + return stored + policy = escrow.policy + if policy.ledger_mode != "production": + raise ChallengeError(409, "economic-bound record is production only") + if not economic_bound(policy): + raise ChallengeError(409, "economic bound q*s*beta*(R+S)>=G fails") + evidence: dict[str, JsonValue] = { + "run_id": run_id, + "economics_policy_hash": escrow.manifest.network.economics_policy_hash, + "bound": "q*s*beta*(R+S)>=G", + } + now = self._now(self._db) + receipt = Receipt( + w=0, commit_hash=sha256_hex(canonicalize(evidence)), received_round=max(now, 1) + ) + record = { + **evidence, + "receipt": envelope_v2.seal(self._coord(), "Receipt", run_id, receipt, NEVER), + } + self._put_record_v2(run_id, "economic-bound", "run", record) + return record + def _service_profile_v2(self, run_id: str) -> _ServiceCapacityV1: """Derive the sole admitted tiny shape; never allocate tensors.""" manifest = self._run_v2(run_id) diff --git a/src/hypertrain/challenge/trust_v2.py b/src/hypertrain/challenge/trust_v2.py index 9cbb179..ba77a6d 100644 --- a/src/hypertrain/challenge/trust_v2.py +++ b/src/hypertrain/challenge/trust_v2.py @@ -145,6 +145,17 @@ def audit_floor( return AuditFloor(min(q, 1_000_000), required, allowed) +def economic_bound(policy: EconomicsPolicyV2) -> bool: + """Run-level q*s*beta*(R+S)>=G at the pinned audit floor; exact ppm integers.""" + return ( + policy.q_floor + * policy.s_lower_ppm + * policy.beta_ppm + * (policy.R_collectible_units + policy.S_min_units) + >= policy.G_max_units * 10**18 + ) + + @dataclass(frozen=True, slots=True) class AuditSelection: selected: bool diff --git a/tests/challenge/test_production_economics_v2.py b/tests/challenge/test_production_economics_v2.py new file mode 100644 index 0000000..c8d583b --- /dev/null +++ b/tests/challenge/test_production_economics_v2.py @@ -0,0 +1,183 @@ +"""Hosted production bootstrap route and economic-bound record writer.""" + +from __future__ import annotations + +import importlib.util +import json +import sys +from pathlib import Path + +import pytest + +from hypertrain.challenge.admission_store import AdmissionError +from hypertrain.challenge.store import ChallengeError, ChallengeStore +from hypertrain.data.store import LocalFSStore +from hypertrain.ledger import Params +from hypertrain.protocol.envelope_v2 import UnauthorizedSigner, seal, verify_envelope +from hypertrain.protocol.jcs import canonicalize +from hypertrain.protocol.messages_v2 import DisputePolicyV2, RunManifestV2 + +_spec = importlib.util.spec_from_file_location( + "production_economics_fixture", + Path(__file__).parents[1] / "ledger/test_production_bootstrap_v2.py", +) +assert _spec is not None and _spec.loader is not None +B = importlib.util.module_from_spec(_spec) +sys.modules[_spec.name] = B +_spec.loader.exec_module(B) +E = B.E + + +def hosted(tmp_path: Path, monkeypatch, *, cuda: bool, **economics): + """Production run in a real store; `cuda` stands in for an installed CUDA qualification.""" + s = B.pinned(E.setup("production"), **economics) + dispute = DisputePolicyV2( + referees=[E.OTHER.ss58], + max_open=32, + max_transcript_entries=256, + max_entry_bytes=65536, + fanout=2, + max_referee_reassignments=1, + max_referee_cost_units=100, + ) + body = s.manifest.body() + body["network"]["dispute_policy_hash"] = dispute.digest() + manifest = RunManifestV2.model_validate(body) + objects = LocalFSStore(tmp_path / "objects") + for policy in (s.policy, s.admission_policy, dispute): + assert objects.put(canonicalize(policy.body())) == policy.digest() + store = ChallengeStore( + tmp_path / "state", + Params("hypertrain", manifest.training.beacon.genesis_time, 300, 1, 1), + E.COORD, + None, + lambda payload: None, + objects, + ) + store._db.execute( + "INSERT INTO runs VALUES(?,?,?,'created',NULL)", + (manifest.run_id(), manifest.model_dump_json(), "{}"), + ) + if cuda: + monkeypatch.setattr(store, "_backend_v2", lambda m: "cuda") + return store, manifest.run_id() + + +def beacon(store, number: int, *, bls: bool) -> None: + store._db.execute( + "INSERT INTO beacon VALUES(?,?,?,?)", (number, "aa" * 48, "bb" * 32, int(bls)) + ) + + +def signed(run_id: str, signer=E.COORD) -> bytes: + return canonicalize(seal(signer, "ProductionBootstrap", run_id, B.bootstrap(run_id), 10000)) + + +@pytest.fixture +def close(): + stores = [] + yield stores.append + for store in stores: + store.close_v2_notifications() + store.close() + + +def issued(store) -> int: + return store._db.execute("SELECT COALESCE(SUM(issued),0) FROM escrow_origins").fetchone()[0] + + +def test_bootstrap_route_refuses_cpu_backend(tmp_path, monkeypatch, close) -> None: + store, run_id = hosted(tmp_path, monkeypatch, cuda=False) + close(store) + beacon(store, 1, bls=True) + with pytest.raises(ChallengeError, match="production CUDA qualification required"): + store.production_bootstrap_v2(run_id, signed(run_id)) + # Refused before any escrow service (or ledger table) exists for the run. + assert store._services_v2 == {} + assert ( + store._db.execute("SELECT 1 FROM sqlite_master WHERE name='escrow_origins'").fetchone() + is None + ) + + +def test_bootstrap_route_requires_bls_beacon(tmp_path, monkeypatch, close) -> None: + # Given: an unverified (fixture/HTTP-relayed) latest beacon round. + store, run_id = hosted(tmp_path, monkeypatch, cuda=True) + close(store) + beacon(store, 1, bls=False) + # When / Then + with pytest.raises(AdmissionError, match="UNVERIFIED_BEACON"): + store.production_bootstrap_v2(run_id, signed(run_id)) + assert issued(store) == 0 + # A BLS-verified round lets the same signed request through, once. + beacon(store, 2, bls=True) + receipt = store.production_bootstrap_v2(run_id, signed(run_id)) + assert receipt["ledger_mode"] == "production" + assert issued(store) == 30000 + + +def test_bootstrap_route_rejects_wrong_envelope_signer(tmp_path, monkeypatch, close) -> None: + store, run_id = hosted(tmp_path, monkeypatch, cuda=True) + close(store) + beacon(store, 1, bls=True) + with pytest.raises(UnauthorizedSigner): + store.production_bootstrap_v2(run_id, signed(run_id, E.OTHER)) + assert issued(store) == 0 + + +def test_economic_bound_refused_when_bound_false(tmp_path, monkeypatch, close) -> None: + # Given: q*s*beta*(R+S) = 1100 units < G = 1101. + store, run_id = hosted(tmp_path, monkeypatch, cuda=True, G_max_units=1101) + close(store) + beacon(store, 1, bls=True) + _, admission, _ = store._services(run_id) + # When / Then + with pytest.raises(ChallengeError, match="economic bound"): + store.economic_bound_v2(run_id) + assert ( + store._db.execute("SELECT COUNT(*) FROM records_v2 WHERE kind='economic-bound'").fetchone()[ + 0 + ] + == 0 + ) + assert admission.conservative_bound() is False + + +def test_economic_bound_written_once_and_immutable(tmp_path, monkeypatch, close) -> None: + # Given: q*s*beta*(R+S) = 1100 units >= G = 1100 (exact boundary). + store, run_id = hosted(tmp_path, monkeypatch, cuda=True, G_max_units=1100) + close(store) + beacon(store, 1, bls=True) + _, admission, _ = store._services(run_id) + assert admission.conservative_bound() is False + # When + record = store.economic_bound_v2(run_id) + raw = store._db.execute( + "SELECT data FROM records_v2 WHERE kind='economic-bound' AND id='run'" + ).fetchone()[0] + # Then: coordinator-signed, admission now sees the bound. + assert record["receipt"]["signer"] == E.COORD.ss58 and verify_envelope(record["receipt"]) + assert admission.conservative_bound() is True + # A later call (new beacon, fresh randomized signature possible) never rewrites it. + beacon(store, 2, bls=True) + assert store.economic_bound_v2(run_id) == record + after = store._db.execute( + "SELECT data FROM records_v2 WHERE kind='economic-bound' AND id='run'" + ).fetchone()[0] + assert after == raw + # A stored record bound to another policy is a conflict, not silently replaced. + store._db.execute( + "UPDATE records_v2 SET data=json_set(data,'$.economics_policy_hash',?) " + "WHERE kind='economic-bound'", + ("ff" * 32,), + ) + with pytest.raises(ChallengeError, match="immutable economic-bound"): + store.economic_bound_v2(run_id) + assert ( + json.loads( + store._db.execute("SELECT data FROM records_v2 WHERE kind='economic-bound'").fetchone()[ + 0 + ] + )["economics_policy_hash"] + == "ff" * 32 + ) From f8742e92ff3508bc6f4dd7176761ac94f8ada9b3 Mon Sep 17 00:00:00 2001 From: echobt <154886644+echobt@users.noreply.github.com> Date: Wed, 21 Oct 2026 20:33:08 +0000 Subject: [PATCH 3/3] test(ledger): guard the bootstrap issuance cap at its boundary Lens found two surviving mutants on the cap check in production_bootstrap: removing the pending shadow-reservation term and turning '>' into '>='. Add the exact-at-cap case and a pending reservation case at one unit short and at an exact fit. Both mutants now fail a test; no change under src/. Co-Authored-By: Claude Sonnet 5.5 --- tests/ledger/test_production_bootstrap_v2.py | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/ledger/test_production_bootstrap_v2.py b/tests/ledger/test_production_bootstrap_v2.py index 73dfd1b..726cd93 100644 --- a/tests/ledger/test_production_bootstrap_v2.py +++ b/tests/ledger/test_production_bootstrap_v2.py @@ -222,3 +222,39 @@ def test_bootstrap_units_never_payable(tmp_path: Path) -> None: # When / Then: free, matured units exist, yet get_weights has nothing to emit. assert e.balances().available == 30000 assert e.payable(10**9) == [] + + +def test_bootstrap_exactly_at_total_issuance_is_accepted(tmp_path: Path) -> None: + # Boundary: total == cap passes, 29_999 (above) is rejected in the test above. + s = pinned(E.setup("production"), max_total_issuance=30_000) + e = E.ledger(s, tmp_path / "ledger.db") + e.production_bootstrap(bootstrap(e.run_id)) + assert e.balances().issued == 30_000 and e.balances().conserved() + + +def _pending_reservation(e) -> None: + """A reserved, not yet accepted shadow round: it will mint round_reward_units.""" + e.db.execute( + "INSERT INTO records_v2 VALUES(?,?,?,?)", + (e.run_id, "shadow-reservation", "0", '{"binding":{},"accepted":null}'), + ) + + +@pytest.mark.parametrize("cap_slack,accepted", [(-1, False), (0, True)]) +def test_bootstrap_counts_pending_shadow_reservation_against_cap( + tmp_path: Path, cap_slack: int, accepted: bool +) -> None: + # Given: a pending reservation holds round_reward_units of the cap. + base = E.setup("production") + cap = 30_000 + base.policy.round_reward_units + cap_slack + s = pinned(base, max_total_issuance=cap) + e = E.ledger(s, tmp_path / "ledger.db") + _pending_reservation(e) + # When / Then: bootstrap + reservation must fit; one unit short is refused, exact fit passes. + if accepted: + e.production_bootstrap(bootstrap(e.run_id)) + assert e.balances().issued == 30_000 + else: + with pytest.raises(EscrowError, match="TOTAL_ISSUANCE_BUDGET"): + e.production_bootstrap(bootstrap(e.run_id)) + assert e.balances().issued == 0