aboutsummaryrefslogtreecommitdiff
path: root/src/qt/walletmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt/walletmodel.cpp')
-rw-r--r--src/qt/walletmodel.cpp337
1 files changed, 70 insertions, 267 deletions
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 795302be58..00b98901c0 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -5,29 +5,20 @@
#include <qt/walletmodel.h>
#include <qt/addresstablemodel.h>
-#include <consensus/validation.h>
#include <qt/guiconstants.h>
-#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/paymentserver.h>
#include <qt/recentrequeststablemodel.h>
#include <qt/sendcoinsdialog.h>
#include <qt/transactiontablemodel.h>
-#include <chain.h>
+#include <interfaces/handler.h>
+#include <interfaces/node.h>
#include <key_io.h>
-#include <keystore.h>
-#include <validation.h>
-#include <net.h> // for g_connman
-#include <policy/fees.h>
-#include <policy/rbf.h>
-#include <sync.h>
#include <ui_interface.h>
#include <util.h> // for GetBoolArg
#include <wallet/coincontrol.h>
-#include <wallet/feebumper.h>
#include <wallet/wallet.h>
-#include <wallet/walletdb.h> // for BackupWallet
#include <stdint.h>
@@ -37,21 +28,19 @@
#include <QTimer>
-WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) :
- QObject(parent), wallet(_wallet), optionsModel(_optionsModel), addressTableModel(0),
+WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *_optionsModel, QObject *parent) :
+ QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(0),
transactionTableModel(0),
recentRequestsTableModel(0),
- cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
- cachedWatchOnlyBalance{0}, cachedWatchUnconfBalance{0}, cachedWatchImmatureBalance{0},
cachedEncryptionStatus(Unencrypted),
cachedNumBlocks(0)
{
- fHaveWatchOnly = wallet->HaveWatchOnly();
+ fHaveWatchOnly = m_wallet->haveWatchOnly();
fForceCheckBalanceChanged = false;
- addressTableModel = new AddressTableModel(wallet, this);
- transactionTableModel = new TransactionTableModel(platformStyle, wallet, this);
- recentRequestsTableModel = new RecentRequestsTableModel(wallet, this);
+ addressTableModel = new AddressTableModel(this);
+ transactionTableModel = new TransactionTableModel(platformStyle, this);
+ recentRequestsTableModel = new RecentRequestsTableModel(this);
// This timer will be fired repeatedly to update the balance
pollTimer = new QTimer(this);
@@ -66,46 +55,6 @@ WalletModel::~WalletModel()
unsubscribeFromCoreSignals();
}
-CAmount WalletModel::getBalance(const CCoinControl *coinControl) const
-{
- if (coinControl)
- {
- return wallet->GetAvailableBalance(coinControl);
- }
-
- return wallet->GetBalance();
-}
-
-CAmount WalletModel::getUnconfirmedBalance() const
-{
- return wallet->GetUnconfirmedBalance();
-}
-
-CAmount WalletModel::getImmatureBalance() const
-{
- return wallet->GetImmatureBalance();
-}
-
-bool WalletModel::haveWatchOnly() const
-{
- return fHaveWatchOnly;
-}
-
-CAmount WalletModel::getWatchBalance() const
-{
- return wallet->GetWatchOnlyBalance();
-}
-
-CAmount WalletModel::getWatchUnconfirmedBalance() const
-{
- return wallet->GetUnconfirmedWatchOnlyBalance();
-}
-
-CAmount WalletModel::getWatchImmatureBalance() const
-{
- return wallet->GetImmatureWatchOnlyBalance();
-}
-
void WalletModel::updateStatus()
{
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
@@ -117,55 +66,34 @@ void WalletModel::updateStatus()
void WalletModel::pollBalanceChanged()
{
- // Get required locks upfront. This avoids the GUI from getting stuck on
- // periodical polls if the core is holding the locks for a longer time -
- // for example, during a wallet rescan.
- TRY_LOCK(cs_main, lockMain);
- if(!lockMain)
- return;
- TRY_LOCK(wallet->cs_wallet, lockWallet);
- if(!lockWallet)
+ // Try to get balances and return early if locks can't be acquired. This
+ // avoids the GUI from getting stuck on periodical polls if the core is
+ // holding the locks for a longer time - for example, during a wallet
+ // rescan.
+ interfaces::WalletBalances new_balances;
+ int numBlocks = -1;
+ if (!m_wallet->tryGetBalances(new_balances, numBlocks)) {
return;
+ }
- if(fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks)
+ if(fForceCheckBalanceChanged || m_node.getNumBlocks() != cachedNumBlocks)
{
fForceCheckBalanceChanged = false;
// Balance and number of transactions might have changed
- cachedNumBlocks = chainActive.Height();
+ cachedNumBlocks = m_node.getNumBlocks();
- checkBalanceChanged();
+ checkBalanceChanged(new_balances);
if(transactionTableModel)
transactionTableModel->updateConfirmations();
}
}
-void WalletModel::checkBalanceChanged()
+void WalletModel::checkBalanceChanged(const interfaces::WalletBalances& new_balances)
{
- CAmount newBalance = getBalance();
- CAmount newUnconfirmedBalance = getUnconfirmedBalance();
- CAmount newImmatureBalance = getImmatureBalance();
- CAmount newWatchOnlyBalance = 0;
- CAmount newWatchUnconfBalance = 0;
- CAmount newWatchImmatureBalance = 0;
- if (haveWatchOnly())
- {
- newWatchOnlyBalance = getWatchBalance();
- newWatchUnconfBalance = getWatchUnconfirmedBalance();
- newWatchImmatureBalance = getWatchImmatureBalance();
- }
-
- if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance ||
- cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance)
- {
- cachedBalance = newBalance;
- cachedUnconfirmedBalance = newUnconfirmedBalance;
- cachedImmatureBalance = newImmatureBalance;
- cachedWatchOnlyBalance = newWatchOnlyBalance;
- cachedWatchUnconfBalance = newWatchUnconfBalance;
- cachedWatchImmatureBalance = newWatchImmatureBalance;
- Q_EMIT balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
- newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance);
+ if(new_balances.balanceChanged(m_cached_balances)) {
+ m_cached_balances = new_balances;
+ Q_EMIT balanceChanged(new_balances);
}
}
@@ -260,7 +188,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return DuplicateAddress;
}
- CAmount nBalance = getBalance(&coinControl);
+ CAmount nBalance = m_wallet->getAvailableBalance(coinControl);
if(total > nBalance)
{
@@ -268,22 +196,17 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
}
{
- LOCK2(cs_main, wallet->cs_wallet);
-
- transaction.newPossibleKeyChange(wallet);
-
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
std::string strFailReason;
- CTransactionRef& newTx = transaction.getTransaction();
- CReserveKey *keyChange = transaction.getPossibleKeyChange();
- bool fCreated = wallet->CreateTransaction(vecSend, newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl);
+ auto& newTx = transaction.getWtx();
+ newTx = m_wallet->createTransaction(vecSend, coinControl, true /* sign */, nChangePosRet, nFeeRequired, strFailReason);
transaction.setTransactionFee(nFeeRequired);
- if (fSubtractFeeFromAmount && fCreated)
+ if (fSubtractFeeFromAmount && newTx)
transaction.reassignAmounts(nChangePosRet);
- if(!fCreated)
+ if(!newTx)
{
if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance)
{
@@ -297,7 +220,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
// reject absurdly high fee. (This can never happen because the
// wallet caps the fee at maxTxFee. This merely serves as a
// belt-and-suspenders check)
- if (nFeeRequired > maxTxFee)
+ if (nFeeRequired > m_node.getMaxTxFee())
return AbsurdFee;
}
@@ -309,8 +232,6 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
QByteArray transaction_array; /* store serialized transaction */
{
- LOCK2(cs_main, wallet->cs_wallet);
-
std::vector<std::pair<std::string, std::string>> vOrderForm;
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
@@ -330,14 +251,13 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
vOrderForm.emplace_back("Message", rcp.message.toStdString());
}
- CTransactionRef& newTx = transaction.getTransaction();
- CReserveKey *keyChange = transaction.getPossibleKeyChange();
- CValidationState state;
- if (!wallet->CommitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm), {} /* fromAccount */, *keyChange, g_connman.get(), state))
- return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason()));
+ auto& newTx = transaction.getWtx();
+ std::string rejectReason;
+ if (!newTx->commit({} /* mapValue */, std::move(vOrderForm), {} /* fromAccount */, rejectReason))
+ return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(rejectReason));
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
- ssTx << newTx;
+ ssTx << newTx->get();
transaction_array.append(&(ssTx[0]), ssTx.size());
}
@@ -352,24 +272,22 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
CTxDestination dest = DecodeDestination(strAddress);
std::string strLabel = rcp.label.toStdString();
{
- LOCK(wallet->cs_wallet);
-
- std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest);
-
// Check if we have a new address or an updated label
- if (mi == wallet->mapAddressBook.end())
+ std::string name;
+ if (!m_wallet->getAddress(dest, &name))
{
- wallet->SetAddressBook(dest, strLabel, "send");
+ m_wallet->setAddressBook(dest, strLabel, "send");
}
- else if (mi->second.name != strLabel)
+ else if (name != strLabel)
{
- wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose
+ m_wallet->setAddressBook(dest, strLabel, ""); // "" means don't change purpose
}
}
}
- Q_EMIT coinsSent(wallet, rcp, transaction_array);
+ Q_EMIT coinsSent(this, rcp, transaction_array);
}
- checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
+
+ checkBalanceChanged(m_wallet->getBalances()); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
return SendCoinsReturn(OK);
}
@@ -396,11 +314,11 @@ RecentRequestsTableModel *WalletModel::getRecentRequestsTableModel()
WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
- if(!wallet->IsCrypted())
+ if(!m_wallet->isCrypted())
{
return Unencrypted;
}
- else if(wallet->IsLocked())
+ else if(m_wallet->isLocked())
{
return Locked;
}
@@ -415,7 +333,7 @@ bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphr
if(encrypted)
{
// Encrypt
- return wallet->EncryptWallet(passphrase);
+ return m_wallet->encryptWallet(passphrase);
}
else
{
@@ -429,39 +347,29 @@ bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
if(locked)
{
// Lock
- return wallet->Lock();
+ return m_wallet->lock();
}
else
{
// Unlock
- return wallet->Unlock(passPhrase);
+ return m_wallet->unlock(passPhrase);
}
}
bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
{
- bool retval;
- {
- LOCK(wallet->cs_wallet);
- wallet->Lock(); // Make sure wallet is locked before attempting pass change
- retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
- }
- return retval;
-}
-
-bool WalletModel::backupWallet(const QString &filename)
-{
- return wallet->BackupWallet(filename.toLocal8Bit().data());
+ m_wallet->lock(); // Make sure wallet is locked before attempting pass change
+ return m_wallet->changeWalletPassphrase(oldPass, newPass);
}
// Handlers for core signals
-static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
+static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
{
qDebug() << "NotifyKeyStoreStatusChanged";
QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
}
-static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
+static void NotifyAddressBookChanged(WalletModel *walletmodel,
const CTxDestination &address, const std::string &label, bool isMine,
const std::string &purpose, ChangeType status)
{
@@ -478,9 +386,8 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
Q_ARG(int, status));
}
-static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
+static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status)
{
- Q_UNUSED(wallet);
Q_UNUSED(hash);
Q_UNUSED(status);
QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection);
@@ -503,21 +410,21 @@ static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly
void WalletModel::subscribeToCoreSignals()
{
// Connect signals to wallet
- wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
- wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6));
- wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
- wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
- wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1));
+ m_handler_status_changed = m_wallet->handleStatusChanged(boost::bind(&NotifyKeyStoreStatusChanged, this));
+ m_handler_address_book_changed = m_wallet->handleAddressBookChanged(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
+ m_handler_transaction_changed = m_wallet->handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2));
+ m_handler_show_progress = m_wallet->handleShowProgress(boost::bind(ShowProgress, this, _1, _2));
+ m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(boost::bind(NotifyWatchonlyChanged, this, _1));
}
void WalletModel::unsubscribeFromCoreSignals()
{
// Disconnect signals from wallet
- wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
- wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6));
- wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
- wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
- wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1));
+ m_handler_status_changed->disconnect();
+ m_handler_address_book_changed->disconnect();
+ m_handler_transaction_changed->disconnect();
+ m_handler_show_progress->disconnect();
+ m_handler_watch_only_changed->disconnect();
}
// WalletModel::UnlockContext implementation
@@ -557,80 +464,9 @@ void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
rhs.relock = false;
}
-bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
-{
- return wallet->GetPubKey(address, vchPubKeyOut);
-}
-
-bool WalletModel::IsSpendable(const CTxDestination& dest) const
-{
- return IsMine(*wallet, dest) & ISMINE_SPENDABLE;
-}
-
-bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const
-{
- return wallet->GetKey(address, vchPrivKeyOut);
-}
-
-// returns a list of COutputs from COutPoints
-void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
-{
- LOCK2(cs_main, wallet->cs_wallet);
- for (const COutPoint& outpoint : vOutpoints)
- {
- auto it = wallet->mapWallet.find(outpoint.hash);
- if (it == wallet->mapWallet.end()) continue;
- int nDepth = it->second.GetDepthInMainChain();
- if (nDepth < 0) continue;
- COutput out(&it->second, outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
- vOutputs.push_back(out);
- }
-}
-
-bool WalletModel::isSpent(const COutPoint& outpoint) const
-{
- LOCK2(cs_main, wallet->cs_wallet);
- return wallet->IsSpent(outpoint.hash, outpoint.n);
-}
-
-// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
-void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
-{
- for (auto& group : wallet->ListCoins()) {
- auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))];
- for (auto& coin : group.second) {
- resultGroup.emplace_back(std::move(coin));
- }
- }
-}
-
-bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
-{
- LOCK2(cs_main, wallet->cs_wallet);
- return wallet->IsLockedCoin(hash, n);
-}
-
-void WalletModel::lockCoin(COutPoint& output)
-{
- LOCK2(cs_main, wallet->cs_wallet);
- wallet->LockCoin(output);
-}
-
-void WalletModel::unlockCoin(COutPoint& output)
-{
- LOCK2(cs_main, wallet->cs_wallet);
- wallet->UnlockCoin(output);
-}
-
-void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
-{
- LOCK2(cs_main, wallet->cs_wallet);
- wallet->ListLockedCoins(vOutpts);
-}
-
void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
{
- vReceiveRequests = wallet->GetDestValues("rr"); // receive request
+ vReceiveRequests = m_wallet->getDestValues("rr"); // receive request
}
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
@@ -641,27 +477,10 @@ bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t
ss << nId;
std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
- LOCK(wallet->cs_wallet);
if (sRequest.empty())
- return wallet->EraseDestData(dest, key);
+ return m_wallet->eraseDestData(dest, key);
else
- return wallet->AddDestData(dest, key, sRequest);
-}
-
-bool WalletModel::transactionCanBeAbandoned(uint256 hash) const
-{
- return wallet->TransactionCanBeAbandoned(hash);
-}
-
-bool WalletModel::abandonTransaction(uint256 hash) const
-{
- LOCK2(cs_main, wallet->cs_wallet);
- return wallet->AbandonTransaction(hash);
-}
-
-bool WalletModel::transactionCanBeBumped(uint256 hash) const
-{
- return feebumper::TransactionCanBeBumped(wallet, hash);
+ return m_wallet->addDestData(dest, key, sRequest);
}
bool WalletModel::bumpFee(uint256 hash)
@@ -672,7 +491,7 @@ bool WalletModel::bumpFee(uint256 hash)
CAmount old_fee;
CAmount new_fee;
CMutableTransaction mtx;
- if (feebumper::CreateTransaction(wallet, hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx) != feebumper::Result::OK) {
+ if (!m_wallet->createBumpTransaction(hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx)) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
(errors.size() ? QString::fromStdString(errors[0]) : "") +")");
return false;
@@ -711,13 +530,13 @@ bool WalletModel::bumpFee(uint256 hash)
}
// sign bumped transaction
- if (!feebumper::SignTransaction(wallet, mtx)) {
+ if (!m_wallet->signBumpTransaction(mtx)) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
return false;
}
// commit the bumped transaction
uint256 txid;
- if (feebumper::CommitTransaction(wallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
+ if(!m_wallet->commitBumpTransaction(hash, std::move(mtx), errors, txid)) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
QString::fromStdString(errors[0])+")");
return false;
@@ -730,28 +549,12 @@ bool WalletModel::isWalletEnabled()
return !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
}
-bool WalletModel::hdEnabled() const
-{
- return wallet->IsHDEnabled();
-}
-
-OutputType WalletModel::getDefaultAddressType() const
-{
- return wallet->m_default_address_type;
-}
-
-int WalletModel::getDefaultConfirmTarget() const
-{
- return nTxConfirmTarget;
-}
-
QString WalletModel::getWalletName() const
{
- LOCK(wallet->cs_wallet);
- return QString::fromStdString(wallet->GetName());
+ return QString::fromStdString(m_wallet->getWalletName());
}
bool WalletModel::isMultiwallet()
{
- return gArgs.GetArgs("-wallet").size() > 1;
+ return m_node.getWallets().size() > 1;
}