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 CBitcoinAddress
addressParsed(address
.toStdString());
192 return addressParsed
.IsValid();
195 WalletModel::SendCoinsReturn
WalletModel::prepareTransaction(WalletModelTransaction
&transaction
, const CCoinControl
& coinControl
)
198 bool fSubtractFeeFromAmount
= false;
199 QList
<SendCoinsRecipient
> recipients
= transaction
.getRecipients();
200 std::vector
<CRecipient
> vecSend
;
202 if(recipients
.empty())
207 QSet
<QString
> setAddress
; // Used to detect duplicates
210 // Pre-check input data for validity
211 for (const SendCoinsRecipient
&rcp
: recipients
)
213 if (rcp
.fSubtractFeeFromAmount
)
214 fSubtractFeeFromAmount
= true;
216 if (rcp
.paymentRequest
.IsInitialized())
217 { // PaymentRequest...
218 CAmount subtotal
= 0;
219 const payments::PaymentDetails
& details
= rcp
.paymentRequest
.getDetails();
220 for (int i
= 0; i
< details
.outputs_size(); i
++)
222 const payments::Output
& out
= details
.outputs(i
);
223 if (out
.amount() <= 0) continue;
224 subtotal
+= out
.amount();
225 const unsigned char* scriptStr
= (const unsigned char*)out
.script().data();
226 CScript
scriptPubKey(scriptStr
, scriptStr
+out
.script().size());
227 CAmount nAmount
= out
.amount();
228 CRecipient recipient
= {scriptPubKey
, nAmount
, rcp
.fSubtractFeeFromAmount
};
229 vecSend
.push_back(recipient
);
233 return InvalidAmount
;
238 { // User-entered bitcoin address / amount:
239 if(!validateAddress(rcp
.address
))
241 return InvalidAddress
;
245 return InvalidAmount
;
247 setAddress
.insert(rcp
.address
);
250 CScript scriptPubKey
= GetScriptForDestination(CBitcoinAddress(rcp
.address
.toStdString()).Get());
251 CRecipient recipient
= {scriptPubKey
, rcp
.amount
, rcp
.fSubtractFeeFromAmount
};
252 vecSend
.push_back(recipient
);
257 if(setAddress
.size() != nAddresses
)
259 return DuplicateAddress
;
262 CAmount nBalance
= getBalance(&coinControl
);
266 return AmountExceedsBalance
;
270 LOCK2(cs_main
, wallet
->cs_wallet
);
272 transaction
.newPossibleKeyChange(wallet
);
274 CAmount nFeeRequired
= 0;
275 int nChangePosRet
= -1;
276 std::string strFailReason
;
278 CWalletTx
*newTx
= transaction
.getTransaction();
279 CReserveKey
*keyChange
= transaction
.getPossibleKeyChange();
280 bool fCreated
= wallet
->CreateTransaction(vecSend
, *newTx
, *keyChange
, nFeeRequired
, nChangePosRet
, strFailReason
, coinControl
);
281 transaction
.setTransactionFee(nFeeRequired
);
282 if (fSubtractFeeFromAmount
&& fCreated
)
283 transaction
.reassignAmounts(nChangePosRet
);
287 if(!fSubtractFeeFromAmount
&& (total
+ nFeeRequired
) > nBalance
)
289 return SendCoinsReturn(AmountWithFeeExceedsBalance
);
291 Q_EMIT
message(tr("Send Coins"), QString::fromStdString(strFailReason
),
292 CClientUIInterface::MSG_ERROR
);
293 return TransactionCreationFailed
;
296 // reject absurdly high fee. (This can never happen because the
297 // wallet caps the fee at maxTxFee. This merely serves as a
298 // belt-and-suspenders check)
299 if (nFeeRequired
> maxTxFee
)
303 return SendCoinsReturn(OK
);
306 WalletModel::SendCoinsReturn
WalletModel::sendCoins(WalletModelTransaction
&transaction
)
308 QByteArray transaction_array
; /* store serialized transaction */
311 LOCK2(cs_main
, wallet
->cs_wallet
);
312 CWalletTx
*newTx
= transaction
.getTransaction();
314 for (const SendCoinsRecipient
&rcp
: transaction
.getRecipients())
316 if (rcp
.paymentRequest
.IsInitialized())
318 // Make sure any payment requests involved are still valid.
319 if (PaymentServer::verifyExpired(rcp
.paymentRequest
.getDetails())) {
320 return PaymentRequestExpired
;
323 // Store PaymentRequests in wtx.vOrderForm in wallet.
324 std::string
key("PaymentRequest");
326 rcp
.paymentRequest
.SerializeToString(&value
);
327 newTx
->vOrderForm
.push_back(make_pair(key
, value
));
329 else if (!rcp
.message
.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
330 newTx
->vOrderForm
.push_back(make_pair("Message", rcp
.message
.toStdString()));
333 CReserveKey
*keyChange
= transaction
.getPossibleKeyChange();
334 CValidationState state
;
335 if(!wallet
->CommitTransaction(*newTx
, *keyChange
, g_connman
.get(), state
))
336 return SendCoinsReturn(TransactionCommitFailed
, QString::fromStdString(state
.GetRejectReason()));
338 CDataStream
ssTx(SER_NETWORK
, PROTOCOL_VERSION
);
340 transaction_array
.append(&(ssTx
[0]), ssTx
.size());
343 // Add addresses / update labels that we've sent to the address book,
344 // and emit coinsSent signal for each recipient
345 for (const SendCoinsRecipient
&rcp
: transaction
.getRecipients())
347 // Don't touch the address book when we have a payment request
348 if (!rcp
.paymentRequest
.IsInitialized())
350 std::string strAddress
= rcp
.address
.toStdString();
351 CTxDestination dest
= CBitcoinAddress(strAddress
).Get();
352 std::string strLabel
= rcp
.label
.toStdString();
354 LOCK(wallet
->cs_wallet
);
356 std::map
<CTxDestination
, CAddressBookData
>::iterator mi
= wallet
->mapAddressBook
.find(dest
);
358 // Check if we have a new address or an updated label
359 if (mi
== wallet
->mapAddressBook
.end())
361 wallet
->SetAddressBook(dest
, strLabel
, "send");
363 else if (mi
->second
.name
!= strLabel
)
365 wallet
->SetAddressBook(dest
, strLabel
, ""); // "" means don't change purpose
369 Q_EMIT
coinsSent(wallet
, rcp
, transaction_array
);
371 checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
373 return SendCoinsReturn(OK
);
376 OptionsModel
*WalletModel::getOptionsModel()
381 AddressTableModel
*WalletModel::getAddressTableModel()
383 return addressTableModel
;
386 TransactionTableModel
*WalletModel::getTransactionTableModel()
388 return transactionTableModel
;
391 RecentRequestsTableModel
*WalletModel::getRecentRequestsTableModel()
393 return recentRequestsTableModel
;
396 WalletModel::EncryptionStatus
WalletModel::getEncryptionStatus() const
398 if(!wallet
->IsCrypted())
402 else if(wallet
->IsLocked())
412 bool WalletModel::setWalletEncrypted(bool encrypted
, const SecureString
&passphrase
)
417 return wallet
->EncryptWallet(passphrase
);
421 // Decrypt -- TODO; not supported yet
426 bool WalletModel::setWalletLocked(bool locked
, const SecureString
&passPhrase
)
431 return wallet
->Lock();
436 return wallet
->Unlock(passPhrase
);
440 bool WalletModel::changePassphrase(const SecureString
&oldPass
, const SecureString
&newPass
)
444 LOCK(wallet
->cs_wallet
);
445 wallet
->Lock(); // Make sure wallet is locked before attempting pass change
446 retval
= wallet
->ChangeWalletPassphrase(oldPass
, newPass
);
451 bool WalletModel::backupWallet(const QString
&filename
)
453 return wallet
->BackupWallet(filename
.toLocal8Bit().data());
456 // Handlers for core signals
457 static void NotifyKeyStoreStatusChanged(WalletModel
*walletmodel
, CCryptoKeyStore
*wallet
)
459 qDebug() << "NotifyKeyStoreStatusChanged";
460 QMetaObject::invokeMethod(walletmodel
, "updateStatus", Qt::QueuedConnection
);
463 static void NotifyAddressBookChanged(WalletModel
*walletmodel
, CWallet
*wallet
,
464 const CTxDestination
&address
, const std::string
&label
, bool isMine
,
465 const std::string
&purpose
, ChangeType status
)
467 QString strAddress
= QString::fromStdString(CBitcoinAddress(address
).ToString());
468 QString strLabel
= QString::fromStdString(label
);
469 QString strPurpose
= QString::fromStdString(purpose
);
471 qDebug() << "NotifyAddressBookChanged: " + strAddress
+ " " + strLabel
+ " isMine=" + QString::number(isMine
) + " purpose=" + strPurpose
+ " status=" + QString::number(status
);
472 QMetaObject::invokeMethod(walletmodel
, "updateAddressBook", Qt::QueuedConnection
,
473 Q_ARG(QString
, strAddress
),
474 Q_ARG(QString
, strLabel
),
476 Q_ARG(QString
, strPurpose
),
480 static void NotifyTransactionChanged(WalletModel
*walletmodel
, CWallet
*wallet
, const uint256
&hash
, ChangeType status
)
485 QMetaObject::invokeMethod(walletmodel
, "updateTransaction", Qt::QueuedConnection
);
488 static void ShowProgress(WalletModel
*walletmodel
, const std::string
&title
, int nProgress
)
490 // emits signal "showProgress"
491 QMetaObject::invokeMethod(walletmodel
, "showProgress", Qt::QueuedConnection
,
492 Q_ARG(QString
, QString::fromStdString(title
)),
493 Q_ARG(int, nProgress
));
496 static void NotifyWatchonlyChanged(WalletModel
*walletmodel
, bool fHaveWatchonly
)
498 QMetaObject::invokeMethod(walletmodel
, "updateWatchOnlyFlag", Qt::QueuedConnection
,
499 Q_ARG(bool, fHaveWatchonly
));
502 void WalletModel::subscribeToCoreSignals()
504 // Connect signals to wallet
505 wallet
->NotifyStatusChanged
.connect(boost::bind(&NotifyKeyStoreStatusChanged
, this, _1
));
506 wallet
->NotifyAddressBookChanged
.connect(boost::bind(NotifyAddressBookChanged
, this, _1
, _2
, _3
, _4
, _5
, _6
));
507 wallet
->NotifyTransactionChanged
.connect(boost::bind(NotifyTransactionChanged
, this, _1
, _2
, _3
));
508 wallet
->ShowProgress
.connect(boost::bind(ShowProgress
, this, _1
, _2
));
509 wallet
->NotifyWatchonlyChanged
.connect(boost::bind(NotifyWatchonlyChanged
, this, _1
));
512 void WalletModel::unsubscribeFromCoreSignals()
514 // Disconnect signals from wallet
515 wallet
->NotifyStatusChanged
.disconnect(boost::bind(&NotifyKeyStoreStatusChanged
, this, _1
));
516 wallet
->NotifyAddressBookChanged
.disconnect(boost::bind(NotifyAddressBookChanged
, this, _1
, _2
, _3
, _4
, _5
, _6
));
517 wallet
->NotifyTransactionChanged
.disconnect(boost::bind(NotifyTransactionChanged
, this, _1
, _2
, _3
));
518 wallet
->ShowProgress
.disconnect(boost::bind(ShowProgress
, this, _1
, _2
));
519 wallet
->NotifyWatchonlyChanged
.disconnect(boost::bind(NotifyWatchonlyChanged
, this, _1
));
522 // WalletModel::UnlockContext implementation
523 WalletModel::UnlockContext
WalletModel::requestUnlock()
525 bool was_locked
= getEncryptionStatus() == Locked
;
528 // Request UI to unlock wallet
529 Q_EMIT
requireUnlock();
531 // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
532 bool valid
= getEncryptionStatus() != Locked
;
534 return UnlockContext(this, valid
, was_locked
);
537 WalletModel::UnlockContext::UnlockContext(WalletModel
*_wallet
, bool _valid
, bool _relock
):
544 WalletModel::UnlockContext::~UnlockContext()
548 wallet
->setWalletLocked(true);
552 void WalletModel::UnlockContext::CopyFrom(const UnlockContext
& rhs
)
554 // Transfer context; old object no longer relocks wallet
559 bool WalletModel::getPubKey(const CKeyID
&address
, CPubKey
& vchPubKeyOut
) const
561 return wallet
->GetPubKey(address
, vchPubKeyOut
);
564 bool WalletModel::havePrivKey(const CKeyID
&address
) const
566 return wallet
->HaveKey(address
);
569 bool WalletModel::getPrivKey(const CKeyID
&address
, CKey
& vchPrivKeyOut
) const
571 return wallet
->GetKey(address
, vchPrivKeyOut
);
574 // returns a list of COutputs from COutPoints
575 void WalletModel::getOutputs(const std::vector
<COutPoint
>& vOutpoints
, std::vector
<COutput
>& vOutputs
)
577 LOCK2(cs_main
, wallet
->cs_wallet
);
578 for (const COutPoint
& outpoint
: vOutpoints
)
580 if (!wallet
->mapWallet
.count(outpoint
.hash
)) continue;
581 int nDepth
= wallet
->mapWallet
[outpoint
.hash
].GetDepthInMainChain();
582 if (nDepth
< 0) continue;
583 COutput
out(&wallet
->mapWallet
[outpoint
.hash
], 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(CBitcoinAddress(group
.first
).ToString())];
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
= CBitcoinAddress(sAddress
).Get();
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 !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