Skip to content

feat(dpp): add max_asset_lock_transaction_inputs limit to prevent stuck funds#3491

Merged
QuantumExplorer merged 5 commits into
v3.1-devfrom
feat/max-asset-lock-inputs
Apr 23, 2026
Merged

feat(dpp): add max_asset_lock_transaction_inputs limit to prevent stuck funds#3491
QuantumExplorer merged 5 commits into
v3.1-devfrom
feat/max-asset-lock-inputs

Conversation

@lklimek
Copy link
Copy Markdown
Contributor

@lklimek lklimek commented Apr 14, 2026

Issue being fixed or feature implemented

Fixes #3399

Imagine you are a user funding a Platform address with tDASH accumulated from many small mining rewards. You send 400 tDASH, the Core transaction succeeds — but Platform rejects the state transition with a cryptic "Tx too large" error. Your funds are stuck: gone from Core wallet, never credited to Platform. This change catches the problem before the Core broadcast, with a clear error message telling you to consolidate UTXOs first.

What was done?

Added a max_asset_lock_transaction_inputs limit (100) to prevent asset lock transactions from exceeding Platform's 20KB max_state_transition_size limit.

Size math: Each input adds ~184 bytes to the state transition (148 bytes for the transaction input + 36 bytes for the InstantLock outpoint). At 100 inputs the total is ~18,877 bytes — fits within the 20,480 byte limit with ~1,600 bytes (~8%) margin.

Changes across 3 packages:

rs-platform-version:

  • Added max_asset_lock_transaction_inputs: u16 to IdentityTransitionAssetLockVersions
  • Set to 100 in all version configs (v1, v2, v3)

rs-dpp:

  • New consensus error IdentityAssetLockTransactionTooManyInputsError (code 10534) with actionable message: "Consolidate UTXOs before creating the asset lock"
  • Added input count validation as the first check in validate_asset_lock_transaction_structure_v0
  • 3 unit tests: reject at 101, accept at 100, accept at 1

wasm-dpp:

  • WASM binding for the new error type with getMaxInputs(), getActualInputs(), getCode(), and message accessors

How Has This Been Tested?

  • cargo check -p dpp --features=validation — clean
  • cargo check -p dash-sdk — clean
  • cargo check -p drive-abci — clean
  • cargo test -p dpp --features=validation -- asset_lock_transaction — 5/5 pass (3 new + 2 existing)

Breaking Changes

None. The new limit (100 inputs) is well above typical transaction sizes. Only transactions that would have been rejected by Platform's existing 20KB state transition size limit are now caught earlier with a better error message.

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

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Co-authored by Claudius the Magnificent AI Agent

Summary by CodeRabbit

  • New Features
    • Asset lock transactions now enforce configurable maximum input limits. Protocol version 3 limits to 100 inputs; earlier versions allow unlimited.
    • Added validation error reporting when transaction inputs exceed the configured limit.
    • WebAssembly bindings updated with new error type and accessor methods for JavaScript integration.

…ck funds

Asset lock transactions with too many inputs (from many small UTXOs) can exceed
Platform's 20KB state transition size limit. Core accepts the transaction but
Platform rejects it, leaving funds stuck. This adds a configurable input count
limit (default 100) that validates early with a clear error message advising
users to consolidate UTXOs first.

Closes #3399

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 14, 2026

Warning

Rate limit exceeded

@lklimek has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 48 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 48 minutes and 48 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4ff73328-0fcd-4e28-9a8e-8b90b800443d

📥 Commits

Reviewing files that changed from the base of the PR and between 71b65fb and cb62127.

📒 Files selected for processing (1)
  • packages/rs-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/v0/mod.rs
📝 Walkthrough

Walkthrough

This PR introduces a new consensus error IdentityAssetLockTransactionTooManyInputsError to enforce maximum input limits on asset lock transactions. The error type is integrated across DPP, platform versioning, and WASM packages, with validation logic added to the asset lock transaction structure validator and configuration parameters distributed across version specifications.

Changes

