1 // Copyright (c) 2011-2016 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.
5 #include "walletmodel.h"
7 #include "addresstablemodel.h"
8 #include "consensus/validation.h"
9 #include "guiconstants.h"
11 #include "optionsmodel.h"
12 #include "paymentserver.h"
13 #include "recentrequeststablemodel.h"
14 #include "sendcoinsdialog.h"
15 #include "transactiontablemodel.h"
20 #include "validation.h"
21 #include "net.h" // for g_connman
22 #include "policy/fees.h"
23 #include "policy/rbf.h"
25 #include "ui_interface.h"
26 #include "util.h" // for GetBoolArg
27 #include "wallet/coincontrol.h"
28 #include "wallet/feebumper.h"
29 #include "wallet/wallet.h"
30 #include "wallet/walletdb.h" // for BackupWallet
35 #include <QMessageBox>
40 WalletModel::WalletModel(const PlatformStyle
*platformStyle
, CWallet
*_wallet
, OptionsModel
*_optionsModel
, QObject
*parent
) :
41 QObject(parent
), wallet(_wallet
), optionsModel(_optionsModel
), addressTableModel(0),
42 transactionTableModel(0),
43 recentRequestsTableModel(0),
44 cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
45 cachedEncryptionStatus(Unencrypted
),
48 fHaveWatchOnly
= wallet
->HaveWatchOnly();
49 fForceCheckBalanceChanged
= false;
51 addressTableModel
= new AddressTableModel(wallet
, this);
52 transactionTableModel
= new TransactionTableModel(platformStyle
, wallet
, this);
53 recentRequestsTableModel
= new RecentRequestsTableModel(wallet
, this);
55 // This timer will be fired repeatedly to update the balance
56 pollTimer
= new QTimer(this);
57 connect(pollTimer
, SIGNAL(timeout()), this, SLOT(pollBalanceChanged()));
58 pollTimer
->start(MODEL_UPDATE_DELAY
);
60 subscribeToCoreSignals();
63 WalletModel::~WalletModel()
65 unsubscribeFromCoreSignals();
68 CAmount
WalletModel::getBalance(const CCoinControl
*coinControl
) const
72 return wallet
->GetAvailableBalance(coinControl
);
75 return wallet
->GetBalance();
78 CAmount
WalletModel::getUnconfirmedBalance() const
80 return wallet
->GetUnconfirmedBalance();
83 CAmount
WalletModel::getImmatureBalance() const
85 return wallet
->GetImmatureBalance();
88 bool WalletModel::haveWatchOnly() const
90 return fHaveWatchOnly
;
93 CAmount
WalletModel::getWatchBalance() const
95 return wallet
->GetWatchOnlyBalance();
98 CAmount
WalletModel::getWatchUnconfirmedBalance() const
100 return wallet
->GetUnconfirmedWatchOnlyBalance();
103 CAmount
WalletModel::getWatchImmatureBalance() const
105 return wallet
->GetImmatureWatchOnlyBalance();
108 void WalletModel::updateStatus()
110 EncryptionStatus newEncryptionStatus
= getEncryptionStatus();
112 if(cachedEncryptionStatus
!= newEncryptionStatus
)
113 Q_EMIT
encryptionStatusChanged(newEncryptionStatus
);
116 void WalletModel::pollBalanceChanged()
118 // Get required locks upfront. This avoids the GUI from getting stuck on
119 // periodical polls if the core is holding the locks for a longer time -
120 // for example, during a wallet rescan.
121 TRY_LOCK(cs_main
, lockMain
);
124 TRY_LOCK(wallet
->cs_wallet
, lockWallet
);
128 if(fForceCheckBalanceChanged
|| chainActive
.Height() != cachedNumBlocks
)
130 fForceCheckBalanceChanged
= false;
132 // Balance and number of transactions might have changed
133 cachedNumBlocks
= chainActive
.Height();
135 checkBalanceChanged();
136 if(transactionTableModel
)
137 transactionTableModel
->updateConfirmations();
141 void WalletModel::checkBalanceChanged()
143 CAmount newBalance
= getBalance();
144 CAmount newUnconfirmedBalance
= getUnconfirmedBalance();
145 CAmount newImmatureBalance
= getImmatureBalance();
146 CAmount newWatchOnlyBalance
= 0;
147 CAmount newWatchUnconfBalance
= 0;
148 CAmount newWatchImmatureBalance
= 0;
151 newWatchOnlyBalance
= getWatchBalance();
152 newWatchUnconfBalance
= getWatchUnconfirmedBalance();
153 newWatchImmatureBalance
= getWatchImmatureBalance();
156 if(cachedBalance
!= newBalance
|| cachedUnconfirmedBalance
!= newUnconfirmedBalance
|| cachedImmatureBalance
!= newImmatureBalance
||
157 cachedWatchOnlyBalance
!= newWatchOnlyBalance
|| cachedWatchUnconfBalance
!= newWatchUnconfBalance
|| cachedWatchImmatureBalance
!= newWatchImmatureBalance
)
159 cachedBalance
= newBalance
;
160 cachedUnconfirmedBalance
= newUnconfirmedBalance
;
161 cachedImmatureBalance
= newImmatureBalance
;
162 cachedWatchOnlyBalance
= newWatchOnlyBalance
;
163 cachedWatchUnconfBalance
= newWatchUnconfBalance
;
164 cachedWatchImmatureBalance
= newWatchImmatureBalance
;
165 Q_EMIT
balanceChanged(newBalance
, newUnconfirmedBalance
, newImmatureBalance
,
166 newWatchOnlyBalance
, newWatchUnconfBalance
, newWatchImmatureBalance
);
170 void WalletModel::updateTransaction()
172 // Balance and number of transactions might have changed
173 fForceCheckBalanceChanged
= true;
176 void WalletModel::updateAddressBook(const QString
&address
, const QString
&label
,
177 bool isMine
, const QString
&purpose
, int status
)
179 if(addressTableModel
)
180 addressTableModel
->updateEntry(address
, label
, isMine
, purpose
, status
);
183 void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly
)
185 fHaveWatchOnly
= fHaveWatchonly
;
186 Q_EMIT
notifyWatchonlyChanged(fHaveWatchonly
);
189 bool WalletModel::validateAddress(const QString
&address
)
191 return IsValidDestinationString(address
.toStdString());
194 WalletModel::SendCoinsReturn
WalletModel::prepareTransaction(WalletModelTransaction
&transaction
, const CCoinControl
& coinControl
)
197 bool fSubtractFeeFromAmount
= false;
198 QList
<SendCoinsRecipient
> recipients
= transaction
.getRecipients();
199 std::vector
<CRecipient
> vecSend
;
201 if(recipients
.empty())
206 QSet
<QString
> setAddress
; // Used to detect duplicates
209 // Pre-check input data for validity
210 for (const SendCoinsRecipient
&rcp
: recipients
)
212 if (rcp
.fSubtractFeeFromAmount
)
213 fSubtractFeeFromAmount
= true;
215 if (rcp
.paymentRequest
.IsInitialized())
216 { // PaymentRequest...
217 CAmount subtotal
= 0;
218 const payments::PaymentDetails
& details
= rcp
.paymentRequest
.getDetails();
219 for (int i
= 0; i
< details
.outputs_size(); i
++)
221 const payments::Output
& out
= details
.outputs(i
);
222 if (out
.amount() <= 0) continue;
223 subtotal
+= out
.amount();
224 const unsigned char* scriptStr
= (const unsigned char*)out
.script().data();
225 CScript
scriptPubKey(scriptStr
, scriptStr
+out
.script().size());
226 CAmount nAmount
= out
.amount();
227 CRecipient recipient
= {scriptPubKey
, nAmount
, rcp
.fSubtractFeeFromAmount
};
228 vecSend
.push_back(recipient
);
232 return InvalidAmount
;
237 { // User-entered bitcoin address / amount:
238 if(!validateAddress(rcp
.address
))
240 return InvalidAddress
;
244 return InvalidAmount
;
246 setAddress
.insert(rcp
.address
);
249 CScript scriptPubKey
= GetScriptForDestination(DecodeDestination(rcp
.address
.toStdString()));
250 CRecipient recipient
= {scriptPubKey
, rcp
.amount
, rcp
.fSubtractFeeFromAmount
};
251 vecSend
.push_back(recipient
);
256 if(setAddress
.size() != nAddresses
)
258 return DuplicateAddress
;
261 CAmount nBalance
= getBalance(&coinControl
);
265 return AmountExceedsBalance
;
269 LOCK2(cs_main
, wallet
->cs_wallet
);
271 transaction
.newPossibleKeyChange(wallet
);
273 CAmount nFeeRequired
= 0;
274 int nChangePosRet
= -1;
275 std::string strFailReason
;
277 CWalletTx
*newTx
= transaction
.getTransaction();
278 CReserveKey
*keyChange
= transaction
.getPossibleKeyChange();
279 bool fCreated
= wallet
->CreateTransaction(vecSend
, *newTx
, *keyChange
, nFeeRequired
, nChangePosRet
, strFailReason
, coinControl
);
280 transaction
.setTransactionFee(nFeeRequired
);
281 if (fSubtractFeeFromAmount
&& fCreated
)
282 transaction
.reassignAmounts(nChangePosRet
);
286 if(!fSubtractFeeFromAmount
&& (total
+ nFeeRequired
) > nBalance
)
288 return SendCoinsReturn(AmountWithFeeExceedsBalance
);
290 Q_EMIT
message(tr("Send Coins"), QString::fromStdString(strFailReason
),
291 CClientUIInterface::MSG_ERROR
);
292 return TransactionCreationFailed
;
295 // reject absurdly high fee. (This can never happen because the
296 // wallet caps the fee at maxTxFee. This merely serves as a
297 // belt-and-suspenders check)
298 if (nFeeRequired
> maxTxFee
)
302 return SendCoinsReturn(OK
);
305 WalletModel::SendCoinsReturn
WalletModel::sendCoins(WalletModelTransaction
&transaction
)
307 QByteArray transaction_array
; /* store serialized transaction */
310 LOCK2(cs_main
, wallet
->cs_wallet
);
311 CWalletTx
*newTx
= transaction
.getTransaction();
313 for (const SendCoinsRecipient
&rcp
: transaction
.getRecipients())
315 if (rcp
.paymentRequest
.IsInitialized())
317 // Make sure any payment requests involved are still valid.
318 if (PaymentServer::verifyExpired(rcp
.paymentRequest
.getDetails())) {
319 return PaymentRequestExpired
;
322 // Store PaymentRequests in wtx.vOrderForm in wallet.
323 std::string
key("PaymentRequest");
325 rcp
.paymentRequest
.SerializeToString(&value
);
326 newTx
->vOrderForm
.push_back(make_pair(key
, value
));
328 else if (!rcp
.message
.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
329 newTx
->vOrderForm
.push_back(make_pair("Message", rcp
.message
.toStdString()));
332 CReserveKey
*keyChange
= transaction
.getPossibleKeyChange();
333 CValidationState state
;
334 if(!wallet
->CommitTransaction(*newTx
, *keyChange
, g_connman
.get(), state
))
335 return SendCoinsReturn(TransactionCommitFailed
, QString::fromStdString(state
.GetRejectReason()));
337 CDataStream
ssTx(SER_NETWORK
, PROTOCOL_VERSION
);
339 transaction_array
.append(&(ssTx
[0]), ssTx
.size());
342 // Add addresses / update labels that we've sent to the address book,
343 // and emit coinsSent signal for each recipient
344 for (const SendCoinsRecipient
&rcp
: transaction
.getRecipients())
346 // Don't touch the address book when we have a payment request
347 if (!rcp
.paymentRequest
.IsInitialized())
349 std::string strAddress
= rcp
.address
.toStdString();
350 CTxDestination dest
= DecodeDestination(strAddress
);
351 std::string strLabel
= rcp
.label
.toStdString();
353 LOCK(wallet
->cs_wallet
);
355 std::map
<CTxDestination
, CAddressBookData
>::iterator mi
= wallet
->mapAddressBook
.find(dest
);
357 // Check if we have a new address or an updated label
358 if (mi
== wallet
->mapAddressBook
.end())
360 wallet
->SetAddressBook(dest
, strLabel
, "send");
362 else if (mi
->second
.name
!= strLabel
)
364 wallet
->SetAddressBook(dest
, strLabel
, ""); // "" means don't change purpose
368 Q_EMIT
coinsSent(wallet
, rcp
, transaction_array
);
370 checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
372 return SendCoinsReturn(OK
);
375 OptionsModel
*WalletModel::getOptionsModel()
380 AddressTableModel
*WalletModel::getAddressTableModel()
382 return addressTableModel
;
385 TransactionTableModel
*WalletModel::getTransactionTableModel()
387 return transactionTableModel
;
390 RecentRequestsTableModel
*WalletModel::getRecentRequestsTableModel()
392 return recentRequestsTableModel
;
395 WalletModel::EncryptionStatus
WalletModel::getEncryptionStatus() const
397 if(!wallet
->IsCrypted())
401 else if(wallet
->IsLocked())
411 bool WalletModel::setWalletEncrypted(bool encrypted
, const SecureString
&passphrase
)
416 return wallet
->EncryptWallet(passphrase
);
420 // Decrypt -- TODO; not supported yet
425 bool WalletModel::setWalletLocked(bool locked
, const SecureString
&passPhrase
)
430 return wallet
->Lock();
435 return wallet
->Unlock(passPhrase
);
439 bool WalletModel::changePassphrase(const SecureString
&oldPass
, const SecureString
&newPass
)
443 LOCK(wallet
->cs_wallet
);
444 wallet
->Lock(); // Make sure wallet is locked before attempting pass change
445 retval
= wallet
->ChangeWalletPassphrase(oldPass
, newPass
);
450 bool WalletModel::backupWallet(const QString
&filename
)
452 return wallet
->BackupWallet(filename
.toLocal8Bit().data());
455 // Handlers for core signals
456 static void NotifyKeyStoreStatusChanged(WalletModel
*walletmodel
, CCryptoKeyStore
*wallet
)
458 qDebug() << "NotifyKeyStoreStatusChanged";
459 QMetaObject::invokeMethod(walletmodel
, "updateStatus", Qt::QueuedConnection
);
462 static void NotifyAddressBookChanged(WalletModel
*walletmodel
, CWallet
*wallet
,
463 const CTxDestination
&address
, const std::string
&label
, bool isMine
,
464 const std::string
&purpose
, ChangeType status
)
466 QString strAddress
= QString::fromStdString(EncodeDestination(address
));
467 QString strLabel
= QString::fromStdString(label
);
468 QString strPurpose
= QString::fromStdString(purpose
);
470 qDebug() << "NotifyAddressBookChanged: " + strAddress
+ " " + strLabel
+ " isMine=" + QString::number(isMine
) + " purpose=" + strPurpose
+ " status=" + QString::number(status
);
471 QMetaObject::invokeMethod(walletmodel
, "updateAddressBook", Qt::QueuedConnection
,
472 Q_ARG(QString
, strAddress
),
473 Q_ARG(QString
, strLabel
),
475 Q_ARG(QString
, strPurpose
),
479 static void NotifyTransactionChanged(WalletModel
*walletmodel
, CWallet
*wallet
, const uint256
&hash
, ChangeType status
)
484 QMetaObject::invokeMethod(walletmodel
, "updateTransaction", Qt::QueuedConnection
);
487 static void ShowProgress(WalletModel
*walletmodel
, const std::string
&title
, int nProgress
)
489 // emits signal "showProgress"
490 QMetaObject::invokeMethod(walletmodel
, "showProgress", Qt::QueuedConnection
,
491 Q_ARG(QString
, QString::fromStdString(title
)),
492 Q_ARG(int, nProgress
));
495 static void NotifyWatchonlyChanged(WalletModel
*walletmodel
, bool fHaveWatchonly
)
497 QMetaObject::invokeMethod(walletmodel
, "updateWatchOnlyFlag", Qt::QueuedConnection
,
498 Q_ARG(bool, fHaveWatchonly
));
501 void WalletModel::subscribeToCoreSignals()
503 // Connect signals to wallet
504 wallet
->NotifyStatusChanged
.connect(boost::bind(&NotifyKeyStoreStatusChanged
, this, _1
));
505 wallet
->NotifyAddressBookChanged
.connect(boost::bind(NotifyAddressBookChanged
, this, _1
, _2
, _3
, _4
, _5
, _6
));
506 wallet
->NotifyTransactionChanged
.connect(boost::bind(NotifyTransactionChanged
, this, _1
, _2
, _3
));
507 wallet
->ShowProgress
.connect(boost::bind(ShowProgress
, this, _1
, _2
));
508 wallet
->NotifyWatchonlyChanged
.connect(boost::bind(NotifyWatchonlyChanged
, this, _1
));
511 void WalletModel::unsubscribeFromCoreSignals()
513 // Disconnect signals from wallet
514 wallet
->NotifyStatusChanged
.disconnect(boost::bind(&NotifyKeyStoreStatusChanged
, this, _1
));
515 wallet
->NotifyAddressBookChanged
.disconnect(boost::bind(NotifyAddressBookChanged
, this, _1
, _2
, _3
, _4
, _5
, _6
));
516 wallet
->NotifyTransactionChanged
.disconnect(boost::bind(NotifyTransactionChanged
, this, _1
, _2
, _3
));
517 wallet
->ShowProgress
.disconnect(boost::bind(ShowProgress
, this, _1
, _2
));
518 wallet
->NotifyWatchonlyChanged
.disconnect(boost::bind(NotifyWatchonlyChanged
, this, _1
));
521 // WalletModel::UnlockContext implementation
522 WalletModel::UnlockContext
WalletModel::requestUnlock()
524 bool was_locked
= getEncryptionStatus() == Locked
;
527 // Request UI to unlock wallet
528 Q_EMIT
requireUnlock();
530 // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
531 bool valid
= getEncryptionStatus() != Locked
;
533 return UnlockContext(this, valid
, was_locked
);
536 WalletModel::UnlockContext::UnlockContext(WalletModel
*_wallet
, bool _valid
, bool _relock
):
543 WalletModel::UnlockContext::~UnlockContext()
547 wallet
->setWalletLocked(true);
551 void WalletModel::UnlockContext::CopyFrom(const UnlockContext
& rhs
)
553 // Transfer context; old object no longer relocks wallet
558 bool WalletModel::getPubKey(const CKeyID
&address
, CPubKey
& vchPubKeyOut
) const
560 return wallet
->GetPubKey(address
, vchPubKeyOut
);
563 bool WalletModel::IsSpendable(const CTxDestination
& dest
) const
565 return IsMine(*wallet
, dest
) & ISMINE_SPENDABLE
;
568 bool WalletModel::getPrivKey(const CKeyID
&address
, CKey
& vchPrivKeyOut
) const
570 return wallet
->GetKey(address
, vchPrivKeyOut
);
573 // returns a list of COutputs from COutPoints
574 void WalletModel::getOutputs(const std::vector
<COutPoint
>& vOutpoints
, std::vector
<COutput
>& vOutputs
)
576 LOCK2(cs_main
, wallet
->cs_wallet
);
577 for (const COutPoint
& outpoint
: vOutpoints
)
579 auto it
= wallet
->mapWallet
.find(outpoint
.hash
);
580 if (it
== wallet
->mapWallet
.end()) continue;
581 int nDepth
= it
->second
.GetDepthInMainChain();
582 if (nDepth
< 0) continue;
583 COutput
out(&it
->second
, outpoint
.n
, nDepth
, true /* spendable */, true /* solvable */, true /* safe */);
584 vOutputs
.push_back(out
);
588 bool WalletModel::isSpent(const COutPoint
& outpoint
) const
590 LOCK2(cs_main
, wallet
->cs_wallet
);
591 return wallet
->IsSpent(outpoint
.hash
, outpoint
.n
);
594 // AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
595 void WalletModel::listCoins(std::map
<QString
, std::vector
<COutput
> >& mapCoins
) const
597 for (auto& group
: wallet
->ListCoins()) {
598 auto& resultGroup
= mapCoins
[QString::fromStdString(EncodeDestination(group
.first
))];
599 for (auto& coin
: group
.second
) {
600 resultGroup
.emplace_back(std::move(coin
));
605 bool WalletModel::isLockedCoin(uint256 hash
, unsigned int n
) const
607 LOCK2(cs_main
, wallet
->cs_wallet
);
608 return wallet
->IsLockedCoin(hash
, n
);
611 void WalletModel::lockCoin(COutPoint
& output
)
613 LOCK2(cs_main
, wallet
->cs_wallet
);
614 wallet
->LockCoin(output
);
617 void WalletModel::unlockCoin(COutPoint
& output
)
619 LOCK2(cs_main
, wallet
->cs_wallet
);
620 wallet
->UnlockCoin(output
);
623 void WalletModel::listLockedCoins(std::vector
<COutPoint
>& vOutpts
)
625 LOCK2(cs_main
, wallet
->cs_wallet
);
626 wallet
->ListLockedCoins(vOutpts
);
629 void WalletModel::loadReceiveRequests(std::vector
<std::string
>& vReceiveRequests
)
631 vReceiveRequests
= wallet
->GetDestValues("rr"); // receive request
634 bool WalletModel::saveReceiveRequest(const std::string
&sAddress
, const int64_t nId
, const std::string
&sRequest
)
636 CTxDestination dest
= DecodeDestination(sAddress
);
638 std::stringstream ss
;
640 std::string key
= "rr" + ss
.str(); // "rr" prefix = "receive request" in destdata
642 LOCK(wallet
->cs_wallet
);
643 if (sRequest
.empty())
644 return wallet
->EraseDestData(dest
, key
);
646 return wallet
->AddDestData(dest
, key
, sRequest
);
649 bool WalletModel::transactionCanBeAbandoned(uint256 hash
) const
651 return wallet
->TransactionCanBeAbandoned(hash
);
654 bool WalletModel::abandonTransaction(uint256 hash
) const
656 LOCK2(cs_main
, wallet
->cs_wallet
);
657 return wallet
->AbandonTransaction(hash
);
660 bool WalletModel::transactionCanBeBumped(uint256 hash
) const
662 LOCK2(cs_main
, wallet
->cs_wallet
);
663 const CWalletTx
*wtx
= wallet
->GetWalletTx(hash
);
664 return wtx
&& SignalsOptInRBF(*wtx
) && !wtx
->mapValue
.count("replaced_by_txid");
667 bool WalletModel::bumpFee(uint256 hash
)
669 std::unique_ptr
<CFeeBumper
> feeBump
;
671 CCoinControl coin_control
;
672 coin_control
.signalRbf
= true;
673 LOCK2(cs_main
, wallet
->cs_wallet
);
674 feeBump
.reset(new CFeeBumper(wallet
, hash
, coin_control
, 0));
676 if (feeBump
->getResult() != BumpFeeResult::OK
)
678 QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
679 (feeBump
->getErrors().size() ? QString::fromStdString(feeBump
->getErrors()[0]) : "") +")");
683 // allow a user based fee verification
684 QString questionString
= tr("Do you want to increase the fee?");
685 questionString
.append("<br />");
686 CAmount oldFee
= feeBump
->getOldFee();
687 CAmount newFee
= feeBump
->getNewFee();
688 questionString
.append("<table style=\"text-align: left;\">");
689 questionString
.append("<tr><td>");
690 questionString
.append(tr("Current fee:"));
691 questionString
.append("</td><td>");
692 questionString
.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), oldFee
));
693 questionString
.append("</td></tr><tr><td>");
694 questionString
.append(tr("Increase:"));
695 questionString
.append("</td><td>");
696 questionString
.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), newFee
- oldFee
));
697 questionString
.append("</td></tr><tr><td>");
698 questionString
.append(tr("New fee:"));
699 questionString
.append("</td><td>");
700 questionString
.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), newFee
));
701 questionString
.append("</td></tr></table>");
702 SendConfirmationDialog
confirmationDialog(tr("Confirm fee bump"), questionString
);
703 confirmationDialog
.exec();
704 QMessageBox::StandardButton retval
= (QMessageBox::StandardButton
)confirmationDialog
.result();
706 // cancel sign&broadcast if users doesn't want to bump the fee
707 if (retval
!= QMessageBox::Yes
) {
711 WalletModel::UnlockContext
ctx(requestUnlock());
717 // sign bumped transaction
720 LOCK2(cs_main
, wallet
->cs_wallet
);
721 res
= feeBump
->signTransaction(wallet
);
724 QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
727 // commit the bumped transaction
729 LOCK2(cs_main
, wallet
->cs_wallet
);
730 res
= feeBump
->commit(wallet
);
733 QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
734 QString::fromStdString(feeBump
->getErrors()[0])+")");
740 bool WalletModel::isWalletEnabled()
742 return !gArgs
.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET
);
745 bool WalletModel::hdEnabled() const
747 return wallet
->IsHDEnabled();
750 int WalletModel::getDefaultConfirmTarget() const
752 return nTxConfirmTarget
;
755 bool WalletModel::getDefaultWalletRbf() const