The published line and the local line of this repository had no common ancestor: the public one carried the hygiene pass (no host names, no internal paths), the local one carried a month of corrections that never shipped. This commit ports the local work onto the public line, keeping the public hygiene wording wherever the two touched the same sentence, and keeping the public version of AERE-CROSS-CLIENT-DETERMINISM.md entirely. Carried: LICENSE/LICENSING corrections, VERIFY-POLICY.md, CITATIONS-UNRESOLVED.md remeasured 2026-08-11, the 'audited' adjective removed from next to Bouncy Castle, citation paths rewritten to published form, AIP-8, the QA consolidation report, the second EIP validation pass, fork-height corrections, the AereSink / threshold-factory correction, the forge test floor, and the architecture-map updates.
353 lines
22 KiB
Markdown
353 lines
22 KiB
Markdown
# Aere Compute Market V3
|
|
|
|
Proof-carrying decentralized compute (DePIN) settlement for Aere Network.
|
|
|
|
## What it is
|
|
|
|
`AereComputeMarketV3` is the on-chain verification and settlement rail for a decentralized compute
|
|
marketplace. A REQUESTER posts a job (a commitment to the workload spec, a reward held in escrow, a
|
|
deadline, and a required verification mode). A PROVIDER claims the job, runs the work off-chain, and
|
|
submits a result. The provider is paid only against verifiable evidence, never on trust alone. Which
|
|
evidence counts, and when payment releases, is decided by the job's VERIFICATION MODE.
|
|
|
|
V3 unifies the verification rails that were split across the earlier coordination layer
|
|
(`AereComputeMarketV2`, which offered a single optimistic path with Foundation arbitration) and adds a
|
|
post-quantum settlement gate. The deployed V1 and V2 DePIN contracts are untouched; V3 is a new,
|
|
independent contract.
|
|
|
|
Source: `aere-contracts/contracts/depin/AereComputeMarketV3.sol`
|
|
Tests:
|
|
- `aere-contracts/test/AereComputeMarketV3.test.js` (14 cases: safety, "nobody is paid without evidence")
|
|
- `aerenew/contracts/test/AereComputeMarketV3.liveness.test.js` (14 cases: liveness and griefing,
|
|
"no single party can freeze the escrow")
|
|
- `aere-research/formal-consensus/computemarket_smt.py` (z3 model of the escrow-solvency invariant)
|
|
|
|
MEASURED 2026-07-20, `npx hardhat test aere-contracts/test/AereComputeMarketV3.test.js test/AereComputeMarketV3.liveness.test.js`
|
|
-> `28 passing (7s)`, 0 failing.
|
|
|
|
## The three verification modes
|
|
|
|
A requester picks one mode per job. Each mode answers one question: what makes a submitted result
|
|
payable?
|
|
|
|
### REPLAY (mode 0)
|
|
|
|
The result is a deterministic function of the input. On submission the provider posts the full result
|
|
bytes, which the contract emits (and anchors as `keccak256(result)`), so any watcher can re-run the
|
|
spec locally and compare `keccak256(localResult)` against the on-chain `resultHash`. The result is
|
|
accepted after a challenge window unless a challenger posts a matching bond and disputes. On a dispute
|
|
the challenger records the `resultHash` they recomputed, so the arbiter (and any observer) can
|
|
mechanically verify who is correct. The arbiter then resolves.
|
|
|
|
When to use it. Workloads that are pure, deterministic, and cheap to re-execute (batch transforms,
|
|
deterministic simulations, reproducible builds). Disputes are objectively decidable by re-running, so
|
|
the arbiter's role is mechanical rather than judgemental.
|
|
|
|
### ZK_VERIFIED (mode 1)
|
|
|
|
The result carries a zero-knowledge proof, verified ON-CHAIN through the existing deployed SP1 gateway
|
|
verifier. The provider submits the SP1 public values (ABI-encoded as `(bytes32 specHash, bytes32
|
|
resultHash)`) and the proof. The contract binds the proof to the job by requiring the proven `specHash`
|
|
to equal the job's committed spec, records the proven `resultHash`, then calls the gateway's
|
|
`verifyProof`. The reward releases in the SAME transaction, and ONLY if the proof verifies. There is no
|
|
other code path that pays a `ZK_VERIFIED` job, so paying one without a valid proof is impossible.
|
|
|
|
When to use it. Workloads where correctness must be enforced without trusting a challenge window or an
|
|
arbiter: verifiable inference, zk coprocessing, anything where the requester wants finality on delivery
|
|
rather than after a delay. The cost is that the provider must run a real prover.
|
|
|
|
The verifier reference. V3 calls the `ISP1Verifier` interface
|
|
(`aere-contracts/contracts/zkverify/ISP1Verifier.sol`), the same interface implemented by the
|
|
deployed `SP1VerifierGateway` at `0x9ca479C8c52C0EbB4599319a36a5a017BCC70628` on Aere Network chain
|
|
2800. V3 does not reimplement proof verification; it references and calls the existing gateway. The
|
|
gateway routes on the proof's first four bytes to the correct SP1 verifier and reverts on an invalid
|
|
proof, which is exactly the fail-closed behavior V3 relies on.
|
|
|
|
### OPTIMISTIC (mode 2)
|
|
|
|
The result is accepted after a challenge window unless a challenger posts a bond and disputes. A
|
|
successful dispute slashes the PROVIDER bond to the CHALLENGER and refunds the reward to the requester.
|
|
Unlike REPLAY, the result is not assumed cheaply re-derivable, so the provider stakes a bond as skin in
|
|
the game and the challenge is a general fraud claim rather than a mechanical recomputation.
|
|
|
|
When to use it. Workloads that are checkable but not cheaply reproducible (large or non-deterministic
|
|
pipelines, results that are expensive to recompute but easy to spot-check). The bond sizes the cost of
|
|
lying.
|
|
|
|
## Post-quantum settlement path
|
|
|
|
Any job in any mode can set `pqcSettlement = true`. When set, the final release of funds additionally
|
|
requires a Falcon-512 signature over a domain-separated settlement digest binding `(chainId, contract,
|
|
jobId, provider, token, amount, resultHash)`. The signature is verified IN FULL on-chain by the live
|
|
native precompile at `0x0AE1` (activated on Aere mainnet 2800 at block 9,189,161), using the same input
|
|
encoding proven against the live precompile in `AerePQCMessageVerifier`.
|
|
|
|
### Whose key, and why it matters
|
|
|
|
The settlement key is the PROVIDER's, and the provider registers it when it claims the job. This is the
|
|
single most consequential design decision in the PQC path, so it is worth stating why.
|
|
|
|
The property being bought is: a quantum adversary who has broken the provider's classical secp256k1
|
|
identity still cannot make this contract pay out that provider's earnings, because the payout also
|
|
needs a Falcon private key that Shor's algorithm does not reach. That hardens the highest-value
|
|
authorization in the system, which is the one that moves money to a new owner.
|
|
|
|
Binding the key to the REQUESTER instead would have been actively harmful. The requester would gain a
|
|
permanent veto over paying for correct work: it could simply never sign, and the provider could never
|
|
be paid. That converts a solved failure mode (a permissionless `finalize` means the buyer's cooperation
|
|
is never required) back into an unsolved one. An earlier revision of this contract had the key on the
|
|
requester; it was moved to the provider precisely because of this.
|
|
|
|
### Where PQC is deliberately NOT used
|
|
|
|
Posting, claiming, submitting, disputing and arbitration are all plain ECDSA, on purpose.
|
|
|
|
None of those operations move value to a new owner. The worst a forged claim or submission achieves is
|
|
the loss of the forger's own bond. Disputes are adjudicated on evidence (a recomputed result hash),
|
|
not on who signed the challenge. Adding Falcon signatures to those paths would cost calldata and gas
|
|
and buy no additional guarantee. A design that reaches for post-quantum signatures on every entrypoint
|
|
is marketing, not engineering, so this one does not.
|
|
|
|
### Two scope boundaries, stated plainly
|
|
|
|
CONSENSUS IS NOT POST-QUANTUM. Aere consensus is classical secp256k1 ECDSA QBFT. Blocks are produced
|
|
and sealed by classical validator signatures. The post-quantum material in this contract is at the
|
|
signature and settlement layer only. Nothing here changes block production.
|
|
|
|
THE ZK PROOFS ARE NOT POST-QUANTUM. The SP1 gateway verifies Groth16/PLONK proofs over the BN254
|
|
pairing curve. BN254 security rests on the hardness of discrete logarithms, which Shor's algorithm
|
|
breaks. A `ZK_VERIFIED` job's proof is therefore CLASSICAL and Shor-breakable, and the on-chain
|
|
verifier is a classical verifier.
|
|
|
|
The consequence is specific and should not be glossed: setting `pqcSettlement = true` on a
|
|
`ZK_VERIFIED` job hardens WHO MAY RECEIVE the payout. It does NOT make the correctness proof
|
|
quantum-safe. Against an adversary with a cryptographically relevant quantum computer, that adversary
|
|
could forge a BN254 proof for a false result, and the Falcon gate would then faithfully authorize
|
|
payment for provably-wrong work to the legitimate provider key. The combination reads stronger than it
|
|
is, which is exactly why it is written out here rather than left implicit.
|
|
|
|
If you need post-quantum correctness rather than post-quantum payout authorization, the honest answer
|
|
today is REPLAY mode, whose security rests on keccak256 (a hash, with only a Grover square-root
|
|
speedup, not a Shor break) plus the ability of any watcher to re-execute.
|
|
|
|
## Escrow-solvency guarantee
|
|
|
|
The contract tracks `totalLiabilities[token]` for every asset: the sum of open job rewards plus posted
|
|
bonds in that asset. Every escrow or bond increments it; every payout, refund, or slash decrements it by
|
|
the same amount, with effects applied before transfers. The invariant
|
|
|
|
```
|
|
balanceOf(contract, token) >= totalLiabilities[token] for every asset
|
|
```
|
|
|
|
therefore holds at all times, where `token == address(0)` is native AERE. The public view `isSolvent`
|
|
checks it. Rewards settle in native AERE or an allowlisted ERC-20; provider and challenger bonds are
|
|
always native AERE, so solvency is tracked per asset. Fee-on-transfer or rebasing reward tokens are
|
|
rejected at escrow time (the contract requires the received amount to equal the stated reward).
|
|
|
|
The test asserts `isSolvent` (and the raw balance-versus-liability comparison) after every mutating step
|
|
of every scenario, including a mixed batch of jobs across all three modes carried to their terminal
|
|
states.
|
|
|
|
## Fail-closed properties
|
|
|
|
- No double-pay. Every job reaches a terminal status (`Paid`, `Refunded`, `Slashed`) exactly once. All
|
|
fund-moving entrypoints are reentrancy-guarded and set the terminal status before any transfer.
|
|
- No pay-without-proof in ZK_VERIFIED. Settlement happens inside `submitResultZK`, after the gateway
|
|
`verifyProof` call. An invalid proof reverts the whole transaction.
|
|
- No admin drain. There is no owner and no sweep. The arbiter can only route a DISPUTED job's escrow
|
|
between its requester, provider, and challenger. Governance can only flip a token allowlist boolean.
|
|
Neither can withdraw escrowed funds.
|
|
- Deadlines. A claimed job that misses its deadline without a submission lets the requester reclaim the
|
|
reward and slashes the provider bond to the requester.
|
|
|
|
## Failure modes
|
|
|
|
A marketplace that only works when everyone behaves is not a marketplace. These are the ways this one
|
|
is attacked, and what happens in each case. Each has a test in
|
|
`test/AereComputeMarketV3.liveness.test.js` unless marked otherwise.
|
|
|
|
### The provider takes the job and vanishes
|
|
|
|
The provider posts a bond to claim. If the deadline passes with no submission, `reclaimExpired` returns
|
|
the reward to the requester AND slashes the provider's bond to the requester. Vanishing is strictly
|
|
loss-making, and the requester is compensated for the wasted deadline. A late submission is refused.
|
|
|
|
Residual risk: a provider can still grief by claiming jobs it never intends to run, burning the
|
|
requester's time until each deadline expires. The bond prices this but does not prevent it. A
|
|
reputation layer or a per-provider claim limit would; neither is in V3.
|
|
|
|
### The buyer refuses to acknowledge correct work
|
|
|
|
Fully solved for non-PQC jobs, and it is the reason `finalize` exists. Once the challenge window
|
|
closes, `finalize` is PERMISSIONLESS: any address, including the provider itself or an unrelated
|
|
bystander, can call it and the reward is released. The requester's cooperation is never required and
|
|
the requester has no veto. `acceptResult` exists only as an early-release convenience.
|
|
|
|
For a PQC job the same holds, because the required signature is the PROVIDER's, not the requester's.
|
|
The requester still cannot block payment. This is the direct payoff of that key-ownership decision.
|
|
|
|
### The provider never produces its Falcon authorization
|
|
|
|
A PQC job can only be paid with the provider's Falcon signature. If the provider loses the key or
|
|
simply stops, the reward would sit in escrow forever. `reclaimUnsettled` closes this: after the
|
|
challenge window plus `PQC_SETTLEMENT_GRACE` (7 days), the requester reclaims the reward and the
|
|
provider's bond is RETURNED to the provider, not slashed.
|
|
|
|
The bond is returned deliberately. Failing to sign is not proven fraud, so slashing would punish what
|
|
may be simple key loss. The provider forfeits the reward, which puts the entire cost of silence on the
|
|
only party that holds the key and wants the money. Before the grace period elapses this path reverts,
|
|
so a requester cannot use it to dodge paying for correct work.
|
|
|
|
### The arbiter never resolves a dispute
|
|
|
|
This was the worst hole in the design, and it is worth being blunt: an arbitrated escrow whose arbiter
|
|
goes offline, is coerced, or is censored freezes the reward AND both bonds permanently, with no
|
|
recovery. `resolveByTimeout` closes it. After `ARBITRATION_TIMEOUT` (14 days) ANY address can unwind a
|
|
stale dispute NEUTRALLY: the reward returns to the requester, and both bonds return to their posters.
|
|
|
|
Nothing is slashed, because nothing was adjudicated. An absent arbiter must not be able to enrich
|
|
either side by doing nothing, since otherwise "make the arbiter unavailable" becomes a strategy. The
|
|
z3 model carries a negative control showing that a timeout unwind which tries to pick a winner
|
|
under-backs the escrow.
|
|
|
|
Residual risk: this weakens the dispute system into "a dispute the arbiter ignores becomes a no-sale".
|
|
A provider who did correct work and was frivolously challenged loses the reward if the arbiter never
|
|
rules. That is a real cost, accepted because permanent fund lock is worse. Arbiter liveness remains a
|
|
trust assumption; V3 bounds the damage rather than removing it.
|
|
|
|
### A challenger is right but nobody is watching
|
|
|
|
NOT SOLVED, and this is the honest weak point of both optimistic modes.
|
|
|
|
The security of REPLAY and OPTIMISTIC rests entirely on at least one honest party re-running the work
|
|
and disputing within the window. If nobody watches, a provider can submit garbage and be paid by
|
|
`finalize` with no recourse. The contract cannot manufacture a watcher.
|
|
|
|
What V3 does provide: the full result bytes are emitted on-chain for inline jobs, so watching requires
|
|
no privileged access or private data feed; and a successful challenge pays the challenger the entire
|
|
provider bond, so watching is profitable in proportion to that bond. What it does NOT provide: any
|
|
guarantee that a watcher exists, any subsidy for watching a job that turns out to be honest, or any
|
|
staking of watchers. The requester's practical defence is to be its own watcher, or to size the
|
|
challenge window long enough for a third party to act.
|
|
|
|
Requesters who cannot rely on a watcher existing should use `ZK_VERIFIED`, which needs no watcher at
|
|
all, and pay the proving cost. That is the real tradeoff between the modes.
|
|
|
|
### The job output is too large to put on chain
|
|
|
|
A 40 GB tensor checkpoint does not fit in calldata. A job can declare `offchainResult = true`, and the
|
|
provider then calls `submitResultRef(id, resultHash, uri)`: the chain stores the binding keccak256
|
|
COMMITMENT, and the URI is a retrieval hint.
|
|
|
|
DATA AVAILABILITY IS NOT SOLVED BY THIS. The contract cannot check that the URI resolves, that it keeps
|
|
resolving, or that its contents hash to `resultHash`. If the provider serves nothing, a challenger
|
|
cannot replay the work. The design's answer is that an unavailable result is indistinguishable from a
|
|
wrong one and should be disputed as such; off-chain jobs remain disputable on identical terms. That is
|
|
a coherent answer, not a complete one. Requesters who cannot tolerate it should require inline results
|
|
or `ZK_VERIFIED`.
|
|
|
|
### Other paths
|
|
|
|
- Double-pay: every job reaches a terminal status exactly once; a second payout is guard-infeasible
|
|
(proved in the z3 model; all fund-moving entrypoints are reentrancy-guarded).
|
|
- Admin drain: there is no owner and no sweep. The arbiter can only route a DISPUTED job's escrow among
|
|
that job's own requester, provider and challenger. Governance can only flip a token allowlist boolean.
|
|
- Replay of a Falcon authorization: the digest binds chainId, contract, jobId, provider, token, amount
|
|
and resultHash, so an authorization cannot be reused for another job, chain, contract, or figure.
|
|
- Fee-on-transfer or rebasing reward tokens: rejected at escrow time.
|
|
|
|
## Job lifecycle (summary)
|
|
|
|
```
|
|
postJob Open requester escrows reward (+ mode / pqc / offchain params)
|
|
claimJob Claimed provider posts the required native-AERE bond (0 for ZK) and,
|
|
for a pqc job, registers ITS OWN Falcon-512 key
|
|
submitResult Submitted REPLAY / OPTIMISTIC inline: result bytes emitted, window starts
|
|
submitResultRef Submitted REPLAY / OPTIMISTIC off-chain: (hash, URI) committed, window starts
|
|
submitResultZK Paid ZK_VERIFIED: proof verified on-chain, paid in the same tx
|
|
acceptResult Paid requester accepts a Submitted result early
|
|
finalize Paid ANYONE, after the window closes with no dispute
|
|
dispute Disputed challenger posts a matching bond within the window
|
|
resolveDispute Paid/Slashed arbiter rules; a bad result slashes the provider bond to the challenger
|
|
resolveByTimeout Refunded ANYONE, after ARBITRATION_TIMEOUT: neutral unwind of a stale dispute
|
|
reclaimUnsettled Refunded requester, after the window + PQC_SETTLEMENT_GRACE, if the provider
|
|
never produced its Falcon authorization (bond returned, not slashed)
|
|
cancelJob Refunded requester reclaims an unclaimed job's escrow
|
|
reclaimExpired Refunded requester reclaims a claimed job that blew its deadline (bond slashed)
|
|
```
|
|
|
|
Every job has an exit that no single party can block. That is the liveness claim, and each clause of it
|
|
has a test.
|
|
|
|
## What V3 does NOT solve
|
|
|
|
Stated flatly, because a design document that only lists strengths is a brochure.
|
|
|
|
1. It does not create compute supply. Real GPU and accelerator capacity, the off-chain provers, and
|
|
real SP1 proving are EXTERNAL to this contract [MEASURE]. V3 is a settlement and verification rail.
|
|
A rail with no providers is not a market, and this contract cannot make providers appear.
|
|
2. It does not guarantee a watcher exists. Both optimistic modes are only as safe as the most attentive
|
|
honest party. See the failure mode above.
|
|
3. It does not solve data availability for large outputs. `submitResultRef` commits to a hash and a
|
|
retrieval hint, nothing more.
|
|
4. It does not make ZK proofs quantum-safe. On-chain verification is classical BN254 and Shor-breakable.
|
|
5. It does not make Aere consensus post-quantum. Consensus is classical secp256k1 ECDSA QBFT.
|
|
6. It does not remove the arbiter as a trust assumption. It bounds the damage an absent arbiter can do
|
|
(14 days, then a neutral unwind), but a present and dishonest arbiter can still rule wrongly on any
|
|
dispute it resolves in time. There is no appeal, no arbiter bond, and no arbiter slashing.
|
|
7. It does not price compute, match buyers to sellers, or rank providers. There is no reputation, no
|
|
discovery, and no order book. A requester must already know which provider it wants, or accept
|
|
whoever claims first.
|
|
8. It does not prevent claim-squatting, as described above.
|
|
9. It does not verify that a job spec is meaningful, or that `specHash` corresponds to anything a
|
|
provider can actually run. The commitment is opaque to the contract by design.
|
|
10. It is not audited and not deployed.
|
|
|
|
## Honest status
|
|
|
|
- Contract: built, compiles, tested. `AereComputeMarketV3.sol` compiles under solc 0.8.23 (repo
|
|
standard). MEASURED 2026-07-20: `npx hardhat compile` printed `Compiled 1 Solidity file successfully
|
|
(evm target: paris)`; `npx hardhat test aere-contracts/test/AereComputeMarketV3.test.js
|
|
test/AereComputeMarketV3.liveness.test.js` printed `28 passing (7s)`, 0 failing.
|
|
- Formal: `aere-research/formal-consensus/computemarket_smt.py` proves the escrow-solvency invariant
|
|
inductively over the modelled transitions, including the two new exit paths, with 4 negative controls
|
|
that fire as expected. BOUNDARY: this models the DESIGN accounting, not the compiled EVM bytecode.
|
|
- ZK verification path [VERIFY]: exercised against `MockSp1Verifier`, which mirrors the deployed gateway
|
|
semantics (reverts on an invalid proof). The reference verifier is the deployed `SP1VerifierGateway`
|
|
at `0x9ca479C8c52C0EbB4599319a36a5a017BCC70628`; wiring V3 to it is a deploy-time constructor
|
|
argument. Real SP1 proving has NOT been run against V3 [MEASURE].
|
|
- Falcon settlement path [VERIFY]: exercised against `MockPQCPrecompile` at `0x0AE1`, which parses the
|
|
Falcon-512 spec offsets. Real Falcon signing has NOT been run against V3. The wire encoding is
|
|
separately KAT-proven in `AerePQCMessageVerifier` and against the live mainnet precompile. On mainnet
|
|
2800 the precompile at `0x0AE1` is live.
|
|
- DEPLOYMENT DEPENDENCY: a `pqcSettlement` job is unsettleable on any chain where `0x0AE1` is not a live
|
|
Falcon-512 precompile, because `_falconVerify` fails closed. On such a chain the escrow would only
|
|
exit via `reclaimUnsettled`. V3 must therefore be deployed on Aere mainnet 2800 (or a testnet
|
|
carrying the precompiles), not on a generic EVM chain.
|
|
- Real compute supply [MEASURE]: adoption, not code, exactly like validator decentralization.
|
|
- No new token. Rewards, escrow, bonds and payment are native AERE or an allowlisted existing ERC-20.
|
|
- NOT DEPLOYED, NOT AUDITED. Built for publication and review. Deployment is FOUNDER-GATED.
|
|
|
|
## Relationship to V1 and V2 (deployed, untouched)
|
|
|
|
| | V1 `AereComputeMarket` | V2 `AereComputeMarketV2` | V3 (this) |
|
|
|---|---|---|---|
|
|
| Address (chain 2800) | `0xf0c8178a5d9feb0f70C5f184e79edeEDaddcF350` | `0x33E3B06A7344f0B201fdD11B18bC244c84dbca32` | not deployed |
|
|
| Deployed | 2026-07-07 | 2026-07-09 | founder-gated |
|
|
| Verification | optimistic + Foundation arbitration | same, plus on-chain spec/result bytes | per-job REPLAY / ZK_VERIFIED / OPTIMISTIC |
|
|
| Provider bond | stake floor | configurable stake floor | per-job bond, slashable to challenger |
|
|
| Reward asset | native AERE | native AERE | native AERE or allowlisted ERC-20 |
|
|
| Arbiter absent | escrow locked | escrow locked | neutral unwind after 14 days |
|
|
| Large outputs | inline only | inline only | inline or (hash, URI) commitment |
|
|
| PQ payout gate | none | none | optional Falcon-512 via `0x0AE1` |
|
|
| Admin sweep | `sweepSlashPool` (Foundation) | `sweepSlashPool` (Foundation) | none |
|
|
|
|
V1 and V2 remain live and untouched. V2's real shortcoming was not that it was broken: three genuine
|
|
end-to-end settlements ran against it on mainnet on 2026-07-09 (see
|
|
`deployments/compute-market-e2e.json`, jobs 0, 1 and 2, all reaching status 5 = Paid). The shortcoming
|
|
was that verification was a single fixed optimistic path with the Foundation as arbiter, so the
|
|
guarantee was identical whether the work was cheaply replayable or needed a real proof, and an
|
|
unresponsive arbiter had no timeout. V3 makes the guarantee a per-job choice and gives every path a
|
|
bounded exit.
|