Skip to content

test(contract): expect only the first schema violation of a document at protocol version 15 - #5614

Merged
shumkov merged 1 commit into
v5.1-devfrom
shumkov/v51-contract-schema-tests
Oct 28, 2026
Merged

shumkov merged 1 commit into
v5.1-devfrom
shumkov/v51-contract-schema-tests

Conversation

@shumkov

@shumkov shumkov commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

Since #5533, 14 JS contract tests fail on v5.1-dev. Each fails the same way: expected [ Array(1) ] to have a length of 2 but got 1.

  • @dashevo/dpns-contract: 3 tests (label, normalizedLabel and normalizedParentDomainName length).
  • @dashevo/dashpay-contract: 8 tests (profile avatar properties, and contactRequest encryptedAccountLabel and autoAcceptProof types).
  • @dashevo/withdrawals-contract: 3 tests (pooling, outputScript and status types).

Root cause

The tests run at dpp.protocolVersion, the latest version (15 on v5.1-dev). #5533 switched protocol version 15 to validate_document 2 (CONTRACT_VERSIONS_V7). It checks a document with the native DocumentSchemaValidator, which stops at the first violation and returns one JsonSchemaError (validate_document_properties_v2 wraps validator.validate(..) -> Option<JsonSchemaError>). The module documentation of validation_schema/validate/v0 says so:

The walk stops at the first violation it meets, the one consensus reports, and meets them in a fixed order, not in the order the schema writes its keywords […] a string's minLength, maxLength and pattern […] then format […] a value breaking several can get another violation first.

Protocol version 14 still uses validate_document 1, the jsonschema crate, which collects every error.

#5538 is about registration-time schema checks (check_document_type_schema 1). Its only edit on the document-validation path lets a plain $id contain $. It doesn't change how a document is checked or how many errors it gets. Rebuilding wasm-dpp at each commit shows #5533 is the first failing commit (table under "How Has This Been Tested?").

How CI missed it:

What each failing case reports, from document.validate() run on this branch's wasm-dpp build:

Case PV14 (jsonschema crate) PV15 (native)
dpns label / normalizedLabel / normalizedParentDomainName too long pattern, maxLength maxLength
dashpay avatarUrl: '' format, minLength minLength
dashpay missing avatarUrl / avatarHash / avatarFingerprint (dependentRequired) required ×2, one per dependentRequired entry that names the missing property required
dashpay avatarHash / avatarFingerprint / encryptedAccountLabel / autoAcceptProof = 'notAnArray' type ×2, from type: array and from the byteArray keyword type
withdrawals pooling / status = 'string' type, enum type
withdrawals outputScript = 1 type ×2, from type: array and from byteArray type

Intended, not a regression

  • Each of these 14 documents is still rejected. The error is a correct JsonSchemaError for a real violation, at the right instance path.
  • The lost second error was one of two things:
    • The same error from a second source: byteArray repeating type, or a second dependentRequired entry naming the same missing property.
    • A further violation of the same value: pattern, format or enum. The tests that target those keywords alone ("should follow pattern", "should be of type URL", "should be within enum range") still pass.
  • Reporting only the first violation, in a fixed order, is the documented design of validate_document 2 (quoted above). feat(dpp)!: validate documents natively at protocol version 15 #5533's description says: "Only info, which the results hash does not cover, can differ: […] a document breaking two keywords […] can get another violation first".
  • Protocol version 14 still reports both errors (checked with document.validate(14) on the same build).

Consensus visibility

The length of the error list is not consensus-visible. Which error comes first is visible to clients, but it is not in the block results hash or in fees:

  • process_validation_result (v0 and v1) passes only errors.first() / errors.remove(0) into StateTransitionExecutionResult. execute_event only checks consensus_errors.is_empty(), so fees don't depend on how many errors there are.
  • ExecTxResult.code is the consensus error's code: 10101 (JsonSchemaError) for every keyword. info carries the serialized first error.
  • No other drive-abci consumer of a document validation result reads the error count or keyword: the batch, create/replace/delete and moderation validators forward the whole list into a paid nonce-bump result. check_tx reads errors.first(), but only for the mempool.
  • Tenderdash hashes only Code, Data and GasUsed into the results hash (deterministicExecTxResult). info, and so which keyword is reported, is not consensus-checked.
  • For a value that breaks several keywords, PV15 can report a different first keyword than PV14 (for example maxLength instead of pattern). That is client-visible in info, under the same error code, and feat(dpp)!: validate documents natively at protocol version 15 #5533 accepted it explicitly for the unreleased protocol version 15. PV14 behaviour is unchanged.