Cohort / File(s) Summary
Error Type Definition
packages/rs-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_too_many_inputs_error.rs
New error struct capturing max_inputs and actual_inputs with thiserror and bincode derives, public accessors, and From impl for ConsensusError conversion.
Error Integration
packages/rs-dpp/src/errors/consensus/basic/basic_error.rs, packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs, packages/rs-dpp/src/errors/consensus/codes.rs
Added error variant to BasicError, module re-export, and error code mapping (10534) within Identity Errors range.
Asset Lock Validation
packages/rs-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/mod.rs, packages/rs-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/v0/mod.rs
Updated validator signature to accept max_inputs parameter; v0 validator now rejects transactions exceeding input limit with new error, includes unit tests validating boundary conditions.
Platform Version Configuration
packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/mod.rs, packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v*.rs
Added max_asset_lock_transaction_inputs: u16 field to IdentityTransitionAssetLockVersions, set to u16::MAX for v1/v2 and 100 for v3.
WASM Bindings
packages/wasm-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_too_many_inputs_error.rs, packages/wasm-dpp/src/errors/consensus/basic/identity/mod.rs, packages/wasm-dpp/src/errors/consensus/consensus_error.rs
Created WebAssembly wrapper exposing getMaxInputs(), getActualInputs(), getCode(), and message() getters; added conversion logic and module re-export.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The changes follow consistent patterns across multiple files (error definition, integration, configuration) with moderate logic density in the validator logic. Homogeneous repetition in version configuration files and standard WASM bindings reduce complexity, though the validator logic update and its test coverage warrant careful review.

Poem

🐰 A bouncing validation hops into place,
Counting inputs with elegant grace,
No more transactions too large and too wide,
One hundred or less, we stand with pride! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 summarizes the main change: adding a max_asset_lock_transaction_inputs limit to prevent stuck funds, which is the core objective.
Linked Issues check ✅ Passed The PR fully addresses the linked issue #3399 by implementing pre-broadcast validation, providing an actionable error message, and preventing asset lock transactions with excessive inputs from producing oversized state transitions.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the max_asset_lock_transaction_inputs limit: error definitions, validation logic, platform version config updates, WASM bindings, and unit tests.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/max-asset-lock-inputs

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 and usage tips.

@github-actions github-actions Bot added this to the v3.1.0 milestone Apr 14, 2026
@lklimek lklimek requested a review from Copilot April 15, 2026 06:44
@lklimek
Copy link
Copy Markdown
Contributor Author

lklimek commented Apr 15, 2026

Needs to be tested with dash-evo-tool

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a protocol-configured cap on Asset Lock transaction input count so oversized asset-lock state transitions are rejected before Core broadcast, avoiding “stuck funds” scenarios and providing a clearer, actionable consensus error.

Changes:

  • Introduces max_asset_lock_transaction_inputs (set to 100) in platform version configs (v1–v3).
  • Enforces the new limit during asset lock transaction structure validation and adds unit tests around the boundary.
  • Wires a new consensus error (code 10534) through Rust + WASM error surfaces.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/mod.rs Adds max_asset_lock_transaction_inputs to identity asset-lock version config struct.
packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v1.rs Sets max asset-lock inputs to 100 for v1.
packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v2.rs Sets max asset-lock inputs to 100 for v2.
packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v3.rs Sets max asset-lock inputs to 100 for v3.
packages/rs-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/mod.rs Threads platform-version limit into v0 validator call.
packages/rs-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/v0/mod.rs Implements input-count guard and adds unit tests for 1/100/101 inputs.
packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs Exposes the new identity consensus error type.
packages/rs-dpp/src/errors/consensus/basic/basic_error.rs Adds the new BasicError enum variant for the consensus error.
packages/rs-dpp/src/errors/consensus/codes.rs Assigns consensus error code 10534.
packages/rs-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_too_many_inputs_error.rs Defines the new consensus error type and message.
packages/wasm-dpp/src/errors/consensus/basic/identity/mod.rs Registers the new WASM error module + re-export.
packages/wasm-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_too_many_inputs_error.rs Adds WASM bindings/accessors for the new error type.
packages/wasm-dpp/src/errors/consensus/consensus_error.rs Maps the new BasicError variant into the WASM consensus error conversion.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@lklimek lklimek marked this pull request as ready for review April 15, 2026 14:41
@thepastaclaw
Copy link
Copy Markdown
Collaborator

thepastaclaw commented Apr 15, 2026

✅ Review complete (commit 3656c69)

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 15, 2026

Codecov Report

❌ Patch coverage is 88.29787% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.83%. Comparing base (bc21822) to head (cb62127).
⚠️ Report is 21 commits behind head on v3.1-dev.

Files with missing lines Patch % Lines
...alidate_asset_lock_transaction_structure/v0/mod.rs 87.50% 11 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           v3.1-dev    #3491      +/-   ##
============================================
- Coverage     84.84%   84.83%   -0.01%     
============================================
  Files          2476     2476              
  Lines        267915   267827      -88     
