Skip to content

feat(client): resolve-before-pay for commitment-bound quotes (ADR-0003)#126

Open
grumbach wants to merge 1 commit into
WithAutonomi:mainfrom
grumbach:adr-0003-quote-commitment-resolve
Open

feat(client): resolve-before-pay for commitment-bound quotes (ADR-0003)#126
grumbach wants to merge 1 commit into
WithAutonomi:mainfrom
grumbach:adr-0003-quote-commitment-resolve

Conversation

@grumbach

Copy link
Copy Markdown
Contributor

ADR-0003: commitment-bound quote pricing — client side.

Implements "the client pays nothing it cannot resolve". Before paying, the client runs the full binding check on every quote and candidate, so a node that overstates its storage to inflate its price is dropped before any on-chain payment instead of after.

What

For each single-node quote and each merkle candidate, the client now:

  • verifies the quote's own ML-DSA-65 signature and that it is for the requested content;
  • checks the (committed_key_count, commitment_pin) shape, the count cap, and that price == calculate_price(count) by exact recomputation;
  • for a bound quote, fully resolves the shipped commitment: parse it, check it is bound to the quoting peer, verify its signature, that it hashes to the quote's pin, and that its key_count matches the claimed count.

Anything unresolvable, withheld, off-curve, or contradictory is dropped before payment — exactly as the storer would reject it. The verified commitments are then forwarded as sidecars in the PUT bundle (single-node and merkle) so storers cross-check synchronously; sidecar blobs are size-capped before parsing. Pricing and commitment verification come from ant-protocol, so client and node never disagree.

Tests

Adds an e2e test (real QUIC nodes + Anvil) proving bound quotes are shipped, priced, fully resolve, and round-trip; the off-curve / forged-commitment rejection is covered in unit tests.

Release ordering

Depends on evmlib WithAutonomi/evmlib#11, ant-protocol WithAutonomi/ant-protocol#15, and ant-node WithAutonomi/ant-node#149. Built locally via temporary [patch.crates-io] path patches + a local ant-node path dep (not committed here); will not build standalone until those publish.

Implement the client half of ADR-0003: the client pays nothing it cannot
resolve. Before paying, it runs the full binding check on every quote and
candidate, so a node that overstates its storage to inflate its price is
dropped before any on-chain payment instead of after.

For each single-node quote and each merkle candidate, the client now:
- verifies the quote's own ML-DSA-65 signature and that it is for the
  requested content;
- checks the (committed_key_count, commitment_pin) shape, the count cap,
  and that price == calculate_price(count) by exact recomputation; and
- for a bound quote, fully resolves the shipped commitment: parse it,
  check it is bound to the quoting peer, verify its signature, that it
  hashes to the quote's pin, and that its key_count matches the claimed
  count.
Anything unresolvable, withheld, off-curve, or contradictory is dropped
before payment, exactly as the storer would reject it.

The verified commitments are then forwarded as sidecars in the PUT bundle
(single-node and merkle) so storers cross-check synchronously. Sidecar
blobs are size-capped before parsing. Pricing and the commitment
verification come from ant-protocol, so client and node never disagree.

Adds an e2e test (real QUIC nodes + Anvil) proving bound quotes are
shipped, priced, fully resolve, and round-trip; and the off-curve /
forged-commitment rejection is covered in unit tests.

Depends on the evmlib, ant-protocol, and ant-node ADR-0003 releases; will
not build standalone until those publish.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant