Skip to content

fix: verify only paid quotes in SingleNode payment model#1

Closed
jacderida wants to merge 1 commit into
mainfrom
fix/verify-only-paid-quotes
Closed

fix: verify only paid quotes in SingleNode payment model#1
jacderida wants to merge 1 commit into
mainfrom
fix/verify-only-paid-quotes

Conversation

@jacderida

Copy link
Copy Markdown
Owner

Summary

  • The SingleNode payment model pays only the median-priced quote (3x) and sends Amount::ZERO for the other 4
  • evmlib::pay_for_quotes() filters out zero-amount payments, so only 1 quote has an on-chain record
  • The verifier was using verify_data_payment() which fails if ANY result is isValid=false, causing every upload to fail because the 4 unpaid quotes have no on-chain record
  • Fix: call the contract's verifyPayment() directly and require that at least one result is valid (the paid quote), rather than requiring all results to be valid

Test plan

  • Verified on 74-node testnet: uploads that previously failed with "Payment verification failed on-chain" now succeed
  • Existing unit tests pass

🤖 Generated with Claude Code

The SingleNode payment model pays only the median-priced quote (3x) and
sends Amount::ZERO for the other 4. evmlib's pay_for_quotes() filters
out zero-amount payments, so only 1 quote has an on-chain record.

The verifier was using verify_data_payment() which fails if ANY result
is isValid=false — causing every upload to fail because the 4 unpaid
quotes have no on-chain record.

Fix: call the contract's verifyPayment() directly and require that at
least one result is valid (the paid quote), rather than requiring all
results to be valid.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jacderida jacderida closed this Mar 19, 2026
jacderida added a commit that referenced this pull request Jun 8, 2026
… delta

PR WithAutonomi#122 made pricing and the freshness gate read the same record source, but
uploads on a fresh, rapidly-filling testnet (STG-01, 0.11.6-rc.2) still failed
~100%. The residual cause is the freshness gate itself.

The gate compared the price-derived quoted record count against the node's
current count with a fixed `max(5, 5%)` tolerance, symmetrically (abs_diff). Two
problems on an actively-replicating network:

1. Tolerance too tight for normal in-flight churn. Between a node quoting and
   verifying a payment (the client collects 7 quotes/chunk, pays on-chain via
   Arbitrum, then PUTs — several seconds) the node's record count drifts by a
   handful of records via replication. Sampled STG-01 rejects had a median
   delta of 8 — just over the floor of 5. At low/moderate fill the pricing
   curve is nearly flat, so that drift is a negligible price change, yet it was
   rejected.

2. Symmetric abs_diff rejected over-payments. ~36% of rejects had current <
   quoted: the node had FEWER records than when it quoted (prune/churn), so the
   client paid for a fuller, pricier node — an over-payment — and the node
   rejected it anyway. Rejecting money a node is owed is nonsensical.

Because an upload needs every chunk stored, even a ~40% per-chunk reject rate
drives upload success to ~0 (0.6^9 for a 9-chunk file; worse for large files).
So per-chunk rejection has to approach zero, not merely shrink.

Fix: make the gate price-based and one-directional. Compute the price the node
would charge now for its current fullness and reject only if the quote paid
less than that by more than QUOTE_PRICE_STALENESS_PCT_TOLERANCE (25%).

- Over-payment (paid >= current price) is always accepted (fixes #2).
- Comparing prices self-scales with the quadratic curve: benign churn on the
  flat part of the curve is ignored, while genuine staleness at high fill —
  where the curve is steep — is still caught (fixes #1).

Replaces the two record-delta tolerance constants with a single price
percentage. Reworks the freshness tests: a 10-record drift now passes (it was
"stale by 10" before), over-payment passes (regression test for #2), and a
quote underpricing by >25% is still rejected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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