Skip to content

fix(key-wallet): don't build asset locks on unconfirmed funds#836

Open
xdustinface wants to merge 2 commits into
dashpay:devfrom
xdustinface:fix/asset-lock-finality
Open

fix(key-wallet): don't build asset locks on unconfirmed funds#836
xdustinface wants to merge 2 commits into
dashpay:devfrom
xdustinface:fix/asset-lock-finality

Conversation

@xdustinface

@xdustinface xdustinface commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Identity registration and top-up could hang for 300 seconds (AssetLockFinalityTimeout) because the wallet funded asset locks with coins that were not final yet. A funding transaction built on such inputs can never receive an InstantSend lock, so Platform never accepts it. This fixes the two key-wallet defects from #832:

  • Asset-lock coin selection now only spends confirmed or InstantSend-locked coins (new opt-in TransactionBuilder::require_final_inputs).
  • A self-send change output only counts as confirmed balance when every parent is final, matching the Bitcoin Core IsTrusted behavior that Utxo::is_trusted documents. Before, change of an unconfirmed transaction showed up as confirmed and spendable.
  • Ordinary payments are unchanged and can still spend unconfirmed coins, now pinned by a regression test.

The remaining defect from the issue (U3, dash-spv credits its own broadcast locally without any network acceptance signal) is already tracked in #664. The BIP61 reject handling suggested in the issue is not an option since Dash Core removed the reject message.

Closes #832

Summary by CodeRabbit

  • Bug Fixes
    • Tightened self-send trusted detection so change outputs are trusted only when all funding inputs are final.
    • Wallet balance calculations no longer count unconfirmed change from self-sends as confirmed/trusted.
    • Asset-lock transaction building now requires final funding inputs (InstantSend/DIP-0010-eligible).
  • Tests
    • Added a test covering unconfirmed parent handling for self-send change trust and balances.
    • Added/updated asset-lock builder tests to reject non-final-only scenarios and prefer confirmed UTXOs.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a9d8c568-2d6d-4e28-9891-28fc14991e8b

📥 Commits

Reviewing files that changed from the base of the PR and between 17d64d5 and 2386559.

📒 Files selected for processing (5)
  • key-wallet/src/managed_account/managed_core_funds_account.rs
  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/wallet/managed_wallet_info/asset_lock_builder.rs
  • key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs
  • key-wallet/src/wallet/managed_wallet_info/transaction_building.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • key-wallet/src/wallet/managed_wallet_info/transaction_building.rs
  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/managed_account/managed_core_funds_account.rs
  • key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs
  • key-wallet/src/wallet/managed_wallet_info/asset_lock_builder.rs

📝 Walkthrough

Walkthrough

This PR tightens trusted-change handling and final-input selection in key-wallet. It also applies the new final-input rule to asset-lock construction and adds regression tests for unconfirmed inputs.

Changes

Trust and finality enforcement

Layer / File(s) Summary
Self-send change trust detection based on input finality
key-wallet/src/managed_account/managed_core_funds_account.rs, key-wallet/src/transaction_checking/wallet_checker.rs
Replaces the sent-based heuristic with all_inputs_final_and_ours and adds a test showing an unconfirmed-parent self-send stays untrusted and unconfirmed.
TransactionBuilder final-input flag
key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs, key-wallet/src/wallet/managed_wallet_info/transaction_building.rs
Adds a require_final_inputs flag and builder method, filters candidate inputs when enabled, and adds a test showing ordinary spends still accept unconfirmed inputs by default.
Asset-lock builder enforces final inputs
key-wallet/src/wallet/managed_wallet_info/asset_lock_builder.rs
Calls require_final_inputs() in both asset-lock build paths, adds a funded-UTXO helper, and adds tests for unconfirmed-only rejection and confirmed-input selection.

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

Sequence Diagram(s)

sequenceDiagram
  participant ManagedWalletInfo
  participant TransactionBuilder
  participant UtxoSet
  participant CoinSelection
  ManagedWalletInfo->>TransactionBuilder: require_final_inputs()
  ManagedWalletInfo->>TransactionBuilder: build_signed()
  TransactionBuilder->>UtxoSet: filter to confirmed or instantlocked UTXOs
  TransactionBuilder->>CoinSelection: assemble_unsigned(filtered inputs)
  CoinSelection-->>TransactionBuilder: selected funding inputs
  TransactionBuilder-->>ManagedWalletInfo: signed asset-lock transaction
Loading

Possibly related issues

Possibly related PRs

  • dashpay/rust-dashcore#823: Also changes TransactionBuilder coin selection and assembly behavior in the same input-selection path.

Suggested labels: ready-for-review

Suggested reviewers: ZocoLini

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The asset-lock and trust/balance fixes are present, but the linked dash-spv self-broadcast rejection/recrediting work is not shown. Add the dash-spv rejection/phantom-output reconciliation fix, or narrow the linked scope if that work is intentionally separate.
✅ 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 is clear and matches the main change: preventing asset-locks from using unconfirmed funds.
Out of Scope Changes check ✅ Passed The changes stay focused on asset-lock finality, trust accounting, and regression tests, with no clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.59%. Comparing base (b0a909c) to head (2386559).

Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #836      +/-   ##
==========================================
+ Coverage   73.44%   73.59%   +0.14%     
==========================================
  Files         324      324              
  Lines       72577    72697     +120     
==========================================
+ Hits        53306    53500     +194     
+ Misses      19271    19197      -74     
Flag Coverage Δ
core 76.94% <ø> (ø)
ffi 47.96% <ø> (-0.02%) ⬇️
rpc 20.00% <ø> (ø)
spv 90.49% <ø> (+0.22%) ⬆️
wallet 72.97% <100.00%> (+0.35%) ⬆️
Files with missing lines Coverage Δ
.../src/managed_account/managed_core_funds_account.rs 77.58% <100.00%> (+0.27%) ⬆️
...-wallet/src/transaction_checking/wallet_checker.rs 99.25% <100.00%> (+0.03%) ⬆️
...c/wallet/managed_wallet_info/asset_lock_builder.rs 88.13% <100.00%> (+4.88%) ⬆️
.../wallet/managed_wallet_info/transaction_builder.rs 85.65% <100.00%> (+0.47%) ⬆️
...wallet/managed_wallet_info/transaction_building.rs 87.87% <100.00%> (+0.53%) ⬆️

... and 7 files with indirect coverage changes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@key-wallet/src/managed_account/managed_core_funds_account.rs`:
- Around line 152-165: The trust recalculation in
update_utxos/confirm_transaction is order-dependent and can overwrite an already
trusted change output back to untrusted on reprocessing. Adjust the logic around
update_utxos in managed_core_funds_account::ManagedCoreFundsAccount so that an
existing outpoint retains its prior is_trusted state, or compute trust from a
source that does not depend on whether spent parents have already been removed
from self.utxos. Use the existing all_inputs_final_and_ours check and the trust
assignment path for new/existing UTXOs to ensure same-context self-sends remain
trusted across repeated passes.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c5f2ec04-9974-4a94-820c-e91ae6e69c6a

📥 Commits

Reviewing files that changed from the base of the PR and between a8a0968 and 17d64d5.

📒 Files selected for processing (5)
  • key-wallet/src/managed_account/managed_core_funds_account.rs
  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet/src/wallet/managed_wallet_info/asset_lock_builder.rs
  • key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs
  • key-wallet/src/wallet/managed_wallet_info/transaction_building.rs

Comment thread key-wallet/src/managed_account/managed_core_funds_account.rs
Asset-lock builders selected funding UTXOs filtered only by `is_spendable`, which deliberately admits unconfirmed mempool outputs. A non-final input is not InstantSend-eligible per DIP-0010, so the resulting funding transaction could never receive the InstantSend lock or ChainLock Platform requires, and identity registration or top-up died on a 300s `AssetLockFinalityTimeout`.

Add an opt-in `TransactionBuilder::require_final_inputs` that restricts coin selection to `is_confirmed || is_instantlocked` UTXOs and enable it in `build_asset_lock` and `build_asset_lock_with_signer`. Ordinary spends keep admitting unconfirmed inputs, now pinned by a regression test.

Part of dashpay#832 (U2).
`Utxo::is_trusted` was set from a flat `has_owned_input && change-addr` check, so change of a self-send spending a still-unconfirmed parent was credited to the confirmed balance bucket. `Utxo::is_trusted` documents Bitcoin Core `CWalletTx::IsTrusted` parity, which is recursive: a zero-conf output is trusted only if every parent is itself trusted.

Set `is_trusted` only when every input spends one of our own UTXOs that is confirmed, InstantSend-locked, or itself trusted. The stored parent flag carries the recursion transitively, and the spent parents are still present in the UTXO map at that point because insertion runs before spent-outpoint removal. Unknown or non-final parents deny trust, so funds the network may still drop never surface as confirmed.

Part of dashpay#832 (U1).
@xdustinface xdustinface force-pushed the fix/asset-lock-finality branch from 17d64d5 to 2386559 Compare July 2, 2026 14:12
@github-actions github-actions Bot added the ready-for-review CodeRabbit has approved this PR label Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-review CodeRabbit has approved this PR

Projects

None yet

1 participant