LCOV - code coverage report
Current view: top level - src/qt - walletmodel.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 0 314 0.0 %
Date: 2015-10-12 22:39:14 Functions: 0 42 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2011-2014 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             : #include "walletmodel.h"
       6             : 
       7             : #include "addresstablemodel.h"
       8             : #include "guiconstants.h"
       9             : #include "guiutil.h"
      10             : #include "paymentserver.h"
      11             : #include "recentrequeststablemodel.h"
      12             : #include "transactiontablemodel.h"
      13             : 
      14             : #include "base58.h"
      15             : #include "keystore.h"
      16             : #include "main.h"
      17             : #include "sync.h"
      18             : #include "ui_interface.h"
      19             : #include "wallet/wallet.h"
      20             : #include "wallet/walletdb.h" // for BackupWallet
      21             : 
      22             : #include <stdint.h>
      23             : 
      24             : #include <QDebug>
      25             : #include <QSet>
      26             : #include <QTimer>
      27             : 
      28             : #include <boost/foreach.hpp>
      29             : 
      30           0 : WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
      31             :     QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
      32             :     transactionTableModel(0),
      33             :     recentRequestsTableModel(0),
      34             :     cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
      35             :     cachedEncryptionStatus(Unencrypted),
      36           0 :     cachedNumBlocks(0)
      37             : {
      38           0 :     fHaveWatchOnly = wallet->HaveWatchOnly();
      39           0 :     fForceCheckBalanceChanged = false;
      40             : 
      41           0 :     addressTableModel = new AddressTableModel(wallet, this);
      42           0 :     transactionTableModel = new TransactionTableModel(platformStyle, wallet, this);
      43           0 :     recentRequestsTableModel = new RecentRequestsTableModel(wallet, this);
      44             : 
      45             :     // This timer will be fired repeatedly to update the balance
      46           0 :     pollTimer = new QTimer(this);
      47           0 :     connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged()));
      48           0 :     pollTimer->start(MODEL_UPDATE_DELAY);
      49             : 
      50           0 :     subscribeToCoreSignals();
      51           0 : }
      52             : 
      53           0 : WalletModel::~WalletModel()
      54             : {
      55           0 :     unsubscribeFromCoreSignals();
      56           0 : }
      57             : 
      58           0 : CAmount WalletModel::getBalance(const CCoinControl *coinControl) const
      59             : {
      60           0 :     if (coinControl)
      61             :     {
      62           0 :         CAmount nBalance = 0;
      63             :         std::vector<COutput> vCoins;
      64           0 :         wallet->AvailableCoins(vCoins, true, coinControl);
      65           0 :         BOOST_FOREACH(const COutput& out, vCoins)
      66           0 :             if(out.fSpendable)
      67           0 :                 nBalance += out.tx->vout[out.i].nValue;
      68             : 
      69           0 :         return nBalance;
      70             :     }
      71             : 
      72           0 :     return wallet->GetBalance();
      73             : }
      74             : 
      75           0 : CAmount WalletModel::getUnconfirmedBalance() const
      76             : {
      77           0 :     return wallet->GetUnconfirmedBalance();
      78             : }
      79             : 
      80           0 : CAmount WalletModel::getImmatureBalance() const
      81             : {
      82           0 :     return wallet->GetImmatureBalance();
      83             : }
      84             : 
      85           0 : bool WalletModel::haveWatchOnly() const
      86             : {
      87           0 :     return fHaveWatchOnly;
      88             : }
      89             : 
      90           0 : CAmount WalletModel::getWatchBalance() const
      91             : {
      92           0 :     return wallet->GetWatchOnlyBalance();
      93             : }
      94             : 
      95           0 : CAmount WalletModel::getWatchUnconfirmedBalance() const
      96             : {
      97           0 :     return wallet->GetUnconfirmedWatchOnlyBalance();
      98             : }
      99             : 
     100           0 : CAmount WalletModel::getWatchImmatureBalance() const
     101             : {
     102           0 :     return wallet->GetImmatureWatchOnlyBalance();
     103             : }
     104             : 
     105           0 : void WalletModel::updateStatus()
     106             : {
     107           0 :     EncryptionStatus newEncryptionStatus = getEncryptionStatus();
     108             : 
     109           0 :     if(cachedEncryptionStatus != newEncryptionStatus)
     110           0 :         Q_EMIT encryptionStatusChanged(newEncryptionStatus);
     111           0 : }
     112             : 
     113           0 : void WalletModel::pollBalanceChanged()
     114             : {
     115             :     // Get required locks upfront. This avoids the GUI from getting stuck on
     116             :     // periodical polls if the core is holding the locks for a longer time -
     117             :     // for example, during a wallet rescan.
     118           0 :     TRY_LOCK(cs_main, lockMain);
     119           0 :     if(!lockMain)
     120             :         return;
     121           0 :     TRY_LOCK(wallet->cs_wallet, lockWallet);
     122           0 :     if(!lockWallet)
     123             :         return;
     124             : 
     125           0 :     if(fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks)
     126             :     {
     127           0 :         fForceCheckBalanceChanged = false;
     128             : 
     129             :         // Balance and number of transactions might have changed
     130           0 :         cachedNumBlocks = chainActive.Height();
     131             : 
     132           0 :         checkBalanceChanged();
     133           0 :         if(transactionTableModel)
     134           0 :             transactionTableModel->updateConfirmations();
     135             :     }
     136             : }
     137             : 
     138           0 : void WalletModel::checkBalanceChanged()
     139             : {
     140           0 :     CAmount newBalance = getBalance();
     141           0 :     CAmount newUnconfirmedBalance = getUnconfirmedBalance();
     142           0 :     CAmount newImmatureBalance = getImmatureBalance();
     143           0 :     CAmount newWatchOnlyBalance = 0;
     144           0 :     CAmount newWatchUnconfBalance = 0;
     145           0 :     CAmount newWatchImmatureBalance = 0;
     146           0 :     if (haveWatchOnly())
     147             :     {
     148           0 :         newWatchOnlyBalance = getWatchBalance();
     149           0 :         newWatchUnconfBalance = getWatchUnconfirmedBalance();
     150           0 :         newWatchImmatureBalance = getWatchImmatureBalance();
     151             :     }
     152             : 
     153           0 :     if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance ||
     154           0 :         cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance)
     155             :     {
     156           0 :         cachedBalance = newBalance;
     157           0 :         cachedUnconfirmedBalance = newUnconfirmedBalance;
     158           0 :         cachedImmatureBalance = newImmatureBalance;
     159           0 :         cachedWatchOnlyBalance = newWatchOnlyBalance;
     160           0 :         cachedWatchUnconfBalance = newWatchUnconfBalance;
     161           0 :         cachedWatchImmatureBalance = newWatchImmatureBalance;
     162             :         Q_EMIT balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
     163           0 :                             newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance);
     164             :     }
     165           0 : }
     166             : 
     167           0 : void WalletModel::updateTransaction()
     168             : {
     169             :     // Balance and number of transactions might have changed
     170           0 :     fForceCheckBalanceChanged = true;
     171           0 : }
     172             : 
     173           0 : void WalletModel::updateAddressBook(const QString &address, const QString &label,
     174             :         bool isMine, const QString &purpose, int status)
     175             : {
     176           0 :     if(addressTableModel)
     177           0 :         addressTableModel->updateEntry(address, label, isMine, purpose, status);
     178           0 : }
     179             : 
     180           0 : void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
     181             : {
     182           0 :     fHaveWatchOnly = fHaveWatchonly;
     183           0 :     Q_EMIT notifyWatchonlyChanged(fHaveWatchonly);
     184           0 : }
     185             : 
     186           0 : bool WalletModel::validateAddress(const QString &address)
     187             : {
     188           0 :     CBitcoinAddress addressParsed(address.toStdString());
     189           0 :     return addressParsed.IsValid();
     190             : }
     191             : 
     192           0 : WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl)
     193             : {
     194           0 :     CAmount total = 0;
     195           0 :     bool fSubtractFeeFromAmount = false;
     196           0 :     QList<SendCoinsRecipient> recipients = transaction.getRecipients();
     197           0 :     std::vector<CRecipient> vecSend;
     198             : 
     199           0 :     if(recipients.empty())
     200             :     {
     201           0 :         return OK;
     202             :     }
     203             : 
     204             :     QSet<QString> setAddress; // Used to detect duplicates
     205           0 :     int nAddresses = 0;
     206             : 
     207             :     // Pre-check input data for validity
     208           0 :     Q_FOREACH(const SendCoinsRecipient &rcp, recipients)
     209             :     {
     210           0 :         if (rcp.fSubtractFeeFromAmount)
     211           0 :             fSubtractFeeFromAmount = true;
     212             : 
     213           0 :         if (rcp.paymentRequest.IsInitialized())
     214             :         {   // PaymentRequest...
     215             :             CAmount subtotal = 0;
     216             :             const payments::PaymentDetails& details = rcp.paymentRequest.getDetails();
     217           0 :             for (int i = 0; i < details.outputs_size(); i++)
     218             :             {
     219           0 :                 const payments::Output& out = details.outputs(i);
     220           0 :                 if (out.amount() <= 0) continue;
     221           0 :                 subtotal += out.amount();
     222           0 :                 const unsigned char* scriptStr = (const unsigned char*)out.script().data();
     223           0 :                 CScript scriptPubKey(scriptStr, scriptStr+out.script().size());
     224           0 :                 CAmount nAmount = out.amount();
     225           0 :                 CRecipient recipient = {scriptPubKey, nAmount, rcp.fSubtractFeeFromAmount};
     226           0 :                 vecSend.push_back(recipient);
     227             :             }
     228           0 :             if (subtotal <= 0)
     229             :             {
     230           0 :                 return InvalidAmount;
     231             :             }
     232           0 :             total += subtotal;
     233             :         }
     234             :         else
     235             :         {   // User-entered bitcoin address / amount:
     236           0 :             if(!validateAddress(rcp.address))
     237             :             {
     238           0 :                 return InvalidAddress;
     239             :             }
     240           0 :             if(rcp.amount <= 0)
     241             :             {
     242           0 :                 return InvalidAmount;
     243             :             }
     244           0 :             setAddress.insert(rcp.address);
     245           0 :             ++nAddresses;
     246             : 
     247           0 :             CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
     248           0 :             CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount};
     249           0 :             vecSend.push_back(recipient);
     250             : 
     251           0 :             total += rcp.amount;
     252             :         }
     253             :     }
     254           0 :     if(setAddress.size() != nAddresses)
     255             :     {
     256           0 :         return DuplicateAddress;
     257             :     }
     258             : 
     259           0 :     CAmount nBalance = getBalance(coinControl);
     260             : 
     261           0 :     if(total > nBalance)
     262             :     {
     263           0 :         return AmountExceedsBalance;
     264             :     }
     265             : 
     266             :     {
     267           0 :         LOCK2(cs_main, wallet->cs_wallet);
     268             : 
     269           0 :         transaction.newPossibleKeyChange(wallet);
     270             : 
     271           0 :         CAmount nFeeRequired = 0;
     272           0 :         int nChangePosRet = -1;
     273             :         std::string strFailReason;
     274             : 
     275             :         CWalletTx *newTx = transaction.getTransaction();
     276           0 :         CReserveKey *keyChange = transaction.getPossibleKeyChange();
     277           0 :         bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl);
     278           0 :         transaction.setTransactionFee(nFeeRequired);
     279           0 :         if (fSubtractFeeFromAmount && fCreated)
     280           0 :             transaction.reassignAmounts(nChangePosRet);
     281             : 
     282           0 :         if(!fCreated)
     283             :         {
     284           0 :             if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance)
     285             :             {
     286           0 :                 return SendCoinsReturn(AmountWithFeeExceedsBalance);
     287             :             }
     288             :             Q_EMIT message(tr("Send Coins"), QString::fromStdString(strFailReason),
     289           0 :                          CClientUIInterface::MSG_ERROR);
     290           0 :             return TransactionCreationFailed;
     291             :         }
     292             : 
     293             :         // reject absurdly high fee > 0.1 bitcoin
     294           0 :         if (nFeeRequired > 10000000)
     295           0 :             return AbsurdFee;
     296             :     }
     297             : 
     298           0 :     return SendCoinsReturn(OK);
     299             : }
     300             : 
     301           0 : WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction)
     302             : {
     303             :     QByteArray transaction_array; /* store serialized transaction */
     304             : 
     305             :     {
     306           0 :         LOCK2(cs_main, wallet->cs_wallet);
     307           0 :         CWalletTx *newTx = transaction.getTransaction();
     308             : 
     309           0 :         Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients())
     310             :         {
     311           0 :             if (rcp.paymentRequest.IsInitialized())
     312             :             {
     313             :                 // Make sure any payment requests involved are still valid.
     314           0 :                 if (PaymentServer::verifyExpired(rcp.paymentRequest.getDetails())) {
     315           0 :                     return PaymentRequestExpired;
     316             :                 }
     317             : 
     318             :                 // Store PaymentRequests in wtx.vOrderForm in wallet.
     319           0 :                 std::string key("PaymentRequest");
     320             :                 std::string value;
     321           0 :                 rcp.paymentRequest.SerializeToString(&value);
     322           0 :                 newTx->vOrderForm.push_back(make_pair(key, value));
     323             :             }
     324           0 :             else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
     325           0 :                 newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString()));
     326             :         }
     327             : 
     328           0 :         CReserveKey *keyChange = transaction.getPossibleKeyChange();
     329           0 :         if(!wallet->CommitTransaction(*newTx, *keyChange))
     330           0 :             return TransactionCommitFailed;
     331             : 
     332           0 :         CTransaction* t = (CTransaction*)newTx;
     333             :         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
     334             :         ssTx << *t;
     335           0 :         transaction_array.append(&(ssTx[0]), ssTx.size());
     336             :     }
     337             : 
     338             :     // Add addresses / update labels that we've sent to to the address book,
     339             :     // and emit coinsSent signal for each recipient
     340           0 :     Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients())
     341             :     {
     342             :         // Don't touch the address book when we have a payment request
     343           0 :         if (!rcp.paymentRequest.IsInitialized())
     344             :         {
     345           0 :             std::string strAddress = rcp.address.toStdString();
     346           0 :             CTxDestination dest = CBitcoinAddress(strAddress).Get();
     347           0 :             std::string strLabel = rcp.label.toStdString();
     348             :             {
     349           0 :                 LOCK(wallet->cs_wallet);
     350             : 
     351           0 :                 std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest);
     352             : 
     353             :                 // Check if we have a new address or an updated label
     354           0 :                 if (mi == wallet->mapAddressBook.end())
     355             :                 {
     356           0 :                     wallet->SetAddressBook(dest, strLabel, "send");
     357             :                 }
     358           0 :                 else if (mi->second.name != strLabel)
     359             :                 {
     360           0 :                     wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose
     361             :                 }
     362             :             }
     363             :         }
     364           0 :         Q_EMIT coinsSent(wallet, rcp, transaction_array);
     365             :     }
     366           0 :     checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
     367             : 
     368           0 :     return SendCoinsReturn(OK);
     369             : }
     370             : 
     371           0 : OptionsModel *WalletModel::getOptionsModel()
     372             : {
     373           0 :     return optionsModel;
     374             : }
     375             : 
     376           0 : AddressTableModel *WalletModel::getAddressTableModel()
     377             : {
     378           0 :     return addressTableModel;
     379             : }
     380             : 
     381           0 : TransactionTableModel *WalletModel::getTransactionTableModel()
     382             : {
     383           0 :     return transactionTableModel;
     384             : }
     385             : 
     386           0 : RecentRequestsTableModel *WalletModel::getRecentRequestsTableModel()
     387             : {
     388           0 :     return recentRequestsTableModel;
     389             : }
     390             : 
     391           0 : WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
     392             : {
     393           0 :     if(!wallet->IsCrypted())
     394             :     {
     395             :         return Unencrypted;
     396             :     }
     397           0 :     else if(wallet->IsLocked())
     398             :     {
     399             :         return Locked;
     400             :     }
     401             :     else
     402             :     {
     403           0 :         return Unlocked;
     404             :     }
     405             : }
     406             : 
     407           0 : bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
     408             : {
     409           0 :     if(encrypted)
     410             :     {
     411             :         // Encrypt
     412           0 :         return wallet->EncryptWallet(passphrase);
     413             :     }
     414             :     else
     415             :     {
     416             :         // Decrypt -- TODO; not supported yet
     417             :         return false;
     418             :     }
     419             : }
     420             : 
     421           0 : bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
     422             : {
     423           0 :     if(locked)
     424             :     {
     425             :         // Lock
     426           0 :         return wallet->Lock();
     427             :     }
     428             :     else
     429             :     {
     430             :         // Unlock
     431           0 :         return wallet->Unlock(passPhrase);
     432             :     }
     433             : }
     434             : 
     435           0 : bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
     436             : {
     437             :     bool retval;
     438             :     {
     439           0 :         LOCK(wallet->cs_wallet);
     440           0 :         wallet->Lock(); // Make sure wallet is locked before attempting pass change
     441           0 :         retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
     442             :     }
     443           0 :     return retval;
     444             : }
     445             : 
     446           0 : bool WalletModel::backupWallet(const QString &filename)
     447             : {
     448           0 :     return BackupWallet(*wallet, filename.toLocal8Bit().data());
     449             : }
     450             : 
     451             : // Handlers for core signals
     452           0 : static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
     453             : {
     454           0 :     qDebug() << "NotifyKeyStoreStatusChanged";
     455             :     QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
     456           0 : }
     457             : 
     458           0 : static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
     459             :         const CTxDestination &address, const std::string &label, bool isMine,
     460             :         const std::string &purpose, ChangeType status)
     461             : {
     462           0 :     QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString());
     463           0 :     QString strLabel = QString::fromStdString(label);
     464           0 :     QString strPurpose = QString::fromStdString(purpose);
     465             : 
     466           0 :     qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status);
     467             :     QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
     468             :                               Q_ARG(QString, strAddress),
     469             :                               Q_ARG(QString, strLabel),
     470             :                               Q_ARG(bool, isMine),
     471             :                               Q_ARG(QString, strPurpose),
     472           0 :                               Q_ARG(int, status));
     473           0 : }
     474             : 
     475           0 : static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
     476             : {
     477             :     Q_UNUSED(wallet);
     478             :     Q_UNUSED(hash);
     479             :     Q_UNUSED(status);
     480             :     QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection);
     481           0 : }
     482             : 
     483           0 : static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress)
     484             : {
     485             :     // emits signal "showProgress"
     486             :     QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection,
     487             :                               Q_ARG(QString, QString::fromStdString(title)),
     488           0 :                               Q_ARG(int, nProgress));
     489           0 : }
     490             : 
     491           0 : static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly)
     492             : {
     493             :     QMetaObject::invokeMethod(walletmodel, "updateWatchOnlyFlag", Qt::QueuedConnection,
     494             :                               Q_ARG(bool, fHaveWatchonly));
     495           0 : }
     496             : 
     497           0 : void WalletModel::subscribeToCoreSignals()
     498             : {
     499             :     // Connect signals to wallet
     500           0 :     wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
     501           0 :     wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6));
     502           0 :     wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
     503           0 :     wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
     504           0 :     wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1));
     505           0 : }
     506             : 
     507           0 : void WalletModel::unsubscribeFromCoreSignals()
     508             : {
     509             :     // Disconnect signals from wallet
     510           0 :     wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
     511           0 :     wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6));
     512           0 :     wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
     513           0 :     wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
     514           0 :     wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1));
     515           0 : }
     516             : 
     517             : // WalletModel::UnlockContext implementation
     518           0 : WalletModel::UnlockContext WalletModel::requestUnlock()
     519             : {
     520           0 :     bool was_locked = getEncryptionStatus() == Locked;
     521           0 :     if(was_locked)
     522             :     {
     523             :         // Request UI to unlock wallet
     524           0 :         Q_EMIT requireUnlock();
     525             :     }
     526             :     // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
     527           0 :     bool valid = getEncryptionStatus() != Locked;
     528             : 
     529           0 :     return UnlockContext(this, valid, was_locked);
     530             : }
     531             : 
     532           0 : WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
     533             :         wallet(wallet),
     534             :         valid(valid),
     535           0 :         relock(relock)
     536             : {
     537           0 : }
     538             : 
     539           0 : WalletModel::UnlockContext::~UnlockContext()
     540             : {
     541           0 :     if(valid && relock)
     542             :     {
     543           0 :         wallet->setWalletLocked(true);
     544             :     }
     545           0 : }
     546             : 
     547           0 : void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
     548             : {
     549             :     // Transfer context; old object no longer relocks wallet
     550           0 :     *this = rhs;
     551           0 :     rhs.relock = false;
     552           0 : }
     553             : 
     554           0 : bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
     555             : {
     556           0 :     return wallet->GetPubKey(address, vchPubKeyOut);
     557             : }
     558             : 
     559           0 : bool WalletModel::havePrivKey(const CKeyID &address) const
     560             : {
     561           0 :     return wallet->HaveKey(address);
     562             : }
     563             : 
     564             : // returns a list of COutputs from COutPoints
     565           0 : void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
     566             : {
     567           0 :     LOCK2(cs_main, wallet->cs_wallet);
     568           0 :     BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
     569             :     {
     570           0 :         if (!wallet->mapWallet.count(outpoint.hash)) continue;
     571           0 :         int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
     572           0 :         if (nDepth < 0) continue;
     573           0 :         COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
     574           0 :         vOutputs.push_back(out);
     575             :     }
     576           0 : }
     577             : 
     578           0 : bool WalletModel::isSpent(const COutPoint& outpoint) const
     579             : {
     580           0 :     LOCK2(cs_main, wallet->cs_wallet);
     581           0 :     return wallet->IsSpent(outpoint.hash, outpoint.n);
     582             : }
     583             : 
     584             : // AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
     585           0 : void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
     586             : {
     587             :     std::vector<COutput> vCoins;
     588           0 :     wallet->AvailableCoins(vCoins);
     589             : 
     590           0 :     LOCK2(cs_main, wallet->cs_wallet); // ListLockedCoins, mapWallet
     591             :     std::vector<COutPoint> vLockedCoins;
     592           0 :     wallet->ListLockedCoins(vLockedCoins);
     593             : 
     594             :     // add locked coins
     595           0 :     BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
     596             :     {
     597           0 :         if (!wallet->mapWallet.count(outpoint.hash)) continue;
     598           0 :         int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
     599           0 :         if (nDepth < 0) continue;
     600           0 :         COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
     601           0 :         if (outpoint.n < out.tx->vout.size() && wallet->IsMine(out.tx->vout[outpoint.n]) == ISMINE_SPENDABLE)
     602           0 :             vCoins.push_back(out);
     603             :     }
     604             : 
     605           0 :     BOOST_FOREACH(const COutput& out, vCoins)
     606             :     {
     607           0 :         COutput cout = out;
     608             : 
     609           0 :         while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
     610             :         {
     611           0 :             if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
     612           0 :             cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0, true);
     613             :         }
     614             : 
     615             :         CTxDestination address;
     616           0 :         if(!out.fSpendable || !ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address))
     617             :             continue;
     618           0 :         mapCoins[QString::fromStdString(CBitcoinAddress(address).ToString())].push_back(out);
     619             :     }
     620           0 : }
     621             : 
     622           0 : bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
     623             : {
     624           0 :     LOCK2(cs_main, wallet->cs_wallet);
     625           0 :     return wallet->IsLockedCoin(hash, n);
     626             : }
     627             : 
     628           0 : void WalletModel::lockCoin(COutPoint& output)
     629             : {
     630           0 :     LOCK2(cs_main, wallet->cs_wallet);
     631           0 :     wallet->LockCoin(output);
     632           0 : }
     633             : 
     634           0 : void WalletModel::unlockCoin(COutPoint& output)
     635             : {
     636           0 :     LOCK2(cs_main, wallet->cs_wallet);
     637           0 :     wallet->UnlockCoin(output);
     638           0 : }
     639             : 
     640           0 : void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
     641             : {
     642           0 :     LOCK2(cs_main, wallet->cs_wallet);
     643           0 :     wallet->ListLockedCoins(vOutpts);
     644           0 : }
     645             : 
     646           0 : void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
     647             : {
     648           0 :     LOCK(wallet->cs_wallet);
     649           0 :     BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook)
     650           0 :         BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item2, item.second.destdata)
     651           0 :             if (item2.first.size() > 2 && item2.first.substr(0,2) == "rr") // receive request
     652           0 :                 vReceiveRequests.push_back(item2.second);
     653           0 : }
     654             : 
     655           0 : bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
     656             : {
     657           0 :     CTxDestination dest = CBitcoinAddress(sAddress).Get();
     658             : 
     659           0 :     std::stringstream ss;
     660             :     ss << nId;
     661           0 :     std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
     662             : 
     663           0 :     LOCK(wallet->cs_wallet);
     664           0 :     if (sRequest.empty())
     665           0 :         return wallet->EraseDestData(dest, key);
     666             :     else
     667           0 :         return wallet->AddDestData(dest, key, sRequest);
     668           0 : }

Generated by: LCOV version 1.11