Skip to content

Move P2MR fee-bump signing off the qbit-qt GUI thread #142

Description

@kiwidream

Issues, reports or feature requests related to the qbit GUI should be opened here only when they apply to this repository

  • I still think this issue should be opened here

Report

Summary

qbit-qt signs fee-bump transactions synchronously on the GUI thread. For transactions with many P2MR inputs, the application can appear hung until signing completes.

The fee-bump implementation also holds cs_wallet across signature generation, blocking wallet RPCs and wallet block-processing work for the duration.

Current behaviour

After confirmation and wallet unlock, WalletModel::bumpFee() directly calls:

m_wallet->signBumpTransaction(mtx)

This runs on the Qt GUI thread.

The interface delegates to feebumper::SignTransaction(), which acquires wallet.cs_wallet and then calls CWallet::SignTransaction() while the outer recursive wallet lock remains held.

P2MR transaction signing may use parallel signing workers internally, but:

  • the GUI thread still waits synchronously;
  • no progress callback is provided;
  • cancellation is unavailable;
  • cs_wallet remains held while signatures are generated; and
  • wallet RPC and scheduler work for that wallet can remain blocked.

Parallel cryptographic work reduces elapsed time but does not make the application responsive.

Steps to reproduce

  1. Create an encrypted P2MR wallet.
  2. Create an RBF-enabled transaction containing many P2MR inputs.
  3. Confirm it and leave it eligible for fee bumping.
  4. In qbit-qt, select Increase transaction fee.
  5. Confirm the replacement and enter the correct wallet password.
  6. Observe that the GUI stops responding until signing completes.
  7. During signing, attempt a wallet RPC and observe that it waits for cs_wallet.

A deterministic Qt regression can use a latch-controlled signer rather than relying on cryptographic timing.

Expected behaviour

Fee-bump preparation and signing should run outside the GUI thread with bounded progress. Long cryptographic signing should not hold cs_wallet, and unrelated wallet activity should remain responsive where consistency permits.

Scope boundary

This issue is limited to fee-bump preparation and signing, including the duration for which cs_wallet is held.

No existing issue covers synchronous WalletModel::bumpFee() signing or the outer cs_wallet lifetime in feebumper::SignTransaction().

Suggested direction

Refactor fee-bump signing into explicit phases:

  1. Under cs_wallet, validate the original transaction and snapshot the inputs and required signing state.
  2. Release cs_wallet.
  3. Reserve counters and sign the replacement on a worker thread.
  4. Report progress to qbit-qt through queued callbacks.
  5. Reacquire the required locks for final validation and commit.

Use the same stateful-PQC cancellation rules as normal send preparation:

  • cancellation may be allowed before durable counter reservation;
  • after reservation, disable cancellation and complete deterministically.

The structured completion result should be able to carry both a signing error and any PQCUsageReport, but the presentation of that report is outside this issue's scope.

Suggested tests

Add latch-controlled tests covering:

  • the GUI event loop remaining responsive during fee-bump signing;
  • wallet RPC access while cryptographic signing is paused;
  • progress delivery;
  • cancellation before counter reservation;
  • attempted cancellation after reservation;
  • original transaction state changing before final commit;
  • wallet unload and application shutdown; and
  • failed signing after counters were consumed.

Acceptance criteria

  • Fee-bump cryptographic signing does not run on the GUI thread.
  • cs_wallet is not held throughout P2MR signature generation.
  • Wallet RPC and scheduler work are not unnecessarily blocked by signing.
  • Progress is visible for multi-input fee bumps.
  • Cancellation respects durable counter-reservation boundaries.
  • Final commit revalidates the original transaction and replacement assumptions.
  • The result preserves any PQC usage needed by the separate presentation layer.
  • Existing non-P2MR, external-signer, and RBF policy behaviour remains unchanged.

Relevant code

  • src/qt/walletmodel.cpp: WalletModel::bumpFee
  • src/wallet/interfaces.cpp: WalletImpl::signBumpTransaction
  • src/wallet/feebumper.cpp: feebumper::SignTransaction
  • src/wallet/wallet.cpp: CWallet::SignTransaction

Version and platform

Source-inspected on qbit v1.0.0. Applies to all Qt-supported platforms.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions