Skip to content

platform-wallet: expose which tracked asset locks a running funding call is consuming #5477

Open

Description

@romchornyi

Expected Behavior

A host can ask platform-wallet whether a tracked asset lock is being consumed by a funding call that is still running, and is notified when that changes. A second call that would consume the same lock is refused with a typed error, so the host doesn't have to keep that state itself.

Current Behavior

Nothing in the SDK tells the host "this outpoint is in use". The wallet keeps the state internally:

Neither is visible over the FFI. While a call runs, its lock's persisted row looks exactly like a stuck one (Built/Broadcast/InstantSendLocked/ChainLocked, never Consumed). A Core-funded shield from many small coins can wait minutes for a ChainLock after #5460.

So dashwallet-ios keeps its own registry, ShieldedAssetLocksInFlight (ShieldedTransferCoordinator.swift#L1657-L1762, dashpay/dashwallet-ios#1212). It is a ref-counted set of claimed outpoints plus a count of fresh-build calls:

  • a fresh build claims the outpoint reported by onAssetLockBuilt (feat(platform-wallet)!: report a freshly built asset lock's outpoint to the caller #5476);
  • every resume entry point claims its outpoint before calling the SDK;
  • the Home row, the transaction details and the bulk recovery pass read it, so they hide "Finish now" and removal on a lock that is still being consumed;
  • resume entry points read it to refuse a second attempt;
  • "Remove if Not on Network" and Drop & Rescan are refused while any call is active, because their runtime reload would stop it.

This logic sits on the wrong side of the boundary:

Possible Solution

  1. Add a per-outpoint active-operation set to AssetLockManager. A fresh build enters it where the on_built observer fires, right after track_asset_lock (#5476). A resume enters it when resolve_funding_with_is_timeout_fallback takes a FromExistingAssetLock. An RAII guard leaves it when the call returns, unwinds or is dropped, so a cancelled future cannot leave a stale entry.

  2. Resolve a FromExistingAssetLock whose outpoint is already in the set to a typed error (for example AssetLockInUse(OutPoint) with its own FFI code). Don't let it queue behind shield_guard.

  3. Expose over the FFI:

    • asset_lock_manager_is_in_use(outpoint);
    • a listing of the in-use outpoints;
    • whether any fresh-build call is running, which the host needs for runtime-reload actions;
    • a change event through the existing PlatformWalletEventHandler.

    Mirror them in Swift (ManagedAssetLockManager) and JNI.

  4. Rust tests for: enter/leave on success, failure, panic and drop; concurrent resume refusal; independent outpoints; a fresh build before its outpoint exists.

The app would then drop ShieldedAssetLocksInFlight and its claim bookkeeping, keep only the UI reads, and map the new typed error to its "still in progress" message.

Alternatives Considered

  • Keep the registry in the app (current state). It works, but it is untested and has to be ported to every host.
  • Persist an "in use" marker on the asset-lock row. No: the state lives exactly as long as one call in one process, so after a restart it would be stale by definition.

Additional Context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions