Commit f432daa
committed
fix(drive): serve unproved ranked reads through the paginated prover
The `prove = false` arm of the ranked query called grovedb's direct read,
whose offset skip is a per-entry walk: one iterator step and one decode
per skipped entry, so the skip alone cost Theta(min(offset, population)).
`OFFSET` has no ceiling, ranked queries carry no fee, the dispatcher does
no cost accounting, a `spawn_blocking` query cannot be cancelled by client
disconnect or stream reset, and the gateway rate-limits per source IP
across the whole Platform service rather than per method. Measured on a
1,000,000-group fixture: 15 us at OFFSET 0, 457 ms at OFFSET 4e9. At
~1,950 req/min from one unauthenticated IP that is roughly 7x
oversubscription of a 2-vCPU node shared with consensus.
`execute_top_k_no_proof` now generates the same envelope the prove path
returns and extracts the page from it with grovedb's verifier, so the
skipped region is attested from counted subtree commitments instead of
walked. The full prove -> verify -> extract round trip measures
78/90/121/129 us at N = 1e3/1e4/1e5/1e6; verification is flat in offset
and in N and scales only with k. The deep-offset lever becomes a flat
48 us. The cost is +113 us absolute in one corner -- offset 0 with a small
k -- and from N = 100k the round trip is cheaper than the direct read
outright.
grovedb's verifier is called rather than drive's `verify::document_ranked`
wrapper because drive-abci builds drive without the `verify` feature, so
the wrapper is not compiled there. No Cargo edits, no feature flags, no
grovedb change, no proto field change, and no platform-version gate:
queries do not touch state, the only production caller is the v1 query
handler with `transaction: None`, and no query cost feeds block execution
or fees.
BEHAVIOUR CHANGE, wire-visible on unproved responses
`RankedPage::skipped` -- `GetDocumentsResponseV1.ResultData.Ranked.skipped`
on the wire -- stops echoing the request and starts reporting the truth.
grovedb's direct read returns an empty vector when the walk exhausts
during the skip and never reports how far it got, so drive had no choice
but to echo the requested offset. Through the envelope it gets the
attested count. On a five-group ranking, `LIMIT 2 OFFSET 9` with
`prove = false` now reports `skipped = 5` rather than `9`; the proved path
is unchanged. Only the past-the-end case differs, and the two paths no
longer diverge at all -- what proving adds is that the value is attested,
not that it differs. A client asserting `skipped == requested_offset`
will see a different value; a client using it as the rank base for
`entries[i]`, its documented purpose, is unaffected and gains a
population count it previously had to prove for.
The contract is corrected in every place that stated the old behaviour:
`platform.proto`, the Objective-C generated client that carries proto
prose verbatim, the developer book, and the Rust docs.
COMMENTS CORRECTED
Three comments asserted things the code did not do, and two of them were
policy: "there is no denial-of-service lever here to cap" justified the
uncapped OFFSET. They land with the fix rather than before it, because
rewriting them into an accurate description while shipping no mitigation
would have published an unmitigated unauthenticated remote DoS, with a
worked recipe, in a public repo. A fourth surfaced during review: the
drive-abci empty-ranking rejection told callers to retry with
`prove = false`, a route this change removes, and blamed a prover that is
retired and not on the path.
TESTS
Two defects, two independent pins, both verified red before green.
- Result equality: 144 cases (3 axes x 2 directions x k in {1, 4, 100} x
offsets {0, 1, 5, 11, 12, 13, 100, 4e9}) against a population where
three groups share every aggregate value, the values straddle zero, and
the averages are non-integral -- so tie ordering, the sign boundary and
the fixed point's rounding are exercised at every offset. The oracle is
a live call to the old grovedb primitives; `skipped` is asserted from
arithmetic, `min(offset, population)`.
Reverting the implementation: 4 tests red in drive plus the wire
assertion in drive-abci, all on `skipped`.
- Cost: asserted through drive's own executor via a new
`execute_top_k_no_proof_with_cost` (public API unchanged), on both
`seek_count` and `storage_loaded_bytes` -- the same `OperationCost`
fields `fees/op.rs` already reads to compute charged credits -- against
a bound derived from the secondary's AVL height rather than a chosen
constant, plus a guard that fails if the fixture stops being able to
catch a walk, plus a size tripwire for the "proof size is
offset-independent" claim that nothing previously pinned. Over 200
groups the direct read costs 5 -> 105 -> 204 -> 204 seeks and
635 -> 30,835 -> 60,671 -> 60,671 bytes at offsets 0/100/200/4e9; the
executor stays at 36 -> 35 -> 23 -> 23 and 4,458 -> 4,515 -> 2,414 ->
2,414.
This pin was verified against the case that defeats a naive one -- a
direct read that also reports a truthful `skipped` by following its
empty result with a count aggregate, satisfying every `skipped`
assertion while restoring the walk. It goes red: "the executor's seeks
must not grow with the offset: 105 at offset 100 against 5 at offset 0".
Without it the security defect had no regression evidence; only the
behaviour change did.
- `empty_ranking_proof_rejection` gets its first test, including the
negative case pinning how deliberately narrow its match is.
drive --lib 3324 passed; drive-abci --lib query:: 607 passed; clippy and
fmt clean. drive also compiles server-only, verify-only, and for
wasm32-unknown-unknown via wasm-drive-verify.
Verification here discards the reconstructed root hash rather than
comparing it against a locally read one: query reads are not
snapshot-isolated, `finalize_block` makes a commit visible before
publishing the height the query layer's retry guard compares, and a
locally read root is not an independent trust boundary in any case. The
reasoning is recorded at the call site.1 parent f05bf82 commit f432daa
12 files changed
Lines changed: 894 additions & 247 deletions
File tree
- book/src/drive
- packages
- dapi-grpc
- clients/platform/v0/objective-c
- protos/platform/v0
- rs-drive-abci/src/query/document_query/v1
- rs-drive/src
- drive/contract/insert/insert_contract/v0/tests
- query/drive_document_ranked_query
- executors
- verify/document_ranked/verify_ranked_top_k_proof/v0
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
321 | 321 | | |
322 | 322 | | |
323 | 323 | | |
324 | | - | |
325 | | - | |
| 324 | + | |
| 325 | + | |
326 | 326 | | |
327 | 327 | | |
328 | | - | |
| 328 | + | |
329 | 329 | | |
330 | 330 | | |
331 | 331 | | |
| |||
Lines changed: 12 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1407 | 1407 | | |
1408 | 1408 | | |
1409 | 1409 | | |
1410 | | - | |
1411 | | - | |
1412 | | - | |
1413 | | - | |
1414 | | - | |
1415 | | - | |
| 1410 | + | |
| 1411 | + | |
| 1412 | + | |
| 1413 | + | |
| 1414 | + | |
| 1415 | + | |
| 1416 | + | |
| 1417 | + | |
| 1418 | + | |
| 1419 | + | |
| 1420 | + | |
| 1421 | + | |
1416 | 1422 | | |
1417 | 1423 | | |
1418 | 1424 | | |
| |||
Lines changed: 54 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1344 | 1344 | | |
1345 | 1345 | | |
1346 | 1346 | | |
1347 | | - | |
| 1347 | + | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
1348 | 1351 | | |
1349 | 1352 | | |
1350 | 1353 | | |
| |||
1445 | 1448 | | |
1446 | 1449 | | |
1447 | 1450 | | |
| 1451 | + | |
| 1452 | + | |
| 1453 | + | |
| 1454 | + | |
| 1455 | + | |
1448 | 1456 | | |
1449 | 1457 | | |
1450 | 1458 | | |
| |||
1463 | 1471 | | |
1464 | 1472 | | |
1465 | 1473 | | |
| 1474 | + | |
| 1475 | + | |
| 1476 | + | |
| 1477 | + | |
| 1478 | + | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
| 1500 | + | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
| 1509 | + | |
| 1510 | + | |
| 1511 | + | |
| 1512 | + | |
1466 | 1513 | | |
1467 | 1514 | | |
1468 | 1515 | | |
| |||
1474 | 1521 | | |
1475 | 1522 | | |
1476 | 1523 | | |
1477 | | - | |
1478 | | - | |
1479 | | - | |
1480 | | - | |
1481 | | - | |
| 1524 | + | |
| 1525 | + | |
| 1526 | + | |
| 1527 | + | |
| 1528 | + | |
| 1529 | + | |
1482 | 1530 | | |
1483 | 1531 | | |
1484 | 1532 | | |
| |||
Lines changed: 62 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2502 | 2502 | | |
2503 | 2503 | | |
2504 | 2504 | | |
2505 | | - | |
2506 | | - | |
2507 | | - | |
| 2505 | + | |
| 2506 | + | |
| 2507 | + | |
| 2508 | + | |
| 2509 | + | |
2508 | 2510 | | |
2509 | 2511 | | |
2510 | 2512 | | |
2511 | 2513 | | |
2512 | 2514 | | |
2513 | 2515 | | |
2514 | 2516 | | |
2515 | | - | |
| 2517 | + | |
| 2518 | + | |
| 2519 | + | |
| 2520 | + | |
| 2521 | + | |
| 2522 | + | |
2516 | 2523 | | |
2517 | 2524 | | |
2518 | 2525 | | |
| |||
3031 | 3038 | | |
3032 | 3039 | | |
3033 | 3040 | | |
| 3041 | + | |
| 3042 | + | |
| 3043 | + | |
| 3044 | + | |
| 3045 | + | |
| 3046 | + | |
| 3047 | + | |
| 3048 | + | |
| 3049 | + | |
| 3050 | + | |
| 3051 | + | |
| 3052 | + | |
| 3053 | + | |
| 3054 | + | |
| 3055 | + | |
| 3056 | + | |
| 3057 | + | |
| 3058 | + | |
| 3059 | + | |
| 3060 | + | |
| 3061 | + | |
| 3062 | + | |
| 3063 | + | |
| 3064 | + | |
| 3065 | + | |
| 3066 | + | |
| 3067 | + | |
| 3068 | + | |
| 3069 | + | |
| 3070 | + | |
| 3071 | + | |
| 3072 | + | |
| 3073 | + | |
| 3074 | + | |
| 3075 | + | |
| 3076 | + | |
| 3077 | + | |
| 3078 | + | |
| 3079 | + | |
| 3080 | + | |
| 3081 | + | |
| 3082 | + | |
| 3083 | + | |
| 3084 | + | |
| 3085 | + | |
| 3086 | + | |
| 3087 | + | |
| 3088 | + | |
| 3089 | + | |
| 3090 | + | |
| 3091 | + | |
3034 | 3092 | | |
Lines changed: 15 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1542 | 1542 | | |
1543 | 1543 | | |
1544 | 1544 | | |
1545 | | - | |
1546 | | - | |
1547 | | - | |
1548 | | - | |
| 1545 | + | |
| 1546 | + | |
| 1547 | + | |
| 1548 | + | |
| 1549 | + | |
| 1550 | + | |
| 1551 | + | |
1549 | 1552 | | |
1550 | 1553 | | |
1551 | 1554 | | |
| |||
1557 | 1560 | | |
1558 | 1561 | | |
1559 | 1562 | | |
1560 | | - | |
1561 | | - | |
| 1563 | + | |
| 1564 | + | |
| 1565 | + | |
1562 | 1566 | | |
1563 | 1567 | | |
1564 | 1568 | | |
| |||
1568 | 1572 | | |
1569 | 1573 | | |
1570 | 1574 | | |
| 1575 | + | |
| 1576 | + | |
| 1577 | + | |
| 1578 | + | |
| 1579 | + | |
1571 | 1580 | | |
1572 | 1581 | | |
1573 | 1582 | | |
| |||
0 commit comments