LCOV - code coverage report
Current view: top level - src/qt - walletmodel.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 0 345 0.0 %
Date: 2020-09-26 01:30:44 Functions: 0 48 0.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2020 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #if defined(HAVE_CONFIG_H)
       6             : #include <config/bitcoin-config.h>
       7             : #endif
       8             : 
       9             : #include <qt/walletmodel.h>
      10             : 
      11             : #include <qt/addresstablemodel.h>
      12             : #include <qt/clientmodel.h>
      13             : #include <qt/guiconstants.h>
      14             : #include <qt/guiutil.h>
      15             : #include <qt/optionsmodel.h>
      16             : #include <qt/paymentserver.h>
      17             : #include <qt/recentrequeststablemodel.h>
      18             : #include <qt/sendcoinsdialog.h>
      19             : #include <qt/transactiontablemodel.h>
      20             : 
      21             : #include <interfaces/handler.h>
      22             : #include <interfaces/node.h>
      23             : #include <key_io.h>
      24             : #include <node/ui_interface.h>
      25             : #include <psbt.h>
      26             : #include <util/system.h> // for GetBoolArg
      27             : #include <util/translation.h>
      28             : #include <wallet/coincontrol.h>
      29             : #include <wallet/wallet.h> // for CRecipient
      30             : 
      31             : #include <stdint.h>
      32             : 
      33             : #include <QDebug>
      34             : #include <QMessageBox>
      35             : #include <QSet>
      36             : #include <QTimer>
      37             : 
      38             : 
      39           0 : WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel& client_model, const PlatformStyle *platformStyle, QObject *parent) :
      40           0 :     QObject(parent),
      41           0 :     m_wallet(std::move(wallet)),
      42           0 :     m_client_model(&client_model),
      43           0 :     m_node(client_model.node()),
      44           0 :     optionsModel(client_model.getOptionsModel()),
      45           0 :     addressTableModel(nullptr),
      46           0 :     transactionTableModel(nullptr),
      47           0 :     recentRequestsTableModel(nullptr),
      48           0 :     cachedEncryptionStatus(Unencrypted),
      49           0 :     timer(new QTimer(this))
      50           0 : {
      51           0 :     fHaveWatchOnly = m_wallet->haveWatchOnly();
      52           0 :     addressTableModel = new AddressTableModel(this);
      53           0 :     transactionTableModel = new TransactionTableModel(platformStyle, this);
      54           0 :     recentRequestsTableModel = new RecentRequestsTableModel(this);
      55             : 
      56           0 :     subscribeToCoreSignals();
      57           0 : }
      58             : 
      59           0 : WalletModel::~WalletModel()
      60           0 : {
      61           0 :     unsubscribeFromCoreSignals();
      62           0 : }
      63             : 
      64           0 : void WalletModel::startPollBalance()
      65             : {
      66             :     // This timer will be fired repeatedly to update the balance
      67           0 :     connect(timer, &QTimer::timeout, this, &WalletModel::pollBalanceChanged);
      68           0 :     timer->start(MODEL_UPDATE_DELAY);
      69           0 : }
      70             : 
      71           0 : void WalletModel::setClientModel(ClientModel* client_model)
      72             : {
      73           0 :     m_client_model = client_model;
      74           0 :     if (!m_client_model) timer->stop();
      75           0 : }
      76             : 
      77           0 : void WalletModel::updateStatus()
      78             : {
      79           0 :     EncryptionStatus newEncryptionStatus = getEncryptionStatus();
      80             : 
      81           0 :     if(cachedEncryptionStatus != newEncryptionStatus) {
      82           0 :         Q_EMIT encryptionStatusChanged();
      83           0 :     }
      84           0 : }
      85             : 
      86           0 : void WalletModel::pollBalanceChanged()
      87             : {
      88             :     // Avoid recomputing wallet balances unless a TransactionChanged or
      89             :     // BlockTip notification was received.
      90           0 :     if (!fForceCheckBalanceChanged && m_cached_last_update_tip == getLastBlockProcessed()) return;
      91             : 
      92             :     // Try to get balances and return early if locks can't be acquired. This
      93             :     // avoids the GUI from getting stuck on periodical polls if the core is
      94             :     // holding the locks for a longer time - for example, during a wallet
      95             :     // rescan.
      96           0 :     interfaces::WalletBalances new_balances;
      97           0 :     uint256 block_hash;
      98           0 :     if (!m_wallet->tryGetBalances(new_balances, block_hash)) {
      99           0 :         return;
     100             :     }
     101             : 
     102           0 :     if (fForceCheckBalanceChanged || block_hash != m_cached_last_update_tip) {
     103           0 :         fForceCheckBalanceChanged = false;
     104             : 
     105             :         // Balance and number of transactions might have changed
     106           0 :         m_cached_last_update_tip = block_hash;
     107             : 
     108           0 :         checkBalanceChanged(new_balances);
     109           0 :         if(transactionTableModel)
     110           0 :             transactionTableModel->updateConfirmations();
     111             :     }
     112           0 : }
     113             : 
     114           0 : void WalletModel::checkBalanceChanged(const interfaces::WalletBalances& new_balances)
     115             : {
     116           0 :     if(new_balances.balanceChanged(m_cached_balances)) {
     117           0 :         m_cached_balances = new_balances;
     118           0 :         Q_EMIT balanceChanged(new_balances);
     119           0 :     }
     120           0 : }
     121             : 
     122           0 : void WalletModel::updateTransaction()
     123             : {
     124             :     // Balance and number of transactions might have changed
     125           0 :     fForceCheckBalanceChanged = true;
     126           0 : }
     127             : 
     128           0 : void WalletModel::updateAddressBook(const QString &address, const QString &label,
     129             :         bool isMine, const QString &purpose, int status)
     130             : {
     131           0 :     if(addressTableModel)
     132           0 :         addressTableModel->updateEntry(address, label, isMine, purpose, status);
     133           0 : }
     134             : 
     135           0 : void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
     136             : {
     137           0 :     fHaveWatchOnly = fHaveWatchonly;
     138           0 :     Q_EMIT notifyWatchonlyChanged(fHaveWatchonly);
     139           0 : }
     140             : 
     141           0 : bool WalletModel::validateAddress(const QString &address)
     142             : {
     143           0 :     return IsValidDestinationString(address.toStdString());
     144           0 : }
     145             : 
     146           0 : WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
     147             : {
     148           0 :     CAmount total = 0;
     149             :     bool fSubtractFeeFromAmount = false;
     150           0 :     QList<SendCoinsRecipient> recipients = transaction.getRecipients();
     151           0 :     std::vector<CRecipient> vecSend;
     152             : 
     153           0 :     if(recipients.empty())
     154             :     {
     155           0 :         return OK;
     156             :     }
     157             : 
     158           0 :     QSet<QString> setAddress; // Used to detect duplicates
     159           0 :     int nAddresses = 0;
     160             : 
     161             :     // Pre-check input data for validity
     162           0 :     for (const SendCoinsRecipient &rcp : recipients)
     163             :     {
     164           0 :         if (rcp.fSubtractFeeFromAmount)
     165           0 :             fSubtractFeeFromAmount = true;
     166             :         {   // User-entered bitcoin address / amount:
     167           0 :             if(!validateAddress(rcp.address))
     168             :             {
     169           0 :                 return InvalidAddress;
     170             :             }
     171           0 :             if(rcp.amount <= 0)
     172             :             {
     173           0 :                 return InvalidAmount;
     174           0 :             }
     175           0 :             setAddress.insert(rcp.address);
     176           0 :             ++nAddresses;
     177             : 
     178           0 :             CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString()));
     179           0 :             CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount};
     180           0 :             vecSend.push_back(recipient);
     181             : 
     182           0 :             total += rcp.amount;
     183           0 :         }
     184           0 :     }
     185           0 :     if(setAddress.size() != nAddresses)
     186             :     {
     187           0 :         return DuplicateAddress;
     188             :     }
     189             : 
     190           0 :     CAmount nBalance = m_wallet->getAvailableBalance(coinControl);
     191             : 
     192           0 :     if(total > nBalance)
     193             :     {
     194           0 :         return AmountExceedsBalance;
     195             :     }
     196             : 
     197             :     {
     198           0 :         CAmount nFeeRequired = 0;
     199           0 :         int nChangePosRet = -1;
     200           0 :         bilingual_str error;
     201             : 
     202           0 :         auto& newTx = transaction.getWtx();
     203           0 :         newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, error);
     204           0 :         transaction.setTransactionFee(nFeeRequired);
     205           0 :         if (fSubtractFeeFromAmount && newTx)
     206           0 :             transaction.reassignAmounts(nChangePosRet);
     207             : 
     208           0 :         if(!newTx)
     209             :         {
     210           0 :             if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance)
     211             :             {
     212           0 :                 return SendCoinsReturn(AmountWithFeeExceedsBalance);
     213             :             }
     214           0 :             Q_EMIT message(tr("Send Coins"), QString::fromStdString(error.translated),
     215             :                 CClientUIInterface::MSG_ERROR);
     216           0 :             return TransactionCreationFailed;
     217             :         }
     218             : 
     219             :         // Reject absurdly high fee. (This can never happen because the
     220             :         // wallet never creates transactions with fee greater than
     221             :         // m_default_max_tx_fee. This merely a belt-and-suspenders check).
     222           0 :         if (nFeeRequired > m_wallet->getDefaultMaxTxFee()) {
     223           0 :             return AbsurdFee;
     224             :         }
     225           0 :     }
     226             : 
     227           0 :     return SendCoinsReturn(OK);
     228           0 : }
     229             : 
     230           0 : WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction)
     231             : {
     232           0 :     QByteArray transaction_array; /* store serialized transaction */
     233             : 
     234             :     {
     235           0 :         std::vector<std::pair<std::string, std::string>> vOrderForm;
     236           0 :         for (const SendCoinsRecipient &rcp : transaction.getRecipients())
     237             :         {
     238           0 :             if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
     239           0 :                 vOrderForm.emplace_back("Message", rcp.message.toStdString());
     240           0 :         }
     241             : 
     242           0 :         auto& newTx = transaction.getWtx();
     243           0 :         wallet().commitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm));
     244             : 
     245           0 :         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
     246           0 :         ssTx << *newTx;
     247           0 :         transaction_array.append(&(ssTx[0]), ssTx.size());
     248           0 :     }
     249             : 
     250             :     // Add addresses / update labels that we've sent to the address book,
     251             :     // and emit coinsSent signal for each recipient
     252           0 :     for (const SendCoinsRecipient &rcp : transaction.getRecipients())
     253             :     {
     254             :         {
     255           0 :             std::string strAddress = rcp.address.toStdString();
     256           0 :             CTxDestination dest = DecodeDestination(strAddress);
     257           0 :             std::string strLabel = rcp.label.toStdString();
     258             :             {
     259             :                 // Check if we have a new address or an updated label
     260           0 :                 std::string name;
     261           0 :                 if (!m_wallet->getAddress(
     262             :                      dest, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr))
     263             :                 {
     264           0 :                     m_wallet->setAddressBook(dest, strLabel, "send");
     265           0 :                 }
     266           0 :                 else if (name != strLabel)
     267             :                 {
     268           0 :                     m_wallet->setAddressBook(dest, strLabel, ""); // "" means don't change purpose
     269           0 :                 }
     270           0 :             }
     271           0 :         }
     272           0 :         Q_EMIT coinsSent(this, rcp, transaction_array);
     273           0 :     }
     274             : 
     275           0 :     checkBalanceChanged(m_wallet->getBalances()); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
     276             : 
     277           0 :     return SendCoinsReturn(OK);
     278           0 : }
     279             : 
     280           0 : OptionsModel *WalletModel::getOptionsModel()
     281             : {
     282           0 :     return optionsModel;
     283             : }
     284             : 
     285           0 : AddressTableModel *WalletModel::getAddressTableModel()
     286             : {
     287           0 :     return addressTableModel;
     288             : }
     289             : 
     290           0 : TransactionTableModel *WalletModel::getTransactionTableModel()
     291             : {
     292           0 :     return transactionTableModel;
     293             : }
     294             : 
     295           0 : RecentRequestsTableModel *WalletModel::getRecentRequestsTableModel()
     296             : {
     297           0 :     return recentRequestsTableModel;
     298             : }
     299             : 
     300           0 : WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
     301             : {
     302           0 :     if(!m_wallet->isCrypted())
     303             :     {
     304           0 :         return Unencrypted;
     305             :     }
     306           0 :     else if(m_wallet->isLocked())
     307             :     {
     308           0 :         return Locked;
     309             :     }
     310             :     else
     311             :     {
     312           0 :         return Unlocked;
     313             :     }
     314           0 : }
     315             : 
     316           0 : bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
     317             : {
     318           0 :     if (encrypted) {
     319           0 :         return m_wallet->encryptWallet(passphrase);
     320             :     }
     321           0 :     return false;
     322           0 : }
     323             : 
     324           0 : bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
     325             : {
     326           0 :     if(locked)
     327             :     {
     328             :         // Lock
     329           0 :         return m_wallet->lock();
     330             :     }
     331             :     else
     332             :     {
     333             :         // Unlock
     334           0 :         return m_wallet->unlock(passPhrase);
     335             :     }
     336           0 : }
     337             : 
     338           0 : bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
     339             : {
     340           0 :     m_wallet->lock(); // Make sure wallet is locked before attempting pass change
     341           0 :     return m_wallet->changeWalletPassphrase(oldPass, newPass);
     342             : }
     343             : 
     344             : // Handlers for core signals
     345           0 : static void NotifyUnload(WalletModel* walletModel)
     346             : {
     347           0 :     qDebug() << "NotifyUnload";
     348           0 :     bool invoked = QMetaObject::invokeMethod(walletModel, "unload");
     349           0 :     assert(invoked);
     350           0 : }
     351             : 
     352           0 : static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
     353             : {
     354           0 :     qDebug() << "NotifyKeyStoreStatusChanged";
     355           0 :     bool invoked = QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
     356           0 :     assert(invoked);
     357           0 : }
     358             : 
     359           0 : static void NotifyAddressBookChanged(WalletModel *walletmodel,
     360             :         const CTxDestination &address, const std::string &label, bool isMine,
     361             :         const std::string &purpose, ChangeType status)
     362             : {
     363           0 :     QString strAddress = QString::fromStdString(EncodeDestination(address));
     364           0 :     QString strLabel = QString::fromStdString(label);
     365           0 :     QString strPurpose = QString::fromStdString(purpose);
     366             : 
     367           0 :     qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status);
     368           0 :     bool invoked = QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
     369           0 :                               Q_ARG(QString, strAddress),
     370           0 :                               Q_ARG(QString, strLabel),
     371           0 :                               Q_ARG(bool, isMine),
     372           0 :                               Q_ARG(QString, strPurpose),
     373           0 :                               Q_ARG(int, status));
     374           0 :     assert(invoked);
     375           0 : }
     376             : 
     377           0 : static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status)
     378             : {
     379             :     Q_UNUSED(hash);
     380             :     Q_UNUSED(status);
     381           0 :     bool invoked = QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection);
     382           0 :     assert(invoked);
     383           0 : }
     384             : 
     385           0 : static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress)
     386             : {
     387             :     // emits signal "showProgress"
     388           0 :     bool invoked = QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection,
     389           0 :                               Q_ARG(QString, QString::fromStdString(title)),
     390           0 :                               Q_ARG(int, nProgress));
     391           0 :     assert(invoked);
     392           0 : }
     393             : 
     394           0 : static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly)
     395             : {
     396           0 :     bool invoked = QMetaObject::invokeMethod(walletmodel, "updateWatchOnlyFlag", Qt::QueuedConnection,
     397           0 :                               Q_ARG(bool, fHaveWatchonly));
     398           0 :     assert(invoked);
     399           0 : }
     400             : 
     401           0 : static void NotifyCanGetAddressesChanged(WalletModel* walletmodel)
     402             : {
     403           0 :     bool invoked = QMetaObject::invokeMethod(walletmodel, "canGetAddressesChanged");
     404           0 :     assert(invoked);
     405           0 : }
     406             : 
     407           0 : void WalletModel::subscribeToCoreSignals()
     408             : {
     409             :     // Connect signals to wallet
     410           0 :     m_handler_unload = m_wallet->handleUnload(std::bind(&NotifyUnload, this));
     411           0 :     m_handler_status_changed = m_wallet->handleStatusChanged(std::bind(&NotifyKeyStoreStatusChanged, this));
     412           0 :     m_handler_address_book_changed = m_wallet->handleAddressBookChanged(std::bind(NotifyAddressBookChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
     413           0 :     m_handler_transaction_changed = m_wallet->handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2));
     414           0 :     m_handler_show_progress = m_wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
     415           0 :     m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(std::bind(NotifyWatchonlyChanged, this, std::placeholders::_1));
     416           0 :     m_handler_can_get_addrs_changed = m_wallet->handleCanGetAddressesChanged(std::bind(NotifyCanGetAddressesChanged, this));
     417           0 : }
     418             : 
     419           0 : void WalletModel::unsubscribeFromCoreSignals()
     420             : {
     421             :     // Disconnect signals from wallet
     422           0 :     m_handler_unload->disconnect();
     423           0 :     m_handler_status_changed->disconnect();
     424           0 :     m_handler_address_book_changed->disconnect();
     425           0 :     m_handler_transaction_changed->disconnect();
     426           0 :     m_handler_show_progress->disconnect();
     427           0 :     m_handler_watch_only_changed->disconnect();
     428           0 :     m_handler_can_get_addrs_changed->disconnect();
     429           0 : }
     430             : 
     431             : // WalletModel::UnlockContext implementation
     432           0 : WalletModel::UnlockContext WalletModel::requestUnlock()
     433             : {
     434           0 :     bool was_locked = getEncryptionStatus() == Locked;
     435           0 :     if(was_locked)
     436             :     {
     437             :         // Request UI to unlock wallet
     438           0 :         Q_EMIT requireUnlock();
     439           0 :     }
     440             :     // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
     441           0 :     bool valid = getEncryptionStatus() != Locked;
     442             : 
     443           0 :     return UnlockContext(this, valid, was_locked);
     444           0 : }
     445             : 
     446           0 : WalletModel::UnlockContext::UnlockContext(WalletModel *_wallet, bool _valid, bool _relock):
     447           0 :         wallet(_wallet),
     448           0 :         valid(_valid),
     449           0 :         relock(_relock)
     450           0 : {
     451           0 : }
     452             : 
     453           0 : WalletModel::UnlockContext::~UnlockContext()
     454           0 : {
     455           0 :     if(valid && relock)
     456             :     {
     457           0 :         wallet->setWalletLocked(true);
     458           0 :     }
     459           0 : }
     460             : 
     461           0 : void WalletModel::UnlockContext::CopyFrom(UnlockContext&& rhs)
     462             : {
     463             :     // Transfer context; old object no longer relocks wallet
     464           0 :     *this = rhs;
     465           0 :     rhs.relock = false;
     466           0 : }
     467             : 
     468           0 : void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
     469             : {
     470           0 :     vReceiveRequests = m_wallet->getDestValues("rr"); // receive request
     471           0 : }
     472             : 
     473           0 : bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
     474             : {
     475           0 :     CTxDestination dest = DecodeDestination(sAddress);
     476             : 
     477           0 :     std::stringstream ss;
     478           0 :     ss << nId;
     479           0 :     std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
     480             : 
     481           0 :     if (sRequest.empty())
     482           0 :         return m_wallet->eraseDestData(dest, key);
     483             :     else
     484           0 :         return m_wallet->addDestData(dest, key, sRequest);
     485           0 : }
     486             : 
     487           0 : bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
     488             : {
     489           0 :     CCoinControl coin_control;
     490           0 :     coin_control.m_signal_bip125_rbf = true;
     491           0 :     std::vector<bilingual_str> errors;
     492           0 :     CAmount old_fee;
     493           0 :     CAmount new_fee;
     494           0 :     CMutableTransaction mtx;
     495           0 :     if (!m_wallet->createBumpTransaction(hash, coin_control, errors, old_fee, new_fee, mtx)) {
     496           0 :         QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
     497           0 :             (errors.size() ? QString::fromStdString(errors[0].translated) : "") +")");
     498           0 :         return false;
     499             :     }
     500             : 
     501           0 :     const bool create_psbt = m_wallet->privateKeysDisabled();
     502             : 
     503             :     // allow a user based fee verification
     504           0 :     QString questionString = create_psbt ? tr("Do you want to draft a transaction with fee increase?") : tr("Do you want to increase the fee?");
     505           0 :     questionString.append("<br />");
     506           0 :     questionString.append("<table style=\"text-align: left;\">");
     507           0 :     questionString.append("<tr><td>");
     508           0 :     questionString.append(tr("Current fee:"));
     509           0 :     questionString.append("</td><td>");
     510           0 :     questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), old_fee));
     511           0 :     questionString.append("</td></tr><tr><td>");
     512           0 :     questionString.append(tr("Increase:"));
     513           0 :     questionString.append("</td><td>");
     514           0 :     questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee - old_fee));
     515           0 :     questionString.append("</td></tr><tr><td>");
     516           0 :     questionString.append(tr("New fee:"));
     517           0 :     questionString.append("</td><td>");
     518           0 :     questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee));
     519           0 :     questionString.append("</td></tr></table>");
     520           0 :     SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
     521           0 :     confirmationDialog.exec();
     522           0 :     QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result());
     523             : 
     524             :     // cancel sign&broadcast if user doesn't want to bump the fee
     525           0 :     if (retval != QMessageBox::Yes) {
     526           0 :         return false;
     527             :     }
     528             : 
     529           0 :     WalletModel::UnlockContext ctx(requestUnlock());
     530           0 :     if(!ctx.isValid())
     531             :     {
     532           0 :         return false;
     533             :     }
     534             : 
     535             :     // Short-circuit if we are returning a bumped transaction PSBT to clipboard
     536           0 :     if (create_psbt) {
     537           0 :         PartiallySignedTransaction psbtx(mtx);
     538           0 :         bool complete = false;
     539           0 :         const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, psbtx, complete, nullptr);
     540           0 :         if (err != TransactionError::OK || complete) {
     541           0 :             QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't draft transaction."));
     542           0 :             return false;
     543             :         }
     544             :         // Serialize the PSBT
     545           0 :         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
     546           0 :         ssTx << psbtx;
     547           0 :         GUIUtil::setClipboard(EncodeBase64(ssTx.str()).c_str());
     548           0 :         Q_EMIT message(tr("PSBT copied"), "Copied to clipboard", CClientUIInterface::MSG_INFORMATION);
     549             :         return true;
     550           0 :     }
     551             : 
     552             :     // sign bumped transaction
     553           0 :     if (!m_wallet->signBumpTransaction(mtx)) {
     554           0 :         QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't sign transaction."));
     555           0 :         return false;
     556             :     }
     557             :     // commit the bumped transaction
     558           0 :     if(!m_wallet->commitBumpTransaction(hash, std::move(mtx), errors, new_hash)) {
     559           0 :         QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
     560           0 :             QString::fromStdString(errors[0].translated)+")");
     561           0 :         return false;
     562             :     }
     563           0 :     return true;
     564           0 : }
     565             : 
     566           0 : bool WalletModel::isWalletEnabled()
     567             : {
     568           0 :    return !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
     569           0 : }
     570             : 
     571           0 : QString WalletModel::getWalletName() const
     572             : {
     573           0 :     return QString::fromStdString(m_wallet->getWalletName());
     574           0 : }
     575             : 
     576           0 : QString WalletModel::getDisplayName() const
     577             : {
     578           0 :     const QString name = getWalletName();
     579           0 :     return name.isEmpty() ? "["+tr("default wallet")+"]" : name;
     580           0 : }
     581             : 
     582           0 : bool WalletModel::isMultiwallet()
     583             : {
     584           0 :     return m_node.walletClient().getWallets().size() > 1;
     585             : }
     586             : 
     587           0 : void WalletModel::refresh(bool pk_hash_only)
     588             : {
     589           0 :     addressTableModel = new AddressTableModel(this, pk_hash_only);
     590           0 : }
     591             : 
     592           0 : uint256 WalletModel::getLastBlockProcessed() const
     593             : {
     594           0 :     return m_client_model ? m_client_model->getBestBlockHash() : uint256{};
     595             : }

Generated by: LCOV version 1.15