============================================
- Hits         227303   227206      -97     
- Misses        40612    40621       +9     
Components Coverage Δ
dpp 82.00% <88.29%> (+<0.01%) ⬆️
drive 84.21% <ø> (ø)
drive-abci 87.46% <ø> (-0.03%) ⬇️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.10% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 55.66% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

lklimek and others added 2 commits April 20, 2026 15:44
- Use `u16::try_from(input_count).unwrap_or(u16::MAX)` instead of
  `input_count as u16` when constructing
  `IdentityAssetLockTransactionTooManyInputsError`, so the reported
  count saturates at u16::MAX rather than silently wrapping for the
  (unrealistic) `input_count > 65535` case.
- Strengthen `should_accept_transaction_at_max_inputs` by also
  asserting `result.is_valid()`, matching the pattern used in
  `should_accept_transaction_with_one_input`. The existing
  absence-of-specific-error check is kept.

Addresses copilot-pull-request-reviewer nits on PR #3491.
Third nit (remove `use crate::errors::ProtocolError;`) declined:
the derive-generated code for `PlatformSerialize`/`PlatformDeserialize`
on `IdentityAssetLockTransactionTooManyInputsError` references the
`ProtocolError` type, so the import is not actually unused.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
output_index: u32,
max_inputs: u16,
) -> ConsensusValidationResult<TxOut> {
let input_count = transaction.input.len();
Copy link
Copy Markdown
Contributor Author

@lklimek lklimek Apr 20, 2026

Choose a reason for hiding this comment

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

@QuantumExplorer please check if we don't need new version of validate_asset_lock_transaction_structure/v0/mod.rs

…set-lock inputs

Raise `max_asset_lock_transaction_inputs` to `u16::MAX` on v1 and v2
state-transition version constants so previously valid asset-lock
transactions remain valid across upgrades. Introduce the new 100-input
limit only at v3, which is the latest/target protocol version for this
change.

The validator (`validate_asset_lock_transaction_structure_v0`) is
version-agnostic and takes `max_inputs` as a runtime argument sourced
from the platform version, so no new validator version is required.

Addresses self-authored review comments on PR #3491 (lklimek).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lklimek lklimek added the ready for final review Ready for the final review. If AI was involved in producing this PR, it has already had a reviewer. label Apr 20, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/rs-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/v0/mod.rs`:
- Around line 67-79: The fixture currently embeds a WIF private-key literal in
make_asset_lock_transaction (private_key_hex / PrivateKey::from_str); replace it
with a programmatically generated key like the one-time key: create a
dashcore::secp256k1::SecretKey via thread_rng(), wrap it with
PrivateKey::new(Network::Testnet) to produce private_key, derive public_key from
that private_key (as is done for one_time_private_key/public_key) and use the
resulting public key/hash instead of parsing a string; remove the hard-coded
private_key_hex and PrivateKey::from_str usage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9c6d7d62-f1b4-4a7e-b9a0-1bc0cb16992d

📥 Commits

Reviewing files that changed from the base of the PR and between bc21822 and 71b65fb.

📒 Files selected for processing (13)
  • packages/rs-dpp/src/errors/consensus/basic/basic_error.rs
  • packages/rs-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_too_many_inputs_error.rs
  • packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs
  • packages/rs-dpp/src/errors/consensus/codes.rs
  • packages/rs-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/mod.rs
  • packages/rs-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/v0/mod.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/mod.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v1.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v2.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v3.rs
  • packages/wasm-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_too_many_inputs_error.rs
  • packages/wasm-dpp/src/errors/consensus/basic/identity/mod.rs
  • packages/wasm-dpp/src/errors/consensus/consensus_error.rs

Replace the hardcoded testnet WIF literal in `make_asset_lock_transaction`
with a programmatically generated key via `SecretKey::new(&mut rng)` +
`PrivateKey::new(..., Network::Testnet)`, mirroring the existing
`one_time_private_key` pattern. The key was only ever used to derive a
`pubkey_hash` for `ScriptBuf::new_p2pkh`, so a random key per run is
semantically equivalent and keeps secret scanners quiet.

Addresses coderabbitai[bot] review comment on PR #3491.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

This change adds a new asset-lock input-count guard plus the matching consensus/WASM error plumbing, but the assigned SHA still has two blocking problems. First, the new check only runs during asset-lock proof / state-transition validation, while the main JS register/top-up flow broadcasts the Core asset-lock transaction before it ever builds the proof, so the advertised stuck-funds prevention does not actually happen. Second, the 100-input cap is written directly into the existing v1/v2/v3 platform-version snapshots instead of being gated behind a new validation version, which retroactively changes historical protocol behavior.

Reviewed commit: 3656c69

🔴 2 blocking | 🟡 1 suggestion(s)

🤖 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-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/v0/mod.rs`:
- [BLOCKING] lines 15-22: The new input-limit check still runs only after the asset lock transaction has already been broadcast
  This guard rejects oversized asset-lock transactions during `validate_asset_lock_transaction_structure_v0`, but that validator is only reached from asset-lock proof / state-transition validation. In the actual JS client flow, the asset-lock transaction is still broadcast first (`packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/register.ts:27-32` and `.../topUp.ts:25-30`), and only afterwards does `createAssetLockProof()` wait for metadata / InstantLock and invoke DPP validation (`packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/internal/createAssetLockProof.ts:24-95`). So on this SHA, a 101+ input asset-lock can still be sent to Core before this error ever fires, which means the stuck-funds scenario described in the PR is still present in the main registration/top-up path. The limit needs to be enforced before `broadcastTransaction`, in the asset-lock transaction creation path, not only during proof validation.
- [SUGGESTION] lines 15-18: `input_count as u16` can wrap and report the wrong actual input count
  `transaction.input.len()` is a `usize`, but the new error payload stores `actual_inputs` as `u16` via an unchecked `as` cast. For pathological transactions with at least 65536 inputs, validation will still fail, but the reported `actual_inputs` value wraps modulo 2^16 and can contradict reality when surfaced through the Rust and WASM error accessors. Saturating or checked conversion keeps the diagnostic accurate without changing the validation outcome.

In `packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v1.rs`:
- [BLOCKING] lines 21-25: The 100-input cap is retrofitted into existing protocol snapshots instead of behind a new version gate
  `validate_asset_lock_transaction_structure()` still dispatches only on version `0`, so the only thing changing consensus behavior here is the new `max_asset_lock_transaction_inputs` value. This SHA writes that value directly into the existing `STATE_TRANSITION_VERSIONS_V1`, and the same pattern is repeated in `.../v2.rs` and `.../v3.rs`, which means old and new binaries running the same protocol version can now disagree about whether a high-input asset-lock transaction is valid. That is exactly the kind of historical-rule mutation the versioned dispatch system is supposed to avoid. If this limit is meant to be a new consensus rule, it needs a new validation version (or a new protocol snapshot that references one) rather than editing existing v1/v2/v3 constants in place.

Comment on lines +15 to +22
max_inputs: u16,
) -> ConsensusValidationResult<TxOut> {
let input_count = transaction.input.len();
if input_count > max_inputs as usize {
return ConsensusValidationResult::new_with_error(
IdentityAssetLockTransactionTooManyInputsError::new(input_count as u16, max_inputs)
.into(),
);
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.

🔴 Blocking: The new input-limit check still runs only after the asset lock transaction has already been broadcast

This guard rejects oversized asset-lock transactions during validate_asset_lock_transaction_structure_v0, but that validator is only reached from asset-lock proof / state-transition validation. In the actual JS client flow, the asset-lock transaction is still broadcast first (packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/register.ts:27-32 and .../topUp.ts:25-30), and only afterwards does createAssetLockProof() wait for metadata / InstantLock and invoke DPP validation (packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/internal/createAssetLockProof.ts:24-95). So on this SHA, a 101+ input asset-lock can still be sent to Core before this error ever fires, which means the stuck-funds scenario described in the PR is still present in the main registration/top-up path. The limit needs to be enforced before broadcastTransaction, in the asset-lock transaction creation path, not only during proof validation.

source: ['codex']

🤖 Fix this 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-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/v0/mod.rs`:
- [BLOCKING] lines 15-22: The new input-limit check still runs only after the asset lock transaction has already been broadcast
  This guard rejects oversized asset-lock transactions during `validate_asset_lock_transaction_structure_v0`, but that validator is only reached from asset-lock proof / state-transition validation. In the actual JS client flow, the asset-lock transaction is still broadcast first (`packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/register.ts:27-32` and `.../topUp.ts:25-30`), and only afterwards does `createAssetLockProof()` wait for metadata / InstantLock and invoke DPP validation (`packages/js-dash-sdk/src/SDK/Client/Platform/methods/identities/internal/createAssetLockProof.ts:24-95`). So on this SHA, a 101+ input asset-lock can still be sent to Core before this error ever fires, which means the stuck-funds scenario described in the PR is still present in the main registration/top-up path. The limit needs to be enforced before `broadcastTransaction`, in the asset-lock transaction creation path, not only during proof validation.

Comment on lines +22 to +25
required_asset_lock_duff_balance_for_processing_start_for_address_funding: 50000,
validate_asset_lock_transaction_structure: 0,
validate_instant_asset_lock_proof_structure: 0,
max_asset_lock_transaction_inputs: 100,
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.

🔴 Blocking: The 100-input cap is retrofitted into existing protocol snapshots instead of behind a new version gate

validate_asset_lock_transaction_structure() still dispatches only on version 0, so the only thing changing consensus behavior here is the new max_asset_lock_transaction_inputs value. This SHA writes that value directly into the existing STATE_TRANSITION_VERSIONS_V1, and the same pattern is repeated in .../v2.rs and .../v3.rs, which means old and new binaries running the same protocol version can now disagree about whether a high-input asset-lock transaction is valid. That is exactly the kind of historical-rule mutation the versioned dispatch system is supposed to avoid. If this limit is meant to be a new consensus rule, it needs a new validation version (or a new protocol snapshot that references one) rather than editing existing v1/v2/v3 constants in place.

source: ['claude', 'codex']

🤖 Fix this 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-platform-version/src/version/dpp_versions/dpp_state_transition_versions/v1.rs`:
- [BLOCKING] lines 21-25: The 100-input cap is retrofitted into existing protocol snapshots instead of behind a new version gate
  `validate_asset_lock_transaction_structure()` still dispatches only on version `0`, so the only thing changing consensus behavior here is the new `max_asset_lock_transaction_inputs` value. This SHA writes that value directly into the existing `STATE_TRANSITION_VERSIONS_V1`, and the same pattern is repeated in `.../v2.rs` and `.../v3.rs`, which means old and new binaries running the same protocol version can now disagree about whether a high-input asset-lock transaction is valid. That is exactly the kind of historical-rule mutation the versioned dispatch system is supposed to avoid. If this limit is meant to be a new consensus rule, it needs a new validation version (or a new protocol snapshot that references one) rather than editing existing v1/v2/v3 constants in place.

Comment on lines +15 to +18
max_inputs: u16,
) -> ConsensusValidationResult<TxOut> {
let input_count = transaction.input.len();
if input_count > max_inputs as usize {
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.

🟡 Suggestion: input_count as u16 can wrap and report the wrong actual input count

transaction.input.len() is a usize, but the new error payload stores actual_inputs as u16 via an unchecked as cast. For pathological transactions with at least 65536 inputs, validation will still fail, but the reported actual_inputs value wraps modulo 2^16 and can contradict reality when surfaced through the Rust and WASM error accessors. Saturating or checked conversion keeps the diagnostic accurate without changing the validation outcome.

💡 Suggested change
Suggested change
max_inputs: u16,
) -> ConsensusValidationResult<TxOut> {
let input_count = transaction.input.len();
if input_count > max_inputs as usize {
let input_count = transaction.input.len();
if input_count > max_inputs as usize {
let actual_inputs = u16::try_from(input_count).unwrap_or(u16::MAX);
return ConsensusValidationResult::new_with_error(
IdentityAssetLockTransactionTooManyInputsError::new(actual_inputs, max_inputs)
.into(),
);
}

source: ['claude']

🤖 Fix this 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-dpp/src/identity/state_transition/asset_lock_proof/validate_asset_lock_transaction_structure/v0/mod.rs`:
- [SUGGESTION] lines 15-18: `input_count as u16` can wrap and report the wrong actual input count
  `transaction.input.len()` is a `usize`, but the new error payload stores `actual_inputs` as `u16` via an unchecked `as` cast. For pathological transactions with at least 65536 inputs, validation will still fail, but the reported `actual_inputs` value wraps modulo 2^16 and can contradict reality when surfaced through the Rust and WASM error accessors. Saturating or checked conversion keeps the diagnostic accurate without changing the validation outcome.

Copy link
Copy Markdown
Member

@QuantumExplorer QuantumExplorer left a comment

Choose a reason for hiding this comment

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

Approved

@QuantumExplorer QuantumExplorer merged commit 257d264 into v3.1-dev Apr 23, 2026
38 checks passed
@QuantumExplorer QuantumExplorer deleted the feat/max-asset-lock-inputs branch April 23, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for final review Ready for the final review. If AI was involved in producing this PR, it has already had a reviewer.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Asset lock state transition rejected as "Tx too large" after Core broadcast — funds stuck

4 participants