gui: Refactor OpenWalletActivity #16261

pull promag wants to merge 1 commits into bitcoin:master from promag:2019-06-refactor-open-wallet changing 3 files +101 −59
  1. promag commented at 3:01 PM on June 21, 2019: member

    This PR consists in 3 refactors:

    1. Split from OpenWalletActivity a base class WalletControllerActivity to simplify new activities, like the upcoming CreateWalletActivity;
    2. Move from BitcoinGUI the details of the wallet opening;
    3. Change threading model - WalletControllerActivity instances belong to the GUI thread and some code (the blocking code) is now executed in the worker thread asynchronously, which allows for a responsive GUI.
  2. DrahtBot commented at 3:05 PM on June 21, 2019: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    No conflicts as of last run.

  3. in src/qt/walletcontroller.cpp:205 in a962b68ebf outdated
     211 | +{
     212 | +    QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
     213 | +
     214 | +    showProgressDialog(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped()));
     215 | +
     216 | +    QTimer::singleShot(500, worker(), [this, path] {
    


    promag commented at 3:07 PM on June 21, 2019:

    We can ditch these 500ms but I think it is ok.

    If we decide to have 0ms then we can only replace QTimer::singleShot(0, with QMetaObject::invokeMethod after bumping Qt to 5.10 - see https://doc.qt.io/qt-5/qmetaobject.html#invokeMethod-5.


    hebasto commented at 9:23 AM on July 7, 2019:

    What is the point to pause? If there is no clear and obvious rationale, QTimer::singleShot() should be avoided, IMO.


    promag commented at 2:39 PM on July 13, 2019:

    No point, but not harm, can make it 0. The point is to call the lambda in the worker() thread.


    hebasto commented at 7:58 PM on July 13, 2019:

    The point is to call the lambda in the worker() thread.

    Did you consider some other approaches?


    promag commented at 8:10 PM on July 13, 2019:

    Yes, those require more QObject subclass, signals and slots. IMO this approach is more clear.


    hebasto commented at 8:22 PM on July 13, 2019:

    May I suggest to remove (make 0 ms) or comment 500 ms timeout?


    promag commented at 9:38 PM on July 13, 2019:

    Sure, I can make 0ms and leave a comment.


    jonasschnelli commented at 3:46 PM on July 16, 2019:

    Is there a benefit of using 500ms? Seems racy...


    promag commented at 1:18 PM on August 29, 2019:

    Not really, I'll make 0 then.

  4. DrahtBot added the label GUI on Jun 21, 2019
  5. achow101 cross-referenced this on Jun 21, 2019 from issue gui: Create wallet menu option by achow101
  6. fanquake added this to the "Blockers" column in a project

  7. fanquake cross-referenced this on Jul 4, 2019 from issue Starting bitcoin-qt with -nowallet and then opening a wallet does not show the wallet by achow101
  8. fanquake requested review from hebasto on Jul 5, 2019
  9. fanquake requested review from jonasschnelli on Jul 5, 2019
  10. fanquake commented at 6:56 AM on July 5, 2019: member

    @promag Can you rebase this on master; as it contains some bug fixes that would be nice to have when testing this PR, such as #16231.

  11. fanquake added the label Waiting for author on Jul 5, 2019
  12. promag force-pushed on Jul 5, 2019
  13. promag commented at 7:33 AM on July 5, 2019: member

    @fanquake done.

  14. fanquake removed the label Waiting for author on Jul 5, 2019
  15. hebasto commented at 3:02 PM on July 5, 2019: member

    Concept ACK.

  16. fanquake commented at 2:24 AM on July 6, 2019: member

    I had a quick test, and this PR on top of master (4f378ac30cf66178564620b4a8ca9cad7f031cc3) doesn't fix #15453.

  17. in src/qt/walletcontroller.cpp:210 in 5604d30a30 outdated
     216 | +    QTimer::singleShot(500, worker(), [this, path] {
     217 | +        std::unique_ptr<interfaces::Wallet> wallet = node().loadWallet(path, m_error_message, m_warning_message);
     218 | +
     219 | +        if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
     220 | +
     221 | +        QTimer::singleShot(500, this, &OpenWalletActivity::finish);
    


    hebasto commented at 9:23 AM on July 7, 2019:

    Same here.


    hebasto commented at 8:08 PM on July 13, 2019:

    OpenWalletActivity::finish() could be inlined here. OpenWalletActivity::open() will remain small enough and readability will be improved, no?


    promag commented at 9:43 PM on July 13, 2019:

    OpenWalletActivity::finish() could be inlined here.

    At the time I had 2 reasons to not do that:

    1. finish could be called from multiple places, also initially it was a virtual method in the super class;
    2. wanted to avoid nesting lambdas.

    hebasto commented at 5:08 AM on July 14, 2019:

    Could it be just

            finish();
    

    ?


    promag commented at 9:11 AM on July 14, 2019:

    No, this finish() is not thread safe - it would be called from the worker thread.


    hebasto commented at 9:39 AM on July 14, 2019:

    ... this finish() is not thread safe - it would be called from the worker thread.

    Right. But thread safety is not required for finish(), IMO.


    promag commented at 1:36 PM on August 29, 2019:

    But it is, see OpenWalletActivity::finish(), it must be called on the GUI thread.


    hebasto commented at 10:24 AM on September 2, 2019:

    Correct.

  18. in src/qt/walletcontroller.cpp:192 in 5604d30a30 outdated
     212 | +    QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
     213 | +
     214 | +    showProgressDialog(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped()));
     215 | +
     216 | +    QTimer::singleShot(500, worker(), [this, path] {
     217 | +        std::unique_ptr<interfaces::Wallet> wallet = node().loadWallet(path, m_error_message, m_warning_message);
    


    hebasto commented at 10:13 AM on July 7, 2019:
    auto wallet = node().loadWallet(path, m_error_message, m_warning_message);
    

    promag commented at 2:37 PM on July 13, 2019:

    I prefer to have to have the type.

  19. in src/qt/walletcontroller.cpp:46 in 5604d30a30 outdated
      44 |  {
      45 | -    m_activity_thread.quit();
      46 | -    m_activity_thread.wait();
      47 | +    m_activity_thread->quit();
      48 | +    m_activity_thread->wait();
      49 | +    delete m_activity_worker;
    


    hebasto commented at 1:08 PM on July 7, 2019:

    Could naked delete be avoided in the new code? There are some techniques to achieve this. E.g., m_activity_worker could have a parent QObject, like m_activity_thread has.


    promag commented at 9:34 PM on July 13, 2019:

    No object could be m_activity_worker parent because it's the only object on its thread. Could connect WalletController::destroyed to its deleteLater or could use some smart pointer but honestly I think this is better.


    hebasto commented at 5:25 AM on July 14, 2019:

    You could use QThread::finished signal. See: https://github.com/bitcoin/bitcoin/pull/16261/files#r303227866

  20. in src/qt/walletcontroller.cpp:151 in 5604d30a30 outdated
     157 | -    : m_wallet_controller(wallet_controller)
     158 | -    , m_name(name)
     159 | -{}
     160 | +WalletControllerActivity::~WalletControllerActivity()
     161 | +{
     162 | +    delete m_progress_dialog;
    


    hebasto commented at 1:09 PM on July 7, 2019:

    Could naked delete be avoided in the new code?


    promag commented at 9:38 PM on July 13, 2019:

    Ownership is given to m_parent_widget so that it shows up properly. If the activity finishes first then we delete it - note lines L174-L176 below.


    hebasto commented at 5:57 AM on July 14, 2019:
  21. DrahtBot added the label Needs rebase on Jul 8, 2019
  22. promag force-pushed on Jul 8, 2019
  23. DrahtBot removed the label Needs rebase on Jul 9, 2019
  24. in src/qt/walletcontroller.cpp:36 in b71017a295 outdated
      32 | @@ -29,15 +33,17 @@ WalletController::WalletController(interfaces::Node& node, const PlatformStyle*
      33 |          getOrCreateWallet(std::move(wallet));
      34 |      }
      35 |  
      36 | -    m_activity_thread.start();
      37 | +    m_activity_worker->moveToThread(m_activity_thread);
    


    hebasto commented at 5:20 AM on July 14, 2019:

    Could add

        connect(m_activity_thread, &QThread::finished, m_activity_worker, &QObject::deleteLater);
    

    and remove following

       delete m_activity_worker;
    

    ?


    promag commented at 4:57 PM on July 16, 2019:

    Why? The thread is explicitly stopped (actually the event loop is stopped and the thread finishes) in ~WalletController() so what better place to also delete the worker? I think explicit teardown is preferable.


    hebasto commented at 7:11 AM on July 18, 2019:

    Why?

    Your approach binds the life of m_activity_worker to the WalletController instance lifetime. IMO, as m_activity_worker lives in m_activity_thread, connecting to the QThread::finished signal seems more appropriate.

  25. hebasto changes_requested
  26. in src/qt/walletcontroller.cpp:157 in b71017a295 outdated
     176 | -    if (wallet) {
     177 | -        Q_EMIT opened(m_wallet_controller->getOrCreateWallet(std::move(wallet)));
     178 | -    } else {
     179 | -        Q_EMIT message(QMessageBox::Critical, QString::fromStdString(error));
     180 | +    m_progress_dialog = new QProgressDialog(m_parent_widget);
     181 | +
    


    hebasto commented at 5:53 AM on July 14, 2019:

    Could add

        connect(this, &OpenWalletActivity::finished, m_progress_dialog, &QObject::deleteLater);
    

    and remove above:

       delete m_progress_dialog;
    

    ?

  27. in src/qt/walletcontroller.cpp:175 in b71017a295 outdated
     184 | +    m_progress_dialog->setCancelButton(nullptr);
     185 | +    m_progress_dialog->setWindowModality(Qt::ApplicationModal);
     186 | +    GUIUtil::PolishProgressDialog(m_progress_dialog);
     187 | +
     188 | +    connect(m_progress_dialog, &QObject::destroyed, [this] {
     189 | +        m_progress_dialog = nullptr;
    


    hebasto commented at 5:55 AM on July 14, 2019:

    Which cases require this line?


    promag commented at 5:26 PM on July 16, 2019:

    Actually I think it's not required now. Initially I had setAttribute(Qt::WA_DeleteOnClose). Removed.

  28. hebasto changes_requested
  29. jonasschnelli commented at 9:17 AM on July 17, 2019: contributor

    Looks like the wallet encryption test fails...

  30. promag commented at 10:20 AM on July 17, 2019: member

    @jonasschnelli it was failing because of build timeouts.

  31. promag force-pushed on Aug 29, 2019
  32. hebasto approved
  33. hebasto commented at 10:46 AM on September 2, 2019: member

    ACK 7afbd0cb69dae4af4b6a78c442c25832cd7fad42, I have tested the code: no change in behavior is observed (compared to the master 6519be605480fec95dcd814771038efcb1ad2abe).

  34. promag force-pushed on Sep 5, 2019
  35. gui: Refactor OpenWalletActivity bc6d8a3662
  36. promag force-pushed on Sep 5, 2019
  37. promag commented at 12:43 AM on September 6, 2019: member

    @hebasto rebased and removed the unused declaration std::vector<std::string> getWalletsAvailableToOpen() const; - left over from other work.

  38. fanquake merged this on Sep 7, 2019
  39. fanquake closed this on Sep 7, 2019

  40. fanquake removed this from the "Blockers" column in a project

  41. promag deleted the branch on Sep 7, 2019
  42. ryanofsky cross-referenced this on Mar 16, 2020 from issue gui: segfault unloading and immediately reloading wallet with gui by ryanofsky
  43. bitcoin locked this on Dec 16, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-20 06:54 UTC