2018-01-02 18:12:05 +01:00
// Copyright (c) 2011-2017 The Bitcoin Core developers
2014-12-13 05:09:33 +01:00
// Distributed under the MIT software license, see the accompanying
2013-11-04 16:20:43 +01:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-11-10 01:57:53 +01:00
# 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>
2017-04-18 00:56:44 +02:00
# include <interface/handler.h>
# include <interface/node.h>
2017-09-20 03:12:25 +02:00
# include <key_io.h>
2017-11-10 01:57:53 +01:00
# 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
2011-06-30 18:05:29 +02:00
2013-04-13 07:13:08 +02:00
# include <stdint.h>
# include <QDebug>
2017-02-03 22:04:39 +01:00
# include <QMessageBox>
2011-07-16 19:01:05 +02:00
# include <QSet>
2012-07-05 17:43:28 +02:00
# include <QTimer>
2011-06-30 18:05:29 +02:00
2015-07-05 14:17:46 +02:00
2017-04-18 00:56:44 +02:00
WalletModel : : WalletModel ( std : : unique_ptr < interface : : Wallet > wallet , interface : : Node & node , const PlatformStyle * platformStyle , CWallet * _wallet , OptionsModel * _optionsModel , QObject * parent ) :
QObject ( parent ) , m_wallet ( std : : move ( wallet ) ) , m_node ( node ) , cwallet ( _wallet ) , optionsModel ( _optionsModel ) , addressTableModel ( 0 ) ,
2011-07-17 14:06:43 +02:00
transactionTableModel ( 0 ) ,
2013-11-05 18:03:05 +01:00
recentRequestsTableModel ( 0 ) ,
2012-07-05 17:43:28 +02:00
cachedEncryptionStatus ( Unencrypted ) ,
cachedNumBlocks ( 0 )
2011-06-30 18:05:29 +02:00
{
2017-04-18 00:56:44 +02:00
fHaveWatchOnly = m_wallet - > haveWatchOnly ( ) ;
2014-08-17 02:34:42 +02:00
fForceCheckBalanceChanged = false ;
2014-07-13 10:19:56 +02:00
2017-04-18 19:01:23 +02:00
addressTableModel = new AddressTableModel ( this ) ;
2017-04-18 00:56:44 +02:00
transactionTableModel = new TransactionTableModel ( platformStyle , cwallet , this ) ;
recentRequestsTableModel = new RecentRequestsTableModel ( cwallet , this ) ;
2012-05-06 19:40:58 +02:00
2012-07-10 15:19:57 +02:00
// This timer will be fired repeatedly to update the balance
2012-07-05 17:43:28 +02:00
pollTimer = new QTimer ( this ) ;
connect ( pollTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( pollBalanceChanged ( ) ) ) ;
2012-07-10 15:19:57 +02:00
pollTimer - > start ( MODEL_UPDATE_DELAY ) ;
2012-07-05 17:43:28 +02:00
2012-05-06 19:40:58 +02:00
subscribeToCoreSignals ( ) ;
}
WalletModel : : ~ WalletModel ( )
{
unsubscribeFromCoreSignals ( ) ;
2011-06-30 18:05:29 +02:00
}
2012-05-05 16:07:14 +02:00
void WalletModel : : updateStatus ( )
2011-06-30 18:05:29 +02:00
{
2012-05-05 16:07:14 +02:00
EncryptionStatus newEncryptionStatus = getEncryptionStatus ( ) ;
2016-10-24 09:21:51 +02:00
if ( cachedEncryptionStatus ! = newEncryptionStatus ) {
Q_EMIT encryptionStatusChanged ( ) ;
}
2012-05-05 16:07:14 +02:00
}
2012-07-05 17:43:28 +02:00
void WalletModel : : pollBalanceChanged ( )
2012-05-05 16:07:14 +02:00
{
2017-04-18 00:56:44 +02:00
// 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.
interface : : WalletBalances new_balances ;
int numBlocks = - 1 ;
if ( ! m_wallet - > tryGetBalances ( new_balances , numBlocks ) ) {
2014-04-23 08:40:48 +02:00
return ;
2017-04-18 00:56:44 +02:00
}
2014-04-23 08:40:48 +02:00
2017-04-18 00:56:44 +02:00
if ( fForceCheckBalanceChanged | | m_node . getNumBlocks ( ) ! = cachedNumBlocks )
2012-07-10 15:19:57 +02:00
{
2014-08-17 02:34:42 +02:00
fForceCheckBalanceChanged = false ;
2014-04-23 08:40:48 +02:00
// Balance and number of transactions might have changed
2017-04-18 00:56:44 +02:00
cachedNumBlocks = m_node . getNumBlocks ( ) ;
2014-04-23 08:40:48 +02:00
2017-04-18 00:56:44 +02:00
checkBalanceChanged ( new_balances ) ;
2014-04-15 17:38:25 +02:00
if ( transactionTableModel )
transactionTableModel - > updateConfirmations ( ) ;
2012-07-05 17:43:28 +02:00
}
}
2017-04-18 00:56:44 +02:00
void WalletModel : : checkBalanceChanged ( const interface : : WalletBalances & new_balances )
2012-07-05 17:43:28 +02:00
{
2017-04-18 00:56:44 +02:00
if ( new_balances . balanceChanged ( m_cached_balances ) ) {
m_cached_balances = new_balances ;
Q_EMIT balanceChanged ( new_balances . balance , new_balances . unconfirmed_balance , new_balances . immature_balance , new_balances . watch_only_balance , new_balances . unconfirmed_watch_only_balance , new_balances . immature_watch_only_balance ) ;
2012-07-05 17:43:28 +02:00
}
}
2012-02-14 12:08:00 +01:00
2014-10-28 19:52:21 +01:00
void WalletModel : : updateTransaction ( )
2012-07-05 17:43:28 +02:00
{
// Balance and number of transactions might have changed
2014-08-17 02:34:42 +02:00
fForceCheckBalanceChanged = true ;
2011-06-30 18:05:29 +02:00
}
2013-09-04 11:52:45 +02:00
void WalletModel : : updateAddressBook ( const QString & address , const QString & label ,
2013-08-29 16:19:43 +02:00
bool isMine , const QString & purpose , int status )
2012-03-24 18:48:18 +01:00
{
2012-05-05 16:07:14 +02:00
if ( addressTableModel )
2013-08-29 16:19:43 +02:00
addressTableModel - > updateEntry ( address , label , isMine , purpose , status ) ;
2012-03-24 18:48:18 +01:00
}
2014-07-26 21:05:11 +02:00
void WalletModel : : updateWatchOnlyFlag ( bool fHaveWatchonly )
{
fHaveWatchOnly = fHaveWatchonly ;
2015-07-14 13:59:05 +02:00
Q_EMIT notifyWatchonlyChanged ( fHaveWatchonly ) ;
2014-07-26 21:05:11 +02:00
}
2011-07-16 19:01:05 +02:00
bool WalletModel : : validateAddress ( const QString & address )
2011-06-30 18:05:29 +02:00
{
2017-08-23 03:02:33 +02:00
return IsValidDestinationString ( address . toStdString ( ) ) ;
2011-07-16 19:01:05 +02:00
}
2017-06-28 22:41:55 +02:00
WalletModel : : SendCoinsReturn WalletModel : : prepareTransaction ( WalletModelTransaction & transaction , const CCoinControl & coinControl )
2011-07-16 19:01:05 +02:00
{
2014-04-23 00:46:19 +02:00
CAmount total = 0 ;
2014-07-23 14:34:36 +02:00
bool fSubtractFeeFromAmount = false ;
2013-08-30 20:04:48 +02:00
QList < SendCoinsRecipient > recipients = transaction . getRecipients ( ) ;
2014-07-23 14:34:36 +02:00
std : : vector < CRecipient > vecSend ;
2011-07-16 19:01:05 +02:00
if ( recipients . empty ( ) )
2011-06-30 18:05:29 +02:00
{
2011-07-16 19:01:05 +02:00
return OK ;
2011-06-30 18:05:29 +02:00
}
2013-07-22 08:50:39 +02:00
QSet < QString > setAddress ; // Used to detect duplicates
int nAddresses = 0 ;
2011-07-16 19:01:05 +02:00
// Pre-check input data for validity
2017-06-02 03:25:02 +02:00
for ( const SendCoinsRecipient & rcp : recipients )
2011-06-30 18:05:29 +02:00
{
2014-07-23 14:34:36 +02:00
if ( rcp . fSubtractFeeFromAmount )
fSubtractFeeFromAmount = true ;
2013-07-22 08:50:39 +02:00
if ( rcp . paymentRequest . IsInitialized ( ) )
2013-09-28 19:29:44 +02:00
{ // PaymentRequest...
2014-04-23 00:46:19 +02:00
CAmount subtotal = 0 ;
2013-07-22 08:50:39 +02:00
const payments : : PaymentDetails & details = rcp . paymentRequest . getDetails ( ) ;
for ( int i = 0 ; i < details . outputs_size ( ) ; i + + )
{
const payments : : Output & out = details . outputs ( i ) ;
if ( out . amount ( ) < = 0 ) continue ;
subtotal + = out . amount ( ) ;
const unsigned char * scriptStr = ( const unsigned char * ) out . script ( ) . data ( ) ;
CScript scriptPubKey ( scriptStr , scriptStr + out . script ( ) . size ( ) ) ;
2014-07-23 14:34:36 +02:00
CAmount nAmount = out . amount ( ) ;
CRecipient recipient = { scriptPubKey , nAmount , rcp . fSubtractFeeFromAmount } ;
vecSend . push_back ( recipient ) ;
2013-07-22 08:50:39 +02:00
}
if ( subtotal < = 0 )
{
return InvalidAmount ;
}
total + = subtotal ;
2011-07-16 19:01:05 +02:00
}
2013-07-22 08:50:39 +02:00
else
{ // User-entered bitcoin address / amount:
if ( ! validateAddress ( rcp . address ) )
{
return InvalidAddress ;
}
if ( rcp . amount < = 0 )
{
return InvalidAmount ;
}
setAddress . insert ( rcp . address ) ;
+ + nAddresses ;
2011-07-16 19:01:05 +02:00
2017-08-23 03:02:33 +02:00
CScript scriptPubKey = GetScriptForDestination ( DecodeDestination ( rcp . address . toStdString ( ) ) ) ;
2014-07-23 14:34:36 +02:00
CRecipient recipient = { scriptPubKey , rcp . amount , rcp . fSubtractFeeFromAmount } ;
vecSend . push_back ( recipient ) ;
2013-07-22 08:50:39 +02:00
total + = rcp . amount ;
2011-07-16 19:01:05 +02:00
}
2011-06-30 18:05:29 +02:00
}
2013-07-22 08:50:39 +02:00
if ( setAddress . size ( ) ! = nAddresses )
2011-07-16 19:01:05 +02:00
{
return DuplicateAddress ;
}
2017-04-18 00:56:44 +02:00
CAmount nBalance = m_wallet - > getAvailableBalance ( coinControl ) ;
2013-08-12 17:03:03 +02:00
if ( total > nBalance )
2011-06-30 18:05:29 +02:00
{
return AmountExceedsBalance ;
}
{
2014-04-23 00:46:19 +02:00
CAmount nFeeRequired = 0 ;
2014-07-23 14:34:36 +02:00
int nChangePosRet = - 1 ;
2013-04-25 23:31:22 +02:00
std : : string strFailReason ;
2013-08-30 20:04:48 +02:00
2017-04-18 00:56:44 +02:00
auto & newTx = transaction . getWtx ( ) ;
newTx = m_wallet - > createTransaction ( vecSend , coinControl , true /* sign */ , nChangePosRet , nFeeRequired , strFailReason ) ;
2013-08-30 20:04:48 +02:00
transaction . setTransactionFee ( nFeeRequired ) ;
2017-04-18 00:56:44 +02:00
if ( fSubtractFeeFromAmount & & newTx )
2014-07-23 14:34:36 +02:00
transaction . reassignAmounts ( nChangePosRet ) ;
2011-06-30 18:05:29 +02:00
2017-04-18 00:56:44 +02:00
if ( ! newTx )
2011-06-30 18:05:29 +02:00
{
2014-07-23 14:34:36 +02:00
if ( ! fSubtractFeeFromAmount & & ( total + nFeeRequired ) > nBalance )
2011-07-16 19:01:05 +02:00
{
2013-08-30 20:04:48 +02:00
return SendCoinsReturn ( AmountWithFeeExceedsBalance ) ;
2011-07-16 19:01:05 +02:00
}
2015-07-14 13:59:05 +02:00
Q_EMIT message ( tr ( " Send Coins " ) , QString : : fromStdString ( strFailReason ) ,
2013-04-25 23:31:22 +02:00
CClientUIInterface : : MSG_ERROR ) ;
2011-07-16 19:01:05 +02:00
return TransactionCreationFailed ;
2011-06-30 18:05:29 +02:00
}
2014-11-02 00:14:47 +01:00
2015-10-25 01:27:24 +02:00
// 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)
2017-04-18 00:56:44 +02:00
if ( nFeeRequired > m_node . getMaxTxFee ( ) )
2015-01-31 03:54:55 +01:00
return AbsurdFee ;
2013-08-30 20:04:48 +02:00
}
return SendCoinsReturn ( OK ) ;
}
WalletModel : : SendCoinsReturn WalletModel : : sendCoins ( WalletModelTransaction & transaction )
{
QByteArray transaction_array ; /* store serialized transaction */
{
2017-02-02 21:30:03 +01:00
std : : vector < std : : pair < std : : string , std : : string > > vOrderForm ;
2017-06-02 03:25:02 +02:00
for ( const SendCoinsRecipient & rcp : transaction . getRecipients ( ) )
2013-07-22 08:50:39 +02:00
{
if ( rcp . paymentRequest . IsInitialized ( ) )
{
2015-01-08 14:42:04 +01:00
// Make sure any payment requests involved are still valid.
if ( PaymentServer : : verifyExpired ( rcp . paymentRequest . getDetails ( ) ) ) {
return PaymentRequestExpired ;
}
// Store PaymentRequests in wtx.vOrderForm in wallet.
2013-07-22 08:50:39 +02:00
std : : string value ;
rcp . paymentRequest . SerializeToString ( & value ) ;
2017-02-02 21:30:03 +01:00
vOrderForm . emplace_back ( " PaymentRequest " , std : : move ( value ) ) ;
2013-07-22 08:50:39 +02:00
}
2014-01-21 23:39:29 +01:00
else if ( ! rcp . message . isEmpty ( ) ) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
2017-02-02 21:30:03 +01:00
vOrderForm . emplace_back ( " Message " , rcp . message . toStdString ( ) ) ;
2011-06-30 18:05:29 +02:00
}
2013-08-30 20:04:48 +02:00
2017-04-18 00:56:44 +02:00
auto & newTx = transaction . getWtx ( ) ;
std : : string rejectReason ;
if ( ! newTx - > commit ( { } /* mapValue */ , std : : move ( vOrderForm ) , { } /* fromAccount */ , rejectReason ) )
return SendCoinsReturn ( TransactionCommitFailed , QString : : fromStdString ( rejectReason ) ) ;
2013-07-22 08:50:39 +02:00
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
2017-04-18 00:56:44 +02:00
ssTx < < newTx - > get ( ) ;
2013-08-30 20:04:48 +02:00
transaction_array . append ( & ( ssTx [ 0 ] ) , ssTx . size ( ) ) ;
2011-06-30 18:05:29 +02:00
}
2017-06-20 00:57:31 +02:00
// Add addresses / update labels that we've sent to the address book,
2013-08-30 20:04:48 +02:00
// and emit coinsSent signal for each recipient
2017-06-02 03:25:02 +02:00
for ( const SendCoinsRecipient & rcp : transaction . getRecipients ( ) )
2011-06-30 18:05:29 +02:00
{
2013-10-24 16:02:39 +02:00
// Don't touch the address book when we have a payment request
if ( ! rcp . paymentRequest . IsInitialized ( ) )
2011-07-16 19:01:05 +02:00
{
2013-10-08 14:23:57 +02:00
std : : string strAddress = rcp . address . toStdString ( ) ;
2017-08-23 03:02:33 +02:00
CTxDestination dest = DecodeDestination ( strAddress ) ;
2013-10-08 14:23:57 +02:00
std : : string strLabel = rcp . label . toStdString ( ) ;
2012-05-03 14:52:15 +02:00
{
2013-10-08 14:23:57 +02:00
// Check if we have a new address or an updated label
2017-04-18 00:56:44 +02:00
std : : string name ;
if ( ! m_wallet - > getAddress ( dest , & name ) )
2013-10-08 14:23:57 +02:00
{
2017-04-18 00:56:44 +02:00
m_wallet - > setAddressBook ( dest , strLabel , " send " ) ;
2013-10-08 14:23:57 +02:00
}
2017-04-18 00:56:44 +02:00
else if ( name ! = strLabel )
2013-10-08 14:23:57 +02:00
{
2017-04-18 00:56:44 +02:00
m_wallet - > setAddressBook ( dest , strLabel , " " ) ; // "" means don't change purpose
2013-10-08 14:23:57 +02:00
}
2012-05-03 14:52:15 +02:00
}
2011-07-16 19:01:05 +02:00
}
2017-04-18 00:56:44 +02:00
Q_EMIT coinsSent ( cwallet , rcp , transaction_array ) ;
2011-06-30 18:05:29 +02:00
}
2017-04-18 00:56:44 +02:00
checkBalanceChanged ( m_wallet - > getBalances ( ) ) ; // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
2011-07-30 19:28:41 +02:00
2013-08-30 20:04:48 +02:00
return SendCoinsReturn ( OK ) ;
2011-06-30 18:05:29 +02:00
}
OptionsModel * WalletModel : : getOptionsModel ( )
{
return optionsModel ;
}
AddressTableModel * WalletModel : : getAddressTableModel ( )
{
return addressTableModel ;
}
TransactionTableModel * WalletModel : : getTransactionTableModel ( )
{
return transactionTableModel ;
}
2011-07-02 13:45:59 +02:00
2013-11-05 18:03:05 +01:00
RecentRequestsTableModel * WalletModel : : getRecentRequestsTableModel ( )
{
return recentRequestsTableModel ;
}
2011-08-23 20:08:42 +02:00
WalletModel : : EncryptionStatus WalletModel : : getEncryptionStatus ( ) const
{
2017-04-18 00:56:44 +02:00
if ( ! m_wallet - > isCrypted ( ) )
2011-08-23 20:08:42 +02:00
{
return Unencrypted ;
}
2017-04-18 00:56:44 +02:00
else if ( m_wallet - > isLocked ( ) )
2011-08-23 20:08:42 +02:00
{
return Locked ;
}
else
{
return Unlocked ;
}
}
2011-08-24 22:07:26 +02:00
2011-11-26 07:02:04 +01:00
bool WalletModel : : setWalletEncrypted ( bool encrypted , const SecureString & passphrase )
2011-08-24 22:07:26 +02:00
{
if ( encrypted )
{
// Encrypt
2017-04-18 00:56:44 +02:00
return m_wallet - > encryptWallet ( passphrase ) ;
2011-08-24 22:07:26 +02:00
}
else
{
// Decrypt -- TODO; not supported yet
return false ;
}
}
2011-11-26 07:02:04 +01:00
bool WalletModel : : setWalletLocked ( bool locked , const SecureString & passPhrase )
2011-08-24 22:07:26 +02:00
{
if ( locked )
{
// Lock
2017-04-18 00:56:44 +02:00
return m_wallet - > lock ( ) ;
2011-08-24 22:07:26 +02:00
}
else
{
// Unlock
2017-04-18 00:56:44 +02:00
return m_wallet - > unlock ( passPhrase ) ;
2011-08-24 22:07:26 +02:00
}
}
2011-11-26 07:02:04 +01:00
bool WalletModel : : changePassphrase ( const SecureString & oldPass , const SecureString & newPass )
2011-08-24 22:07:26 +02:00
{
2017-04-18 00:56:44 +02:00
m_wallet - > lock ( ) ; // Make sure wallet is locked before attempting pass change
return m_wallet - > changeWalletPassphrase ( oldPass , newPass ) ;
2012-02-14 13:14:43 +01:00
}
2012-05-06 19:40:58 +02:00
// Handlers for core signals
2017-04-18 00:56:44 +02:00
static void NotifyKeyStoreStatusChanged ( WalletModel * walletmodel )
2012-05-06 19:40:58 +02:00
{
2013-09-04 11:52:45 +02:00
qDebug ( ) < < " NotifyKeyStoreStatusChanged " ;
2012-05-06 19:40:58 +02:00
QMetaObject : : invokeMethod ( walletmodel , " updateStatus " , Qt : : QueuedConnection ) ;
}
2017-04-18 00:56:44 +02:00
static void NotifyAddressBookChanged ( WalletModel * walletmodel ,
2013-08-29 16:19:43 +02:00
const CTxDestination & address , const std : : string & label , bool isMine ,
const std : : string & purpose , ChangeType status )
2012-05-06 19:40:58 +02:00
{
2017-08-23 03:02:33 +02:00
QString strAddress = QString : : fromStdString ( EncodeDestination ( address ) ) ;
2013-09-04 11:52:45 +02:00
QString strLabel = QString : : fromStdString ( label ) ;
QString strPurpose = QString : : fromStdString ( purpose ) ;
2015-01-08 11:44:25 +01:00
qDebug ( ) < < " NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine= " + QString : : number ( isMine ) + " purpose= " + strPurpose + " status= " + QString : : number ( status ) ;
2012-05-06 19:40:58 +02:00
QMetaObject : : invokeMethod ( walletmodel , " updateAddressBook " , Qt : : QueuedConnection ,
2013-09-04 11:52:45 +02:00
Q_ARG ( QString , strAddress ) ,
Q_ARG ( QString , strLabel ) ,
2012-05-06 22:41:35 +02:00
Q_ARG ( bool , isMine ) ,
2013-09-04 11:52:45 +02:00
Q_ARG ( QString , strPurpose ) ,
2012-05-06 19:40:58 +02:00
Q_ARG ( int , status ) ) ;
}
2017-04-18 00:56:44 +02:00
static void NotifyTransactionChanged ( WalletModel * walletmodel , const uint256 & hash , ChangeType status )
2012-05-06 19:40:58 +02:00
{
2014-10-28 19:52:21 +01:00
Q_UNUSED ( hash ) ;
Q_UNUSED ( status ) ;
QMetaObject : : invokeMethod ( walletmodel , " updateTransaction " , Qt : : QueuedConnection ) ;
2012-05-06 19:40:58 +02:00
}
2014-03-19 00:26:14 +01:00
static void ShowProgress ( WalletModel * walletmodel , const std : : string & title , int nProgress )
{
2014-08-17 02:34:42 +02:00
// emits signal "showProgress"
QMetaObject : : invokeMethod ( walletmodel , " showProgress " , Qt : : QueuedConnection ,
Q_ARG ( QString , QString : : fromStdString ( title ) ) ,
Q_ARG ( int , nProgress ) ) ;
2014-03-19 00:26:14 +01:00
}
2014-07-26 21:05:11 +02:00
static void NotifyWatchonlyChanged ( WalletModel * walletmodel , bool fHaveWatchonly )
{
QMetaObject : : invokeMethod ( walletmodel , " updateWatchOnlyFlag " , Qt : : QueuedConnection ,
Q_ARG ( bool , fHaveWatchonly ) ) ;
}
2012-05-06 19:40:58 +02:00
void WalletModel : : subscribeToCoreSignals ( )
{
// Connect signals to wallet
2017-04-18 00:56:44 +02:00
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 ) ) ;
2012-05-06 19:40:58 +02:00
}
void WalletModel : : unsubscribeFromCoreSignals ( )
{
// Disconnect signals from wallet
2017-04-18 00:56:44 +02:00
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 ( ) ;
2012-05-06 19:40:58 +02:00
}
2011-08-24 22:07:26 +02:00
// WalletModel::UnlockContext implementation
WalletModel : : UnlockContext WalletModel : : requestUnlock ( )
{
bool was_locked = getEncryptionStatus ( ) = = Locked ;
if ( was_locked )
{
// Request UI to unlock wallet
2015-07-14 13:59:05 +02:00
Q_EMIT requireUnlock ( ) ;
2011-08-24 22:07:26 +02:00
}
// If wallet is still locked, unlock was failed or cancelled, mark context as invalid
bool valid = getEncryptionStatus ( ) ! = Locked ;
return UnlockContext ( this , valid , was_locked ) ;
}
2016-09-09 13:43:29 +02:00
WalletModel : : UnlockContext : : UnlockContext ( WalletModel * _wallet , bool _valid , bool _relock ) :
wallet ( _wallet ) ,
valid ( _valid ) ,
relock ( _relock )
2011-08-24 22:07:26 +02:00
{
}
WalletModel : : UnlockContext : : ~ UnlockContext ( )
{
if ( valid & & relock )
{
wallet - > setWalletLocked ( true ) ;
}
}
void WalletModel : : UnlockContext : : CopyFrom ( const UnlockContext & rhs )
{
// Transfer context; old object no longer relocks wallet
* this = rhs ;
rhs . relock = false ;
}
2013-08-12 17:03:03 +02:00
2014-01-14 05:05:43 +01:00
void WalletModel : : loadReceiveRequests ( std : : vector < std : : string > & vReceiveRequests )
{
2017-04-18 00:56:44 +02:00
vReceiveRequests = m_wallet - > getDestValues ( " rr " ) ; // receive request
2014-01-14 05:05:43 +01:00
}
bool WalletModel : : saveReceiveRequest ( const std : : string & sAddress , const int64_t nId , const std : : string & sRequest )
{
2017-08-23 03:02:33 +02:00
CTxDestination dest = DecodeDestination ( sAddress ) ;
2014-01-14 05:05:43 +01:00
std : : stringstream ss ;
ss < < nId ;
std : : string key = " rr " + ss . str ( ) ; // "rr" prefix = "receive request" in destdata
if ( sRequest . empty ( ) )
2017-04-18 00:56:44 +02:00
return m_wallet - > eraseDestData ( dest , key ) ;
2014-01-14 05:05:43 +01:00
else
2017-04-18 00:56:44 +02:00
return m_wallet - > addDestData ( dest , key , sRequest ) ;
2017-02-03 22:04:39 +01:00
}
bool WalletModel : : bumpFee ( uint256 hash )
{
2017-06-15 16:34:17 +02:00
CCoinControl coin_control ;
coin_control . signalRbf = true ;
std : : vector < std : : string > errors ;
CAmount old_fee ;
CAmount new_fee ;
CMutableTransaction mtx ;
2017-04-18 00:56:44 +02:00
if ( ! m_wallet - > createBumpTransaction ( hash , coin_control , 0 /* totalFee */ , errors , old_fee , new_fee , mtx ) ) {
2017-02-03 22:04:39 +01:00
QMessageBox : : critical ( 0 , tr ( " Fee bump error " ) , tr ( " Increasing transaction fee failed " ) + " <br />( " +
2017-06-15 16:34:17 +02:00
( errors . size ( ) ? QString : : fromStdString ( errors [ 0 ] ) : " " ) + " ) " ) ;
2017-02-03 22:04:39 +01:00
return false ;
}
// allow a user based fee verification
2017-04-26 09:55:54 +02:00
QString questionString = tr ( " Do you want to increase the fee? " ) ;
questionString . append ( " <br /> " ) ;
questionString . append ( " <table style= \" text-align: left; \" > " ) ;
questionString . append ( " <tr><td> " ) ;
questionString . append ( tr ( " Current fee: " ) ) ;
questionString . append ( " </td><td> " ) ;
2017-06-15 16:34:17 +02:00
questionString . append ( BitcoinUnits : : formatHtmlWithUnit ( getOptionsModel ( ) - > getDisplayUnit ( ) , old_fee ) ) ;
2017-04-26 09:55:54 +02:00
questionString . append ( " </td></tr><tr><td> " ) ;
questionString . append ( tr ( " Increase: " ) ) ;
questionString . append ( " </td><td> " ) ;
2017-06-15 16:34:17 +02:00
questionString . append ( BitcoinUnits : : formatHtmlWithUnit ( getOptionsModel ( ) - > getDisplayUnit ( ) , new_fee - old_fee ) ) ;
2017-04-26 09:55:54 +02:00
questionString . append ( " </td></tr><tr><td> " ) ;
questionString . append ( tr ( " New fee: " ) ) ;
questionString . append ( " </td><td> " ) ;
2017-06-15 16:34:17 +02:00
questionString . append ( BitcoinUnits : : formatHtmlWithUnit ( getOptionsModel ( ) - > getDisplayUnit ( ) , new_fee ) ) ;
2017-04-26 09:55:54 +02:00
questionString . append ( " </td></tr></table> " ) ;
2017-02-03 22:04:39 +01:00
SendConfirmationDialog confirmationDialog ( tr ( " Confirm fee bump " ) , questionString ) ;
confirmationDialog . exec ( ) ;
2017-06-01 16:13:35 +02:00
QMessageBox : : StandardButton retval = static_cast < QMessageBox : : StandardButton > ( confirmationDialog . result ( ) ) ;
2017-02-03 22:04:39 +01:00
2018-03-18 15:26:45 +01:00
// cancel sign&broadcast if user doesn't want to bump the fee
2017-02-03 22:04:39 +01:00
if ( retval ! = QMessageBox : : Yes ) {
return false ;
}
WalletModel : : UnlockContext ctx ( requestUnlock ( ) ) ;
if ( ! ctx . isValid ( ) )
{
return false ;
}
// sign bumped transaction
2017-04-18 00:56:44 +02:00
if ( ! m_wallet - > signBumpTransaction ( mtx ) ) {
2017-02-03 22:04:39 +01:00
QMessageBox : : critical ( 0 , tr ( " Fee bump error " ) , tr ( " Can't sign transaction. " ) ) ;
return false ;
}
// commit the bumped transaction
2017-06-15 16:34:17 +02:00
uint256 txid ;
2017-04-18 00:56:44 +02:00
if ( ! m_wallet - > commitBumpTransaction ( hash , std : : move ( mtx ) , errors , txid ) ) {
2017-02-03 22:04:39 +01:00
QMessageBox : : critical ( 0 , tr ( " Fee bump error " ) , tr ( " Could not commit transaction " ) + " <br />( " +
2017-06-15 16:34:17 +02:00
QString : : fromStdString ( errors [ 0 ] ) + " ) " ) ;
2017-02-03 22:04:39 +01:00
return false ;
}
return true ;
}
2016-09-21 12:37:00 +02:00
bool WalletModel : : isWalletEnabled ( )
{
2017-08-01 21:17:40 +02:00
return ! gArgs . GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) ;
2016-09-21 12:37:00 +02:00
}
2018-03-06 05:26:40 +01:00
QString WalletModel : : getWalletName ( ) const
{
2017-04-18 00:56:44 +02:00
return QString : : fromStdString ( m_wallet - > getWalletName ( ) ) ;
2018-03-06 05:26:40 +01:00
}
bool WalletModel : : isMultiwallet ( )
{
2017-04-18 00:56:44 +02:00
return m_node . getWallets ( ) . size ( ) > 1 ;
2018-03-06 05:26:40 +01:00
}