Skip to content

refactor(dpp): decode instant asset lock proofs with rust-dashcore's legacy asset lock decoder - #5423

Merged
shumkov merged 2 commits into
v5.0-devfrom
legacy-asset-lock-decoder-in-rust-dashcore
Oct 14, 2026
Merged

shumkov merged 2 commits into
v5.0-devfrom
legacy-asset-lock-decoder-in-rust-dashcore

Conversation

@shumkov

@shumkov shumkov commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

An instant asset lock proof carries a Core asset lock transaction as raw bytes the sender chooses. Neither the InstantSend lock nor the transition signature covers the asset lock's payload length prefix, and Platform has always read the payload whatever length that prefix announces. #5403 kept that behaviour once rust-dashcore started reading special payloads strictly through their prefix: it added decode_asset_lock_transaction, a byte-level workaround that zeroes the type bytes of a copy, decodes it as a classic transaction up to the payload, then reads and ignores the prefix.

That decoding now lives in rust-dashcore as a named, frozen legacy decoder in its own module, Transaction::deserialize_with_legacy_asset_lock_framing (dashpay/rust-dashcore#1167, merged). It is deliberately neither #[deprecated] nor behind a cargo feature: Platform has to call it for as long as it must agree with its older binaries and replay its chain, so there is nothing to migrate to. This PR uses it and deletes the workaround.

Based on #5422. This branch is built on #5422's branch (Core-v24-getdeploymentinfo-softforks; start on Dash Core v24), because both move the rust-dashcore pin along integration/v5.0-core-v24. Until #5422 merges, its commits also show in this PR's diff; this PR's own changes are the last two commits. Merge #5422 first.

What was done?

  • rust-dashcore pin: bumped to edc4d430 on integration/v5.0-core-v24. That is the previous head 379f0574 (fix(platform): start on Dash Core v24, which no longer reports softforks in getblockchaininfo #5422's pin) plus rust-dashcore#1167's two commits, cherry-picked with git cherry-pick -x: the function (a5ae6375), then its rename and move into its own module (edc4d430).
  • rs-dpp:
    • TryFrom<RawInstantLockProof> for InstantAssetLockProof calls Transaction::deserialize_with_legacy_asset_lock_framing.
    • decode_asset_lock_transaction and its imports are removed.
  • Tests:
    • rs-dpp, prefix widths: the test that the payload is read whatever its prefix announces now also covers 5- and 9-byte prefixes.
    • rs-dpp, differential test (new): test_raw_instant_lock_proof_decodes_every_transaction_as_the_byte_level_decoder_did keeps a test-only copy of the removed workaround. It checks that both decoders agree on 100,000 seeded mutations of a real asset lock, its witness form and its zero-input form, on Ok/Err, the decoded Transaction and the error string. Half of the mutations rewrite the payload length prefix in a random width.
    • drive-abci: should_create_the_same_identity_from_a_proof_with_another_payload_length_prefix also replaces the 1-byte prefix with a 3-byte one. The IdentityCreate must still execute with the same identity, fee and balance.

Out of scope: client-side code that builds a proof from Core's own bytes still uses plain dashcore::consensus::deserialize, for example the wasm-dpp2 InstantAssetLockProof constructor and rs-sdk-ffi identity/helpers.rs. It never sees a relayed, altered prefix. Every node decodes a proof through TryFrom<RawInstantLockProof>, whether from bincode, serde or platform_value, so that is where the change applies.

In-place changes to shipped generations

  • Instant asset lock proof transaction decoding: TryFrom<RawInstantLockProof>, reached by every funding transition (IdentityCreate, IdentityTopUp, AddressFundingFromAssetLock, ShieldFromAssetLock).
    • Protocol versions: all of them. The decode runs inside serde and is not versioned.
    • Why consensus cannot change:
      • The new function decodes every input exactly as the removed workaround did: the same Ok/Err, the same Transaction and the same error string, which reaches ProtocolError::DecodingError unchanged.
      • It is standalone in rust-dashcore. It shares no code with Decodable for Transaction or AssetLockPayload::consensus_decode, so later rust-dashcore changes to those cannot change it.
      • For any transaction that is not an asset lock (version ≥ 3 as i16, type 8), both the old and the new code call deserialize.
    • Evidence:
      • the rs-dpp differential test;
      • a differential run in rust-dashcore against a copy of the workaround: 16M seeded mutations at 7302d0a6 and at rust-dashcore dev, with no Ok/Err, transaction or error mismatch;
      • an independent review, which also probed edge cases: credit outputs at the 4,000,000-byte read limit, 5 MB scripts and a 100k-item witness;
      • the fix(platform)!: keep unknown Core payload layouts decodable #5403 tests, unchanged and passing.

How Has This Been Tested?

All at the final pin edc4d430:

  • cargo test -p dpp --lib instant_asset_lock_proof: 27 passed. This includes the new differential test, which decoded about 22k of the 100k mutations from non-canonical bytes, with every prefix width succeeding at least once.
  • cargo test -p dpp --lib asset_lock: 156 passed.
  • cargo test -p drive-abci --lib identity_create: 243 passed, including the prefix test with 1-, 3- and 5-byte prefixes.
  • cargo test -p drive-abci --lib asset_lock: 180 passed.
  • cargo test -p drive-abci --lib rpc::core (fix(platform): start on Dash Core v24, which no longer reports softforks in getblockchaininfo #5422's tests): 13 passed.
  • cargo clippy -p dpp -p drive-abci --tests -- -D warnings: clean.
  • The differential test goes red when the new call is replaced with plain deserialize.
  • rust-dashcore#1167 is merged with green CI. rust.yml passed on integration/v5.0-core-v24 at a5ae6375 and is running at edc4d430. Locally, the 46 decoder tests, cargo clippy -p dashcore --all-features --all-targets -- -D warnings and cargo doc with -D warnings pass at edc4d430.
  • The rename keeps the function body byte for byte, so the decoding at edc4d430 is the decoding at a5ae6375.

Breaking Changes

None. Consensus behaviour is unchanged at every protocol version: proofs decode exactly as before.

Checklist:

  • I have performed a self-review of my own code
  • 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

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

PR Hygiene · ff15245

  • Bots — coderabbitai skipped after its own rate limit · thepastaclaw ✓
  • Self-review — post /self-reviewed
  • Build running
  • 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.

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: dashpay/platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1fbe7196-2f7f-4fdb-9c6f-2414a488626f
📥 Commits

Reviewing files that changed from the base of the PR and between 9917fef and fff5d99.

⛔ Files ignored due to path filters: 1
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing: 8
  • Cargo.toml
  • packages/dashmate/configs/defaults/getBaseConfigFactory.js
  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dashmate/test/unit/config/configFile/migrateConfigFileFactory.spec.js
  • packages/rs-dpp/src/identity/state_transition/asset_lock_proof/instant/instant_asset_lock_proof.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs
  • packages/rs-drive-abci/src/rpc/core.rs
  • packages/rs-sdk/src/core/dash_core_client.rs

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 change updates Rust Dash Core dependency revisions, adds Core deployment lookup with a fallback for older Core versions, and updates instant asset-lock transaction decoding. Dashmate configuration and tests cover the new RPC whitelist entry and migration.

Changes: Core Deployment Lookup

Layer / File(s) Summary
Whitelist deployment RPC
packages/dashmate/configs/defaults/getBaseConfigFactory.js, packages/dashmate/configs/getConfigFileMigrationsFactory.js, packages/dashmate/test/unit/config/configFile/migrateConfigFileFactory.spec.js
The default Drive consensus RPC whitelist includes getdeploymentinfo. Migration 5.0.0-rc.2 adds the method to existing array-valued whitelists without removing other entries. Tests cover additional entries, null values, and config loading.
Core deployment lookup
packages/rs-drive-abci/src/rpc/core.rs
get_fork_info reads deployments through getdeploymentinfo and falls back to getblockchaininfo.softforks only when Core returns method-not-found. Tests cover Core v23 and v24 responses, retries, unknown deployments, and other errors.
Platform activation lookup
packages/rs-sdk/src/core/dash_core_client.rs
get_platform_activation_height reads mn_rr through getdeploymentinfo and uses getblockchaininfo only after method-not-found. Tests cover both response paths and missing data.

Instant Asset Lock Decoding

Layer / File(s) Summary
Use the dashcore transaction decoder
Cargo.toml, packages/rs-dpp/src/identity/state_transition/asset_lock_proof/instant/instant_asset_lock_proof.rs
The pinned Rust Dash Core dependencies use revision a5ae6375fc2582cf7e7eef123d4c23f36909257c. InstantAssetLockProof::try_from uses deserialize_ignoring_asset_lock_payload_length and maps failures to ProtocolError::DecodingError.
Validate payload-prefix handling
packages/rs-dpp/src/identity/state_transition/asset_lock_proof/instant/instant_asset_lock_proof.rs, packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs
Decoder tests compare seeded mutations with a byte-level reference decoder and test four CompactSize prefix widths. IdentityCreate tests compare fees and balances for altered prefix encodings.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Refactor

Suggested reviewers: quantumexplorer

Merge Risk: ⚪ Minimal · up to fff5d

Existing configurations receive the new RPC permission, and no actionable deployment-lookup or asset-lock decoding issue remains. The change is mergeable after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 75.68% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 37 functions across 7 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
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.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title accurately identifies the main refactor: instant asset lock proof decoding now uses rust-dashcore’s legacy asset lock decoder. It is specific, concise, and related to the primary changes.
Full details: Docstring Coverage

Explanation

Docstring coverage is 75.68% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 37 functions across 7 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ 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.

@thepastaclaw

thepastaclaw commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit ff15245) · triage: normal

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai ✓ · 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 14, 2026
@github-actions github-actions Bot added this to the v5.0.0 milestone Oct 14, 2026
@shumkov
shumkov force-pushed the legacy-asset-lock-decoder-in-rust-dashcore branch from fff5d99 to 79b3030 Compare October 14, 2026 05:57
@github-actions

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai not yet · 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.

@shumkov
shumkov force-pushed the legacy-asset-lock-decoder-in-rust-dashcore branch from 79b3030 to ff15245 Compare October 14, 2026 06:49
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai not yet · 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.

@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

No in-scope defects were found at ff15245. Static comparison of the removed workaround with the exact pinned rust-dashcore change supports unchanged decoding behavior, including signed-version selection, witness handling, payload reader limits, trailing-byte rejection, and error mapping; the added differential and execution tests cover the intended compatibility. No builds or tests were run in this static lane, and Rust workspace validation and JS builds remained queued in the supplied CI snapshot.

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); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: normal by gpt-6.1-sol (effort low) — The production changes replace a contained asset-lock decoder and add Core RPC compatibility handling, while most added code is tests, so the diff does not clearly meet the large-or-intricate critical-surface threshold.
  • 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 below 15% reserve: weekly 14% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — platform-versioning (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); 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 bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. and removed waiting-bots Waiting for the review bots to report on this head labels Oct 14, 2026
shumkov and others added 2 commits October 14, 2026 15:40
…legacy asset lock decoder

An instant asset lock proof's transaction is decoded from sender-chosen
bytes, and an asset lock's payload has always been read whatever length
its length prefix announces: neither the InstantSend lock nor the
transition signature covers the prefix. #5403 kept that working with
`decode_asset_lock_transaction`, a byte-level workaround on top of
rust-dashcore's strict decoder. rust-dashcore now provides the same
decoding as `Transaction::deserialize_ignoring_asset_lock_payload_length`
(dashpay/rust-dashcore#1167). The rust-dashcore pin moves to a5ae6375 on
integration/v5.0-core-v24, which is 379f0574 plus that commit
cherry-picked, so the workaround is deleted and the proof decodes through
it.

Consensus is unchanged at every protocol version: the new function gives
the same Ok/Err, decoded transaction and error string as the workaround
for every input. A new differential test checks this against a test-only
copy of the workaround over 100,000 seeded mutations of a real asset
lock, its witness form and its zero-input form. A differential run in
rust-dashcore covered 16M more. The #5403 tests pass unchanged, and now
also cover 5- and 9-byte prefixes. The drive-abci IdentityCreate test also
replaces the 1-byte prefix with a 3- and a 5-byte one, and checks the
same identity, fee and balance.

No red/green step applies: the change keeps the output identical. The
differential test goes red when the new call is replaced with plain
`deserialize`.

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

rust-dashcore renamed
`Transaction::deserialize_ignoring_asset_lock_payload_length` to
`Transaction::deserialize_with_legacy_asset_lock_framing` and moved it
into its own module (dashpay/rust-dashcore#1167), so that it reads as
what it is: a legacy decoder Platform keeps calling to agree with its
older binaries. The rust-dashcore pin moves to edc4d430 on
integration/v5.0-core-v24, which is a5ae6375 plus that commit
cherry-picked. Instant asset lock proofs and the differential test call
the new name.

Consensus is unchanged: the function body is byte-for-byte the one the
previous pin had. The differential test against the byte-level decoder,
the test_raw_instant_lock_proof_* tests and the drive-abci
IdentityCreate test with a 3- and a 5-byte payload length prefix pass.

No red/green step applies: nothing behaves differently.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shumkov
shumkov force-pushed the legacy-asset-lock-decoder-in-rust-dashcore branch from 734e7ea to f9076a4 Compare October 14, 2026 08:41
@shumkov
shumkov merged commit a1c437d into v5.0-dev Oct 14, 2026
5 of 6 checks passed
@shumkov
shumkov deleted the legacy-asset-lock-decoder-in-rust-dashcore branch October 14, 2026 08:41
HashEngineering pushed a commit to HashEngineering/platform that referenced this pull request Oct 19, 2026
Merge origin/v5.0-dev (51ee8a7) into v5.1-dev (5b5daf6).

Conflicts resolved:
- Cargo.toml: GroveDB from v5.0-dev (6.1.0, fc7028d8); rust-dashcore
  pinned to dev afbe5515, which carries the legacy asset lock decoder
  (dashpay#1167) that dpp's instant asset lock proofs need (dashpay#5423), plus
  everything v5.0-dev's edc4d430 backported.
- Cargo.lock: v5.1-dev's lockfile plus `cargo update -p dashcore -p grovedb`;
  no crates.io package changes.
- CHANGELOG.md: kept the [Unreleased] section above the rc.1, rc.2 and rc.3 entries,
  and updated its rust-dashcore pin note.

Semantic fixes for code v5.0-dev added against APIs that v5.1-dev changed:
- drive-abci wasm vector examples and wasm-sdk cache tests: secp256k1 0.33
  (from_secret_bytes, context-free from_secret_key) and dpp::bls instead of
  the removed dpp::bls_signatures re-export. The quorum public keys come
  out byte-identical.
- wasm-sdk fixtures regenerated with the examples for the latest protocol
  version (15), as their README prescribes.

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

Claude-Session: https://claude.ai/code/session_01PSi8cX229kW2fmLxKW6ir4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. 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