What was done?

Test changes only; no code changes.

  • The 14 failing tests now expect exactly one error. Each asserts the error's keyword with its instance path or params.
  • dpns: the length tests expect maxLength. The normalizedParentDomainName case ("should be less than 190 chars", 191 characters) now uses 64 characters and is named "should be less than 63 chars", matching the schema's maxLength of 63.
  • dashpay:
    • The empty avatarUrl test expects minLength.
    • The three "should be present if other avatar properties are present" tests no longer expect a second required error.
    • The avatar dependentRequired map is symmetric, so one reported error no longer shows which entry fired, and removing an entry would go unnoticed. Three new tests ("should require the other avatar properties when present alone") each set one avatar property alone; each fails if that property's entry is removed.
  • withdrawals: the three type tests now also assert the instance path.

How Has This Been Tested?

Red → green, locally, with @dashevo/wasm-dpp built from this branch's base (yarn workspace @dashevo/wasm-dpp build, as CI's "Build JS packages" step does via yarn build):

Package origin/v5.1-dev (cd00e8382d) This PR
@dashevo/dpns-contract 28 passing, 3 failing 31 passing
@dashevo/dashpay-contract 32 passing, 8 failing 43 passing (40 + 3 new)
@dashevo/withdrawals-contract 19 passing, 3 failing 22 passing

Which commit started the failures, with the unchanged specs and wasm-dpp rebuilt at each commit:

Commit dpns dashpay withdrawals
eb3e1b8272 (before #5533) 31 passing (CI as well) 40 passing 22 passing
2933198012 (#5533) 3 failing 8 failing 3 failing
88c31c2bc1 (#5538) 3 failing (CI) — —

Mutation check, with the schema JSON edited temporarily and then restored:

  • Removing any one of the three avatar dependentRequired entries fails exactly the matching new test and nothing else. Without the new tests, none of these removals was caught.
  • Raising dpns label maxLength to 64 fails "should be less than 63 chars", which reports pattern instead.

Other packages on the same validator, all passing, unchanged: moderation-charters (75), masternode-reward-shares (9), token-history (31), keyword-search (20), wallet-utils (10), app-connect (13), document-history (19).

  • @dashevo/wasm-dpp: test:node gives 235 passing, 0 failing (533 pending are existing skips), and test:types passes. test:browsers was not run: there is no Chrome or Firefox on the test machine, and CI runs it nightly only.
  • yarn workspace <pkg> lint passes for the three changed packages.

Breaking Changes

None. Test expectations only.

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
  • 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
  • If I added or changed a system contract's document schemas, I checked the contract 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 · aa0f616

  • Bots — thepastaclaw ✓
  • Self-review — post /self-reviewed
  • Build green
  • 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

  • Tests
    • Updated validation checks for profile avatar fields and encrypted account values, including missing fields and incorrect value types.
    • Added checks that domain labels and parent names exceeding length limits are rejected.
    • Refined withdrawal validation assertions to identify the specific invalid property and expected error count.

…at protocol version 15

From protocol version 15 (`validate_document` 2), documents are checked by
the native document schema validator. It stops at the first violation it
meets, in a fixed keyword order, and reports that single JsonSchemaError.
The jsonschema crate, which protocol version 14 still uses, listed every
violation. Fourteen DPNS, DashPay and withdrawals contract tests still
expected two errors.

Each of those tests now expects one error and asserts its keyword with its
instance path or params. Where the value breaks several keywords, the
reported keyword follows the native order:
- DPNS names over 63 characters report `maxLength`, which is checked before
  `pattern`. The separate "should follow pattern" tests still cover the
  patterns. The parent domain name case now uses 64 characters instead of
  191, so it exercises the 63-character limit.
- An empty DashPay `avatarUrl` reports `minLength`, which is checked before
  `format`.
- A non-array byte array reports one `type` error. The `type` keyword and
  the `byteArray` keyword each reported one before.
- A missing avatar property reports one `required` error. Before, each
  dependentRequired entry that names it reported one. The avatar
  dependencies are symmetric, so a single error no longer shows which entry
  fired. New tests with one avatar property present alone fail if that
  property's entry is removed.
- The withdrawals `type` cases now also assert the instance path.

Test would have caught this in CI: 14 failing before this change on
origin/v5.1-dev (dpns 3, dashpay 8, withdrawals 3). After it, dpns 31,
dashpay 43 and withdrawals 22 pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shumkov shumkov added this to the v5.1.0 milestone Oct 28, 2026
@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between cd00e83 and aa0f616.

Files selected for processing: 3
  • packages/dashpay-contract/test/unit/schema.spec.js
  • packages/dpns-contract/test/unit/dpnsContract.spec.js
  • packages/withdrawals-contract/test/unit/withdrawalsContract.spec.js

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The pull request updates validation test expectations in the Dashpay, DPNS, and withdrawals contract suites. The tests now check revised error counts, keywords, missing-property details, and instance paths.

Changes: Dashpay schema validation

Layer / File(s) Summary
Avatar and account validation assertions
packages/dashpay-contract/test/unit/schema.spec.js
Avatar tests expect updated single-error results and check missing required properties for URL-only, hash-only, and fingerprint-only cases. Encrypted account label and auto-accept proof type tests also expect one error.

DPNS domain-document validation

Layer / File(s) Summary
Domain field length assertions
packages/dpns-contract/test/unit/dpnsContract.spec.js
Overlong label and normalized-label tests expect one maxLength error. The normalized parent-name test uses a 64-character value and expects one maxLength error.

Withdrawals contract validation

Layer / File(s) Summary
Property type error assertions
packages/withdrawals-contract/test/unit/withdrawalsContract.spec.js
The pooling, outputScript, and status tests expect one validation error and assert the corresponding instancePath.

Priority: Low

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Other

Suggested reviewers: quantumexplorer

Merge Risk: Minimal · up to aa0f6

No actionable merge-blocking risk was identified in these test-only updates.

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title states the main change: the tests for protocol version 15 now expect only the first schema violation of a document. The change touches DPNS, DashPay, and withdrawals contract tests, and the …
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
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: Title check

Explanation

The title states the main change: the tests for protocol version 15 now expect only the first schema violation of a document. The change touches DPNS, DashPay, and withdrawals contract tests, and the title's test(contract) scope matches a test-only change. The title is specific and accurate. It does not name the DashPay avatar dependency tests, which are a secondary addition, and that omission is acceptable.

Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. 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 0 functions across 3 files.

Finishing Touches
📝 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.

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Oct 28, 2026
@thepastaclaw

thepastaclaw commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit aa0f616) · triage: low

@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

The commit only updates contract-test expectations for protocol version 15's documented first-violation validation behavior and adds targeted avatar dependency coverage. The changed assertions match the schemas and native validator ordering, and the affected package tests, builds, and lint checks passed in CI; no in-scope issues were found.

Review provenance

Source: reviewer 1: glm-5.3-flash (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); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: low by gpt-6.1-sol (effort low) — This is a small, well-contained test-only change updating expected validation-error counts for an already established protocol behavior, with no production or consensus logic modified.
  • Phase 1 reviewers: glm-5.3-flash — general (completed, effort high); agent phase1-reviewer
  • Phase 1 model: glm-5.3-flash — zai quota: 5h 99% left, weekly 95% left; passed over gemini-3.8-flash-high (antigravity quota lookup failed)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort medium); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort medium); agent phase2-reviewer

@github-actions

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
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
@shumkov
shumkov merged commit c9c98b5 into v5.1-dev Oct 28, 2026
76 of 78 checks passed
@shumkov
shumkov deleted the shumkov/v51-contract-schema-tests branch October 28, 2026 02:39
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