Skip to content

perf(platform)!: delete a consumed document from what its lookup read (PV15) - #5360

Merged
QuantumExplorer merged 45 commits into
v5.1-devfrom
claude/dpns-consume-single-read
Oct 30, 2026
Merged

QuantumExplorer merged 45 commits into
v5.1-devfrom
claude/dpns-consume-single-read

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Basic explanation

What this does: When a document "consumes" a commitment (as registering a DPNS name deletes the name's preorder), the platform was reading the commitment from storage twice: once to check it, and once more to delete it, and it billed both reads. From protocol version 15 the delete reuses what the first read found.

Value: A create that consumes a commitment costs one document read less in processing fees: a DPNS v3 name create 10,660 credits less, a chooseFirst reveal 12,020 less. The same document is deleted and the same storage refund is paid. It applies to any contract whose refersTo declares consume, not only DPNS.

Risks: Low. It is a consensus change at protocol version 15 only, through two new generations that only protocol version 15's tables select: protocol version 14 keeps both reads and the fees v5.0-dev ships, which a test pins. The cheaper path deletes from the document and storage flags the lookup read, so a mismatch there would refund the wrong owner or remove the wrong entries; a Drive test checks its operations equal the force delete's after that read.

Based on v5.1-dev, where DPNS v3 (#5337) has landed.

Versioning

The single read is two new generations, selected only by protocol version 15's tables. Protocol version 14 and earlier run generation 0 of both, as v5.1-dev ships it.

  • Document reference validation 1 (document_reference_validation, in DRIVE_ABCI_VALIDATION_VERSIONS_V11): a copy of generation 0 (v1/mod.rs). The refersTo lookup of a reference declaring consume reads with query_documents_with_flags (v1/lookup.rs, batch state 0's fetch_document_through_lookup with that one call changed) and keeps the read in the ConsumedDocument. Any other lookup calls batch state 0's fetch_document_through_lookup itself. It reuses generation 0's chooseFirst budget helpers, and deletable_document_reference_target_is_gone stays generation 0's at both versions. To review it against generation 0: diff <(git show origin/v5.1-dev:<v0 path>) <v1 path> shows 67 changed lines besides the _v0 to _v1 renames.
  • Create conversion 1 (document_create_transition, in the new DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V5, which only DRIVE_VERSION_V10 selects): generation 0's operations, except that each consumed document goes through the new AddDocumentAndDeleteReadConsumed and ForceDeleteReadDocument batch operations, which delete it from that read. The list is taken out of the action, not copied.
  • query_documents_with_flags and query_documents run the same path query through different GroveDB calls (query vs query_item_value, which differ in how they treat a missing intermediate tree). Generation 0, and every generation 1 lookup that does not consume, keep the plain query and its cost, also for a lookup that finds nothing. A consuming lookup that finds nothing pays the same too: the two calls part ways only past a layer a query item misses (query goes on with the next item, query_item_value stops), and a lookup fixes every property of a unique index, one key a layer. should_bill_a_consuming_lookup_that_finds_nothing_the_same_at_protocol_versions_14_and_15 pins it for a missing commitment, a missing voucher, and an owner-keyed voucher whose writer has no tree under the owner level or holds another serial.
  • Protocol version 15 note 11 describes the change. DRIVE_VERSION_V10 and DRIVE_ABCI_VALIDATION_VERSIONS_V11 already exist on v5.1-dev; protocol version 15 is unreleased, so they take the new generations in place.

Issue being fixed or feature implemented

A create that consumes a commitment (a refersTo lookup with consume: true) read the commitment twice:

  1. document reference validation found it through the lookup's index query (billed);
  2. converting the create to Drive operations deleted it with force_delete_document_for_contract_operations, which reads the document again by id to know which index entries to remove and whom to refund (billed again).

What was done?

  • ConsumedDocument keeps its id and type name and gains read: Option<ConsumedDocumentRead>, the document and its stored element's storage flags. Reference validation 0 leaves it None; reference validation 1 sets it, recording the consumed document after the rule reads that still use it and moving the lookup's read into it.
  • Create conversion 1, as above. A consumed document with no read (none reaches it at protocol version 15) is deleted by its id, as generation 0 deletes it.
  • New batch operations AddDocumentAndDeleteReadConsumed and ForceDeleteReadDocument; AddDocumentAndDeleteConsumed and ForceDeleteDocument are unchanged.
  • Drive::force_delete_read_document_for_contract_operations, dispatched on the existing delete_document_for_contract_operations slot: the force delete's operations less its read, with the same guards (refuses indexOnly and history-keeping types).
  • Book: the consume entry says the create pays for one read of the commitment from protocol version 15.

Before and after

protocol version 14 protocol version 15 before protocol version 15 after
DPNS name create (should_charge_a_name_at_protocol_versions_14_and_15), processing 1,846,280 (DPNS v2, no consume) 3,654,380 3,643,720
chooseFirst reveal, accepted (should_pin_the_fees_of_a_reveal_choosing_the_first_of_its_preorders), processing 3,574,720 3,574,720 3,562,700

Storage fees and refunds are unchanged everywhere. The chooseFirst reveal is pinned at both versions: at 14 it is the fee v5.0-dev ships.

In-place changes to shipped generations

  • Document reference validation 0 (protocol versions 14 and earlier): its ConsumedDocument literal sets the new read field to None, with a comment. That is its only change. The create conversion 0 that receives it reads document_id and document_type_name as before, so its output is unchanged. The fee pins at protocol version 14 above cover it.
  • Create conversion dispatcher (document_create_transition.rs): gains mod v1; and the 1 => arm; the 0 => arm is unchanged.
  • Drive delete generation 0 (delete_document_for_contract_operations/mod.rs and v0/mod.rs): gains force_delete_read_document_for_contract_operations and its _v0 on the existing method slot 0, and nothing else; the functions already there are unchanged. Their only caller is the create conversion 1 (through AddDocumentAndDeleteReadConsumed and ForceDeleteReadDocument), which only the protocol version 15 table selects (DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V5), so protocol version 14 never reaches them.
  • Every other shipped file this PR once changed matches v5.1-dev again: batch state 0's fetch_documents.rs, AddDocumentAndDeleteConsumed, ForceDeleteDocument, and the Drive document method tables (the delete_consumed_document_operations slot is gone). consumed_documents.rs gains read: None in a test helper only.

How Has This Been Tested?

  • Both generations through their dispatchers: should_pin_the_fees_of_a_reveal_choosing_the_first_of_its_preorders (3,574,720 at 14, unchanged; 3,562,700 at 15) and should_charge_a_name_at_protocol_versions_14_and_15 (3,643,720 at 15).
  • Reference validation 1 keeps the read: should_bill_the_commitment_lookup_and_report_the_consumed_commitment checks the consumed read equals the stored preorder and its storage flags, fetched by id, and that those flags are epoch 0 with Alice as owner.
  • A lookup that does not consume reads as generation 0's: should_bill_a_lookup_that_does_not_consume_the_same_at_protocol_versions_14_and_15 checks that a post finding its handle, and one finding none, cost the same at protocol versions 14 and 15, also under an index whose owner level holds no tree for the writer. The flags read costs the same in those cases too, so the test pins the fees rather than telling the two reads apart; the non-consuming path is generation 0's by construction.
  • A consumed document is the creating contract's: should_reject_a_consuming_lookup_into_another_contract registers a lookup into another contract's consumable preorder without consume, and the same lookup with consume is refused (ReferencedDocumentLookupInvalidError). The protocol version 15 delete relies on that rule: it deletes the read from the creating contract without reading it there.
  • Drive: should_delete_a_read_document_as_a_force_delete_does_less_its_read (the operations equal the force delete's after its read) and should_estimate_a_read_document_delete_as_a_force_delete_less_its_read (one operation fewer, the read; as many estimated layers; the same fee once the read is left out; estimated operations hold made-up keys, so they are compared by fee).
  • Drive, guards: should_refuse_to_delete_a_read_index_only_document (CorruptedCodeExecution) and should_refuse_to_delete_a_read_document_that_keeps_history (InvalidDeletionOfDocumentThatKeepsHistory), each with and without cost estimation.
  • cargo test -p drive-abci --lib -- dpns_v3_tests commit_reveal consume choose_first only_when_consumed refers_to dpns document_reference lookup_reference reference_expression derived_index_values: 238 passed (RUST_MIN_STACK=16777216: should_register_contract_with_reference_expressions, a contract registration test this PR does not reach, overflows the default 2 MiB debug test stack).
  • cargo test -p drive --lib -- drive::document::delete util::batch::drive_op_batch state_transition_action: 1,199 passed. cargo test -p platform-version: passed.
  • cargo clippy -p drive -p drive-abci -p platform-version --all-targets and cargo fmt --all -- --check: clean.
  • Mutation check: dropping the read delete's layer estimation fails the estimation test (11 layers vs 7).

Breaking Changes

Consensus change at protocol version 15: a create that consumes a commitment is charged one document read less. Nothing changes at protocol version 14 or for clients.

Checklist:

  • I have performed a self-review of my own code
  • My Rust, FFI, WASM, Swift or Kotlin changes follow the coding conventions
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed (the book's consume entry notes the single read)
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

PR Hygiene · e319d43

  • Bots — thepastaclaw ✓
  • Self-review — post /self-reviewed
  • Build failed
  • Approvals — you own every area touched; none needed

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

Summary by CodeRabbit

  • Improvements
    • From protocol version 15, consuming a document reference reuses the document read performed during lookup, avoiding an additional read when the commitment is deleted.
    • This lowers processing fees for affected operations. DPNS v3 name creation processing fees decrease by 10,660 credits; storage fees and refunds are unchanged.
    • Protocol versions 14 and earlier retain the existing behavior, including the additional read when deleting a consumed commitment. The fee reduction applies to processing costs only.

QuantumExplorer and others added 17 commits October 8, 2026 16:17
…a keywords

From protocol version 14 the DPNS `domain` create is checked by the
contract's own keywords instead of most of its data trigger:

- `normalizedLabel` and `normalizedParentDomainName` are generated from
  `label` and `parentDomainName` (`generatedFrom` homographSafeASCII);
- `preorderSalt` reveals the writer's own preorder, made in an earlier
  block, and deletes it (`refersTo` with a sha256d `findBy`, `where`
  `$ownerId`, `minimumAgeBlocks: 1`, `consume`); the preorder's storage
  is refunded to the writer;
- the `recordsIdentityIsOwner` rule holds a new name's `records.identity`
  to its owner until the name first changes hands;
- `domain` sets `canBeDeleted: false`; `preorder` requires
  `$createdAtBlockHeight`. Positions, transient list and encoding are v2's.

`create_domain_data_trigger` 2 keeps only the parent domain checks, and
data trigger bindings 2 drop the `domain` Replace and Delete rejects.
`transition_to_version_14` re-stores DPNS. A preorder recording no
`$createdAtBlockHeight` (made before the upgrade) counts as old enough
for `minimumAgeBlocks`. The legacy JS SDK hashes the preorder as the
platform does: normalized label, ".", parent as sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A document recording no `$createdAtBlockHeight` is known only to come from
a block before the protocol upgrade that re-stored its system contract, so
it now meets `minimumAgeBlocks: 1` (the DPNS reveal's) and no larger
minimum. Another contract revealing DPNS preorders with a larger minimum
refuses a pre-upgrade preorder; a test covers it.

Also: a trigger-refused DPNS reveal keeps its preorder for a retry (test),
and the check_tx contract update fee pin follows the DPNS v3 preorder type
the test copies in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riscoll-44c981

# Conflicts:
#	packages/rs-platform-version/src/version/v14.rs
`User.DASH` hashes `user.DASH`, the parent as sent, while the domain
carries `parentDomainName: "DASH"` and `normalizedParentDomainName: "dash"`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riscoll-44c981

# Conflicts:
#	packages/rs-platform-version/src/version/v14.rs
Short `description`s and no `$comment`s in DPNS v3; the rules they
restated are in the schema keywords. The check_tx contract update fee pin
follows the smaller preorder type it copies in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…owner

A copy of a pending preorder no longer blocks it, and the copier can no
longer reveal the name with the copy once the owner's reveal shows the salt:

- `preorder` is unique on (`$ownerId`, `saltedDomainHash`), replacing the
  unique index on the hash alone;
- the domain's `preorderSalt` finds it by `$ownerId` and the sha256d of the
  writer's id, the salt, the normalized label, "." and the parent.

The parser (meta-schema v3, parser generation 3) admits `"$ownerId"` as a
findBy function param (`LookupKeyParam::Writer`), a `$ownerId` findBy key on
a transferable type beside a function, and that key for `consume`.

At protocol version 14 every existing preorder is deleted and the type is
rebuilt as a fresh v3 chain lays it out
(`Drive::apply_contract_rebuilding_document_types`), so the minimumAgeBlocks
allowance for preorders recording no creation height is reverted.

rs-sdk and js-dash-sdk compute the preorder hash from the contract's own
declaration, so either side of the upgrade hashes as the platform does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riscoll-44c981

# Conflicts:
#	packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs
#	packages/rs-platform-version/src/version/v14.rs
A registration took the preorder's hash form from the DPNS contract the
client already held: the context provider's for the SDK's protocol version
(13 on a fresh SDK), or js-dash-sdk's app cache. Either could still be DPNS
v2 after the network moved to v3, so the preorder committed to the old hash
and the domain create could never find it (40120), after the preorder was
paid.

rs-sdk now refreshes the protocol version (proven) and fetches DPNS from
state before hashing, fetching again when the response raised the version
the contract was parsed under. A preorderSalt reference without a findBy
function is an error instead of a silent fall back to the old hash.
js-dash-sdk fetches the contract with a new `skipCache` option, which also
replaces the cached contract both documents are created against.

Tests: the SDK hash against the real DPNS v2 and v3 contracts, a missing
hashed property, and a mock SDK seeded at 13 with a provider holding v2;
js specs for a cache warmed with v2 and for `skipCache`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…arsed version

Comparing the SDK's protocol version before and after the fetch missed a
node behind the network: after the refresh learned protocol 14, a node at
the block before activation could still prove DPNS v2 at 13, the ratchet
ignores the lower version, and the registration would hash the old way.

The registration now reads each DPNS contract response with its metadata
and takes the first one proved at the version the SDK parsed it under, at
most 3 times. A response proved at a newer version was parsed under an
older one (decoding DPNS v3 under 13 drops the salt's reference) and has
raised the SDK's version, so the next is parsed under it; one proved at an
older version is skipped. Otherwise the registration fails before paying.

The document building moves into `dpns_registration_documents`, so an
offline test drives it against a context provider holding v2 and checks
the preorder's owner-bound hash and the domain's salt. Scripted tests cover
a response parsed under an older version (rebuilt from serialized bytes as
a proof decode does), a node behind the network, and every node behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`apply_contract_rebuilding_document_types` stored the new contract
through `update_contract_add_operations`, which only builds operations,
so unlike an update it never put the rewritten contract in the block
cache. Until the protocol change events refresh every system contract at
their end, a read in the block could fall back to a global cache entry a
committed-state read had filled with the old contract. The rebuild now
fetches what it stored and seeds it with `insert_rewritten`, as
`update_contract` does. Test: DPNS v2 warm in the global cache, the
preorder type rebuilt, and a read in the block's transaction gets v3.

The book's same-block transfer case says the rule still applies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…anwhile

The version a registration compared a DPNS contract response with was
read before the fetch awaited the network. SDK clones share that version,
so another request could raise it from 13 to 14 while the fetch waited; a
response from a node still at 13 proving DPNS v2 then matched the stale
13 and was taken, and the preorder hashed the old way.

A response is now taken only when the SDK's version is unchanged across
the fetch as well as equal to the version the node proved it at. The
version only rises, so one unchanged across the fetch is the version the
response was parsed under. Regression: the first fetch raises the shared
version to the latest while returning DPNS v2 proved at 13, which is
skipped, and the next response, v3, is taken.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riscoll-44c981

# Conflicts:
#	packages/rs-platform-version/src/version/v14.rs
Now that `identifier` and `bytes` + `size` are in v5.0-dev (#5355), the
DPNS v3 schema uses them: `preorderSalt` and `saltedDomainHash` are
`"type": "bytes", "size": 32`, `records.identity` is `"type":
"identifier"`. The parsed types are unchanged; the stored contract keeps
the schema as written, so the check_tx contract-update fee pin moves
(27003089990 to 27003077990).

Protocol 13 cannot decode the shorthands, so the SDK test of a response
parsed under an older version now uses DPNS v2 as the contract read
under 13.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clients:
- js-dash-sdk refuses a records.identity other than the registering
  identity before paying for the preorder when the contract declares
  recordsIdentityIsOwner; the legacy (pre-v3) hash of a top-level name is
  of the salt and the label as sent, as trigger v1 hashes it; the "no
  DPNS app" spec now reaches the code it names.
- rs-sdk `salted_domain_hash` reads the salt and label from the domain's
  properties instead of separate parameters.

Drive and drive-abci:
- the preorder rebuild refuses a type with trees outside its own subtree
  (indexOnly, contested index, moderator deletions, ttl), deletes without
  the backward-reference scan Drive never needs, and drops the
  always-None storage flags parameter.
- trigger v2 queries the parent under the top level directly (a parent
  domain name holds no dot) and gains in-module tests.

Parser and docs:
- the consume check moves into `writer_owns_found_document`, so the
  parse_reference_target match is no longer reflowed.
- `LOOKUP_KEY_WRITER` gives way to the existing `OWNER_ID`; the unused
  `preorder::properties::SALTED_DOMAIN_HASH` and `hash_double` import go.
- meta-schema v3, reference_lookup.rs, wasm-dpp2 and the book describe
  the findBy `$ownerId` entry (40120 for another identity's commitment),
  the per-owner preorder index and the legacy top-level hash.

Tests:
- the strategy tests hash preorders with the shared
  `dpns_salted_domain_hash` (now outside cfg(test)) instead of the rule
  under test, and lose the stale "disable document triggers" comments;
  dead `dpns < 3` arms, the pasted height-1 comments and the derivable
  flag go; the protocol 13 test is renamed `should_...`; preorders are
  read by id; the award test uses `fast_forward_to_block`; the upgrade
  layout reference is a bare genesis state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`DocumentPropertyReferenceTarget::lookup_hash_key` returns the computed
key of the `findBy` function a target declares, the chain
`as_any_document_reference` -> `lookup` -> `hash_key` that rs-sdk's DPNS
preorder hash and document reference validation 0 each spelled out.

Reference validation 0 is a shipped generation edited in place: the
accessor returns exactly what the inline chain returned, so nothing
changes at any protocol version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A create that consumes a commitment (a `refersTo` lookup with a computed
key declaring `consume`, protocol version 14) read the commitment twice:
the lookup in reference validation found it, and the delete read it again
by id to know what to remove and refund. The second read was billed.

The lookup now keeps the stored element's storage flags beside the
document (`query_documents_with_flags`, the same path query and cost),
`ConsumedDocument` carries both, and the delete runs from them through
`Drive::force_delete_read_document_for_contract_operations`: the
operations of `force_delete_document_for_contract_operations` less its
read, dispatched on the same method version. A contested create's consume
uses the new `ForceDeleteReadDocument` operation, the plain create's
`AddDocumentAndDeleteConsumed`.

A DPNS v3 domain create's processing fee drops from 2,525,540 to
2,514,960 credits; storage fee and the refund to the writer are
unchanged. A Drive test checks the read-document delete's operations
equal the force delete's after its read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Walkthrough

Protocol v15 reuses the read from a consuming refersTo lookup when deleting the consumed document. The change adds versioned reference validation and document-create conversion, carries lookup data into Drive deletion, and updates version-specific fee tests and documentation.

Changes: Consumed lookup deletion

Layer / File(s) Summary
Reference validation and retained lookup data
packages/rs-drive-abci/.../document_reference_validation/*, packages/rs-drive/.../document_create_transition_action/*
Reference validation v1 retains the matched document and storage flags for consuming lookups. The create action stores and exposes the consumed-document data.
Deletion from retained document data
packages/rs-drive/.../delete_document_for_contract_operations/*, packages/rs-drive/src/util/batch/drive_op_batch/document.rs
Drive adds a deletion path for an already-read document. Batch operations use retained lookup data when available and otherwise delete by ID.
Document-create conversion
packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition*
The v1 converter adds the document and queues deletion of consumed documents, using retained lookup data when available.
Protocol version selection
packages/rs-platform-version/src/version/*
Platform version configuration selects reference validation v1 and document-create conversion v1 for protocol v15. Earlier versions retain their prior versions.
Version-specific tests and documentation
packages/rs-drive-abci/.../tests/document/*, book/src/contract-keywords/refers-to-lookup.md
Tests compare lookup behavior and processing fees across protocol versions 14 and 15. The DPNS fee expectation and lookup documentation reflect the v15 behavior.

Priority: Low

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Validation as DocumentReferenceValidationV1
  participant Action as DocumentCreateTransitionAction
  participant Converter as DocumentCreateTransitionV1
  participant Batch as DocumentOperationType
  participant Drive as Drive
  Validation->>Action: retain consumed document and storage flags
  Action->>Converter: provide consumed documents
  Converter->>Batch: add document and queue consumed-document deletions
  Batch->>Drive: delete using retained read data when available
Loading

Possibly related PRs

  • dashpay/platform#5337: Introduces the DPNS v3 preorder consumed by domain creation through a refersTo lookup.

Suggested reviewers: shumkov, thepastaclaw, lklimek

Merge Risk: Minimal · up to e319d

Version 15 reuses the lookup read for deletion. No merge-blocking issue was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 77.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: deleting a consumed document from the read performed by its lookup in protocol version 15.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 77.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 40 functions across 20 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thepastaclaw

thepastaclaw commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit e319d43) · triage: critical

QuantumExplorer and others added 3 commits October 9, 2026 15:45
…ties

The register spec mocks `crypto.randomBytes` to zeros for the whole
suite, so two `generateRandomIdentifier()` calls gave the same identity
and the refusal never fired. The spec now uses two fixed, different ids.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s stay deletable

documents.md stated without exception that a findBy `"$ownerId"` source
needs a referring type that cannot be transferred or traded, for a
property's findBy and for creatorRefersTo; beside a function the lookup
is judged on the create alone and the source is allowed, as DPNS v3
declares. The deletion chapter's onlyWhenConsumed preorder example now
says DPNS v3's own preorder keeps `canBeDeleted: true`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three Drive tests used the latest DPNS fixture for writes or proofs at
protocol version 13. DPNS v3 is now written with the `bytes` and
`identifier` type shorthands, which the protocol 13 parser refuses
("unsupported property type: bytes"). A chain at 13 stores DPNS v2, which
every later version reads too, so these tests now load it: the two
contested-poll tests (`..._poll_started_before_protocol_version_14`) and
`verify_batch_document_proof_before_protocol_version_14_carries_no_balance`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Phase 1 + Phase 2

Verified the supplied findings against head cec6d0a and the PR's base-to-head diff. No blocking defects were confirmed; the overlapping cloning findings combine into one performance suggestion, and the new deletion guards lack direct negative-path coverage. This was static verification only: no builds or tests were run, and the supplied CI snapshot shows Kotlin checks queued without completed Rust validation.

🟡 2 suggestion(s)

1 finding(s) not shown inline (the lines are not part of this PR's diff)

🟡 Suggestion: Move consumed document payloads instead of deep-cloning them
packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs:58

ConsumedDocument now owns a full Document and its storage flags, so this to_vec() recursively clones each document's property map and values. The reference-validation block also clones the owned lookup result into ConsumedDocument before dropping the original. Both copies are avoidable: this converter owns mut self, and the subsequent owned document conversion discards the original consumed_documents field. The PR therefore introduces copying proportional to the consumed document bodies on every consuming create, including contracts with larger commitments than DPNS preorders. After completing the borrowed reference checks, move the lookup tuple into ConsumedDocument; add a take_consumed_documents accessor using std::mem::take and use it here, matching the existing take_* accessors.

source: muse-spark-1.3-contributor (phase1-reviewer: general, rust-quality); gpt-6.1-sol (phase2-reviewer: general, architecture-layering, platform-versioning, rust-quality, security-auditor)

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 7: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — The cross-layer change to lookup state, create conversion, and batch deletion is intricate and directly changes consensus-visible fee accounting and storage-refund inputs through force_delete_read_document_for_contract_operations_v0 and DocumentOperationType conversion.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (lane failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs`:
- [SUGGESTION] packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs:58: Move consumed document payloads instead of deep-cloning them
  ConsumedDocument now owns a full Document and its storage flags, so this to_vec() recursively clones each document's property map and values. The reference-validation block also clones the owned lookup result into ConsumedDocument before dropping the original. Both copies are avoidable: this converter owns mut self, and the subsequent owned document conversion discards the original consumed_documents field. The PR therefore introduces copying proportional to the consumed document bodies on every consuming create, including contracts with larger commitments than DPNS preorders. After completing the borrowed reference checks, move the lookup tuple into ConsumedDocument; add a take_consumed_documents accessor using std::mem::take and use it here, matching the existing take_* accessors.

In `packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs`:
- [SUGGESTION] packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs:222-236: Add negative-path tests for the new read-document deletion guards
  The new helper independently duplicates the indexOnly and history-keeping guards from the existing force-delete path. The added operation-equivalence test uses a normal document type, so it does not verify either rejection; the existing history-deletion test exercises the old deletion path rather than this helper. Contract registration currently excludes these types from consumption, so this is a defensive API coverage gap, not a demonstrated execution defect. Add direct assert_matches! cases for the new entry point with an indexOnly type and a history-keeping type, asserting CorruptedCodeExecution and InvalidDeletionOfDocumentThatKeepsHistory respectively, to pin the guard parity promised by this PR.

QuantumExplorer and others added 7 commits October 9, 2026 17:43
…ion the response reports

A fresh SDK starts at its network's floor (protocol version 13 on
mainnet, testnet and regtest) and learns the network's version only
from a verified response. DPNS v3 is written with the `bytes` and
`identifier` type shorthands, which the protocol version 13 parser
refuses, so on a network at 14 the first proof holding DPNS failed
("unsupported property type: bytes") before the SDK could learn 14,
every time.

When parsing under the SDK's version fails on an unpinned SDK below the
newest version it knows, `parse_proof_at_the_reported_version` parses
under that newest version, which verifies the proof and its quorum
signature over a state id that signs the response's protocol version,
and, when the reported version is another known one, parses again under
it. A pinned SDK, or one at the newest version, reports the first
failure. The fetch traits require cloneable responses (all are) for the
retry.

Tests: a stand-in proof readable only from protocol version 14 parses on
an SDK seeded at 13 and fails on one pinned at 13.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts with #5313, which verifies a response again after fetching a
missing quorum key, in the same clone-and-retry spot as the protocol
version fallback:
- fetch.rs, fetch_many.rs: both sides require a cloneable response; the
  doc names both retries.
- sdk.rs: the Dapi arm takes #5313's `verify_fetching_quorum_key`, whose
  two verifications now go through `parse_proof_at_the_reported_version`
  (the version passed in, so both start from the same one). A failure of
  the quorum signature or its key is reported as it is under either
  version (`fails_after_reading_the_proof`): the signature is checked
  once the proof was read, so a missing key still reaches the fetch and
  no extra quorum lookup is made.

Test: `should_report_a_missing_quorum_key_found_under_the_newest_version`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… verification

`parse_proof_at_the_reported_version` borrows the request and response
and copies them once per parse, so `verify_fetching_quorum_key` keeps one
copy for both of its verifications instead of copying it again before
the first.

The probe is now scripted by its request (the first version that decodes
it, the version its response reports, the versions whose signature or
key fails) and records every version it is parsed under. New tests:
- a reported version between the SDK's and the newest is parsed again
  under it, and its failure there is reported;
- a signature failure under the newest version is reported over the
  first decoding error, and one under the SDK's version is not retried;
- through `verify_fetching_quorum_key`, a fresh SDK reads the proof and
  learns the reported version, and learns none when the signature fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h the version fallback

The probe now asks the provider for its quorum's key instead of failing
outright, so a key the provider fetches makes the second verification
succeed. A new test drives `verify_fetching_quorum_key` with an SDK two
versions back and a provider holding no key: one fetch, the parse
sequence current, newest, current, newest, reported, and the SDK learns
the reported version. A regression of the second verification to a
direct parse at the SDK's version would fail it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riscoll-44c981

# Conflicts:
#	book/src/contract-keywords/refers-to-lookup.md
#	book/src/data-model/documents.md
#	packages/rs-dpp/schema/meta_schemas/document/v3/document-meta.json
#	packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_reference_validation/v0/mod.rs
#	packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_documents.rs
…riscoll-44c981

# Conflicts:
#	book/src/contract-keywords/refers-to-lookup.md
#	book/src/data-model/documents.md
#	packages/rs-dpp/schema/meta_schemas/document/v3/document-meta.json
#	packages/rs-dpp/src/data_contract/document_type/property/reference_lookup.rs
…ut a salt

A DPNS v3 preorder now holds `ownerNameHash`, the sha256d of the owner's
id, the normalized label, "." and the normalized parent, unique per owner
(`ownerAndNameHash`), and `nameHash`, the same without the owner, indexed
with its creation height (`nameHashAndHeight`). It carries no salt and
lives an hour (`ttl` 3600, so it refunds nothing when consumed). The
domain finds it through `creatorRefersTo` (findBy `$ownerId` and the
`ownerNameHash` function, minimumAgeBlocks 1, consume). `preorderSalt`
stays declared on the domain, transient and no longer required, so
domains stored under v1 and v2 decode.

`nameHash` is there for a first-committer refersTo keyword built in a
separate PR: with it, a name whose older valid preorder belongs to
someone else is refused, which stops a watcher who reads a pending name
from the mempool from preordering and revealing it first under full
blocks. No salted design can check that before the owner reveals.

Without a salt an owner holds one pending preorder of a name: a second
is refused as a duplicate (40105) while the first stands.
`Sdk::register_dpns_name` reveals a pending one instead of preordering
again.

- Drive: `apply_contract_rebuilding_document_types` leaves a type
  already stored as declared (so the v14 upgrade stays idempotent), and
  rebuilds into a type with a ttl, which holds no document and so no
  expiry entry; a stored type with a ttl is still refused.
- rs-sdk and js-dash-sdk build the preorder from the domain's creator
  reference (`nameHash` from its params without `$ownerId`) and send no
  salt from v3; v1 and v2 keep the salted hash.
- Tests: dpp DPNS v3 shape and hash; drive rebuild (ttl new type, type
  left as stored, stored ttl refused); drive-abci dpns_v3 (one pending
  preorder per name, the contested retry reveals the same preorder,
  preorder and domain fees pinned: 62,554,803 credits a name at 14
  against 76,862,280 at 13); the check_tx update pin gains the 0.01 Dash
  non-unique index; rs-sdk and js-dash-sdk preorder shapes.
- Docs: v14 note 90, the book (commit and reveal, documents, deletion,
  transient).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw requested changes on this head; dismiss the review or push a fix; thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed and removed waiting-bots Waiting for the review bots to report on this head labels Oct 28, 2026
QuantumExplorer and others added 3 commits October 29, 2026 09:14
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…alidation and create conversion generations

The protocol version 15 single read ran through generation 0 of document
reference validation and of the create conversion, which protocol
version 14 also selects, gated by a Drive delete slot read inside the
shipped batch state code. It now has generations of its own, selected
only by protocol version 15's tables:

- document_reference_validation 1 (DRIVE_ABCI_VALIDATION_VERSIONS_V11):
  a copy of generation 0 whose lookup reads with query_documents_with_flags
  (v1/lookup.rs) and whose consumed commitment keeps that read in
  ConsumedDocument::read. It reuses generation 0's chooseFirst budget
  helpers, and deletable_document_reference_target_is_gone stays
  generation 0's at both versions.
- document_create_transition conversion 1 (new
  DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V5, selected by DRIVE_VERSION_V10):
  generation 0's operations, deleting each consumed document through the
  new AddDocumentAndDeleteReadConsumed and ForceDeleteReadDocument batch
  operations, from the read.

Generation 0 is v5.1-dev's again: fetch_documents.rs, conversion 0's arm,
AddDocumentAndDeleteConsumed and ForceDeleteDocument are unchanged, and
the delete_consumed_document_operations slot and
DRIVE_DOCUMENT_METHOD_VERSIONS_V5 are gone. The one line left in
reference validation 0 sets ConsumedDocument's new `read` field to None,
which conversion 0 never reads. force_delete_read_document_for_contract_operations
dispatches on the existing delete_document_for_contract_operations slot.

Fees are unchanged from the previous head: DPNS v3 name create at
protocol version 15 3,643,720, chooseFirst reveal 3,574,720 at 14 and
3,562,700 at 15.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

The protocol-15 versioning and the five previously identified fixes are correctly implemented, and the Rust workspace check covering the changed code succeeded. One non-blocking issue remains: protocol 15 routes non-consuming lookups through a different GroveDB query API, which can change processing costs and missing-tree behavior even though the optimization only requires flags for consuming lookups. The cross-contract consumption concern is refuted by the existing contract-registration validation that rejects foreign-contract consuming references.

🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 11: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 12: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This is a large, intricate change to consensus-critical document validation, deletion, storage refunds, and protocol-versioned state-transition behavior, including the functions that determine which document and ownership data are removed and refunded.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_reference_validation/v1/lookup.rs`:
- [SUGGESTION] packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_reference_validation/v1/lookup.rs:131-137: Use the flags query only for consuming lookups
  This helper is used for every lookup in validation generation 1, but it always calls `query_documents_with_flags`, including when `lookup.consume` is false and no storage flags are needed. The existing generation-0 path uses `query_documents`, which reaches GroveDB through `query_item_value`, while this path uses `query`; the two calls use different intermediate-tree error modes and can produce different processing costs for unsuccessful lookups. That means protocol 15 changes fees and query behavior for non-consuming references even though the stated optimization only needs to change consuming references. Preserve the existing lookup path for non-consuming references and use the flags-returning path only when `lookup.consume` is set.

@github-actions

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

Document reference validation 1 read every `refersTo` lookup through
`query_documents_with_flags`, though only a lookup declaring `consume` needs
the flags. A lookup that does not consume now calls batch state 0's
`fetch_document_through_lookup` itself, so it keeps generation 0's GroveDB
call and cost at protocol version 15.

A new test pins that a post finding its handle, and one finding none, cost
the same at protocol versions 14 and 15, also under an index whose owner
level holds no tree for the writer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@github-actions

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 2 only (queue backlog)

The protocol-15 optimization is correctly isolated behind new validation and conversion generations, and all six prior findings are addressed at the current head. Two non-blocking issues remain: consuming lookup misses use different GroveDB query semantics from the historical path, and the retained-document test does not verify the complete document or exact refund metadata. The Rust workspace check is still in progress; no failed code checks are reported.

🟡 2 suggestion(s)

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This is a large, intricate consensus-critical change that alters protocol-versioned document validation, deletion operations, storage refunds, and processing-fee accounting in rs-drive and rs-drive-abci.
  • Phase 1 reviewers: not run (skipped for throughput: 13 PRs queued, above the 10 limit)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_reference_validation/v1/lookup.rs`:
- [SUGGESTION] packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_reference_validation/v1/lookup.rs:151-157: Preserve the original query semantics for consuming lookup misses
  The consuming branch calls `query_documents_with_flags`, which reaches GroveDB `query` with `error_if_intermediate_path_tree_not_present = false`. The generation-0 path and the non-consuming branch use `query_documents`, which reaches `query_item_value` with that option enabled. Although Drive converts missing-path errors from the historical query into an empty result, the two APIs can traverse different missing-intermediate-tree cases and charge different processing costs. This means a consuming lookup that finds no document can have different consensus fees for reasons unrelated to the single-read optimization. Add a Drive-owned document-plus-flags query that preserves the original missing-path semantics, or add tests covering each absent-intermediate-path shape and explicitly pin the intended protocol-15 behavior.

In `packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/commit_reveal_lookup.rs`:
- [SUGGESTION] packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/commit_reveal_lookup.rs:1243-1245: Assert the retained document and exact storage flags
  The assertion verifies only the retained document ID and that some storage flags are present. The new deletion path uses the complete document to reconstruct index-removal operations and uses the flags to assign storage refunds, so this test would still pass if the retained document contents were incomplete or if the flags belonged to the wrong owner or epoch. Compare the retained document contents and the exact storage-flag owner/base epoch with the stored preorder or a direct flagged fetch.

@github-actions

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

…ctly

A consuming lookup reads through `query_documents_with_flags` from
protocol version 15, whose GroveDB `query` differs from generation 0's
`query_item_value` only past a layer a query item misses. A lookup fixes
every property of a unique index, one key a layer, so a miss stops at the
same layer either way. A new test pins equal fees at protocol versions 14
and 15 for a missing commitment, a missing voucher, and an owner-keyed
voucher whose writer has no tree under the owner level or holds another
serial, each refused with ReferencedEntityNotFoundError (40120).

The consumed-read test now compares the read with the stored preorder and
its storage flags fetched by id, and pins those flags to epoch 0 with
Alice as owner, instead of checking only the id and that flags exist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw requested changes on this head; dismiss the review or push a fix; thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

The protocol-15 optimized deletion path can accept a consuming lookup into a foreign contract but resolves the deletion against the creating contract. This can leave the foreign document intact while the create succeeds, allowing the same commitment to be replayed; the issue is blocking. The PR also omits the newly added shipped-generation delete helper from its in-place-generation inventory, which is a non-blocking versioning documentation gap. Rust workspace tests and JS build checks are still queued.

🔴 1 blocking | 🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 7: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 11: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 12: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This is a large, intricate consensus-critical change that alters protocol-versioned document validation, deletion, storage refunds, and fee accounting in the Drive state-transition path.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive/src/util/batch/drive_op_batch/document.rs`:
- [BLOCKING] packages/rs-drive/src/util/batch/drive_op_batch/document.rs:724-733: Foreign-contract consumed documents are deleted from the declaring contract
  `ConsumedDocument` stores only the target type name and the document read, not the effective referenced contract ID. In protocol-15 validation, the lookup is performed against `referenced_contract`, which may be foreign, but this conversion resolves `document_type_name` against `contract`, the creating contract, and passes that contract to `force_delete_consumed_document_operations`. A contract B can therefore declare a consuming lookup into a document type with the same name in contract A; the lookup retains A's document, while the optimized delete constructs B's primary and index deletions. Because the optimized path no longer performs the by-ID read under B, the absent B row can be treated as a no-op and the A document remains available for replay while the B create succeeds. Protocol 14's by-ID path would read under the declaring contract and reject the missing row. Preserve the effective referenced contract identity in the consumed record and use it for deletion, or reject foreign-contract consuming lookups before conversion; add a regression test proving the foreign document is removed exactly once.

In `packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs`:
- [SUGGESTION] packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs:207-220: Document the in-place edit to the shipped delete generation
  This adds `force_delete_read_document_for_contract_operations_v0` inside the existing delete generation 0 while its dispatcher continues to select the existing delete method slot 0. The helper is currently reachable only from the protocol-15 create-conversion generation, so the behavior is safe for protocol 14, but the PR's "In-place changes to shipped generations" inventory does not list this modified module. Add this file to that inventory and state the protocol-15-only reachability proof, or give the helper its own versioned method slot.

…ntract

From protocol version 15 a create deletes a consumed document from what its
lookup read, from the type of that name in the creating contract, without
reading it there again. That is right because contract registration refuses
`consume` beside a findBy into another contract (data contract reference
validation 0), a rule nothing pinned.

`should_reject_a_consuming_lookup_into_another_contract` registers a lookup
into another contract's consumable `preorder` without `consume`, and is
refused with ReferencedDocumentLookupInvalidError once the same lookup
declares it. The consumed delete helper and `ConsumedDocument` now say why
the create's contract is the one to delete from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@github-actions

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

Reviewed the complete diff at e319d43 and found no actionable in-scope defects: protocol 15 alone selects the read-reusing generations, while protocol 14 retains its historical behavior. Nine prior concerns are addressed; the foreign-contract finding is withdrawn because the registration safeguard already existed on the base branch. The current Rust workspace job failed after its self-hosted runner lost communication, with formatting, clippy, and the non-shielded test step successful, so I judge that failure unrelated; the DAPI-client and WASM-SDK JavaScript test checks remain pending.

🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 7: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: platform-versioning); reviewer 11: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 12: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — This is a large, intricate change to consensus-critical document validation, deletion operations, storage refunds, and protocol-version-gated state-transition behavior, including the critical surface in document reference validation and create-to-operations conversion.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.

No unresolved findings remain from the prior review on this head.

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
Full checklist in the description.

@QuantumExplorer
QuantumExplorer merged commit c949f38 into v5.1-dev Oct 30, 2026
90 of 93 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/dpns-consume-single-read branch October 30, 2026 09:55
QuantumExplorer added a commit that referenced this pull request Oct 30, 2026
v5.1-dev's consume single read (#5360) adds
AddDocumentAndDeleteReadConsumed and ForceDeleteReadDocument. At
protocol version 15 apply_drive_operations 2 builds every document
operation against the batch's earlier ones, so both get an arm there:
as their AddDocumentAndDeleteConsumed and ForceDeleteDocument siblings,
deleting from what the lookup read when the read was kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shumkov added a commit that referenced this pull request Oct 30, 2026
…2-document-request-version

Brings in #5680 (yes/no votes name their poll by id, polls carry a typed
purpose), #5487 and #5360.

Conflict: protocol_gate_tests.rs imports; keep YesNoVotePollPurpose and
the drive query types the document gate tests use. #5680 adds a poll to
the yes/no poll state response only: no new method or request field, so
no gate or request inventory verdict changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shumkov added a commit that referenced this pull request Oct 30, 2026
…ov/v51-f0-pr3-pre-send-windows-and-index

Brings in v5.1-dev through #5636's branch: #5680, #5487 and #5360. No
conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-self-review Waiting for the author to post /self-reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants