2015-12-13 14:51:43 +01:00
// Copyright (c) 2011-2015 The Bitcoin Core developers
2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash 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.
2011-06-30 18:05:29 +02:00
# include "walletmodel.h"
2013-04-13 07:13:08 +02:00
2011-06-30 18:05:29 +02:00
# include "addresstablemodel.h"
2016-10-28 13:49:04 +02:00
# include "consensus/validation.h"
2013-04-13 07:13:08 +02:00
# include "guiconstants.h"
2014-07-23 14:34:36 +02:00
# include "guiutil.h"
2015-01-08 14:42:04 +01:00
# include "paymentserver.h"
2013-11-05 18:03:05 +01:00
# include "recentrequeststablemodel.h"
2013-12-16 22:54:02 +01:00
# include "transactiontablemodel.h"
2011-06-30 18:05:29 +02:00
2013-04-13 07:13:08 +02:00
# include "base58.h"
# include "keystore.h"
2017-08-09 02:19:06 +02:00
# include "validation.h"
# include "net.h" // for g_connman
2013-04-13 07:13:08 +02:00
# include "sync.h"
2012-04-16 14:56:45 +02:00
# include "ui_interface.h"
2017-08-09 02:19:06 +02:00
# include "util.h" // for GetBoolArg
2015-02-03 21:09:47 +01:00
# include "wallet/wallet.h"
# include "wallet/walletdb.h" // for BackupWallet
2011-06-30 18:05:29 +02:00
2016-12-20 14:27:59 +01:00
# include "instantx.h"
# include "spork.h"
2017-05-05 13:26:27 +02:00
# include "privatesend-client.h"
2016-12-20 14:27:59 +01:00
2013-04-13 07:13:08 +02:00
# include <stdint.h>
# include <QDebug>
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
# include <boost/foreach.hpp>
2014-06-16 16:30:38 +02:00
2016-09-23 12:44:09 +02:00
WalletModel : : WalletModel ( const PlatformStyle * platformStyle , CWallet * _wallet , OptionsModel * _optionsModel , QObject * parent ) :
QObject ( parent ) , wallet ( _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 ) ,
2017-02-09 06:29:00 +01:00
cachedBalance ( 0 ) ,
cachedUnconfirmedBalance ( 0 ) ,
cachedImmatureBalance ( 0 ) ,
cachedAnonymizedBalance ( 0 ) ,
cachedWatchOnlyBalance ( 0 ) ,
cachedWatchUnconfBalance ( 0 ) ,
cachedWatchImmatureBalance ( 0 ) ,
2012-07-05 17:43:28 +02:00
cachedEncryptionStatus ( Unencrypted ) ,
2017-02-09 06:29:00 +01:00
cachedNumBlocks ( 0 ) ,
cachedTxLocks ( 0 ) ,
cachedPrivateSendRounds ( 0 )
2011-06-30 18:05:29 +02:00
{
2014-07-26 21:05:11 +02:00
fHaveWatchOnly = wallet - > HaveWatchOnly ( ) ;
2015-02-10 14:24:05 +01:00
fForceCheckBalanceChanged = false ;
2011-06-30 18:05:29 +02:00
addressTableModel = new AddressTableModel ( wallet , this ) ;
2015-07-28 15:20:14 +02:00
transactionTableModel = new TransactionTableModel ( platformStyle , wallet , this ) ;
2013-11-05 18:03:05 +01:00
recentRequestsTableModel = new RecentRequestsTableModel ( wallet , 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
}
2014-04-23 00:46:19 +02:00
CAmount WalletModel : : getBalance ( const CCoinControl * coinControl ) const
2011-06-30 18:05:29 +02:00
{
2013-08-12 17:03:03 +02:00
if ( coinControl )
{
2014-04-23 00:46:19 +02:00
CAmount nBalance = 0 ;
2013-08-12 17:03:03 +02:00
std : : vector < COutput > vCoins ;
wallet - > AvailableCoins ( vCoins , true , coinControl ) ;
BOOST_FOREACH ( const COutput & out , vCoins )
2013-12-10 15:27:53 +01:00
if ( out . fSpendable )
2016-12-05 08:01:20 +01:00
nBalance + = out . tx - > tx - > vout [ out . i ] . nValue ;
2013-08-12 17:03:03 +02:00
return nBalance ;
}
2011-06-30 18:05:29 +02:00
return wallet - > GetBalance ( ) ;
}
2014-12-09 02:17:57 +01:00
2015-04-14 10:51:14 +02:00
CAmount WalletModel : : getAnonymizedBalance ( ) const
2014-12-09 02:17:57 +01:00
{
2015-02-11 00:50:35 +01:00
return wallet - > GetAnonymizedBalance ( ) ;
2014-12-09 02:17:57 +01:00
}
2014-04-23 00:46:19 +02:00
CAmount WalletModel : : getUnconfirmedBalance ( ) const
2011-07-11 20:42:10 +02:00
{
return wallet - > GetUnconfirmedBalance ( ) ;
}
2014-04-23 00:46:19 +02:00
CAmount WalletModel : : getImmatureBalance ( ) const
2012-02-14 12:08:00 +01:00
{
return wallet - > GetImmatureBalance ( ) ;
}
2014-07-26 21:05:11 +02:00
bool WalletModel : : haveWatchOnly ( ) const
2011-06-30 18:05:29 +02:00
{
2014-07-26 21:05:11 +02:00
return fHaveWatchOnly ;
}
2014-04-23 00:46:19 +02:00
CAmount WalletModel : : getWatchBalance ( ) const
2014-03-29 05:15:28 +01:00
{
return wallet - > GetWatchOnlyBalance ( ) ;
}
2014-04-23 00:46:19 +02:00
CAmount WalletModel : : getWatchUnconfirmedBalance ( ) const
2014-03-29 05:15:28 +01:00
{
return wallet - > GetUnconfirmedWatchOnlyBalance ( ) ;
}
2014-04-23 00:46:19 +02:00
CAmount WalletModel : : getWatchImmatureBalance ( ) const
2014-03-29 05:15:28 +01:00
{
return wallet - > GetImmatureWatchOnlyBalance ( ) ;
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 ( ) ;
if ( cachedEncryptionStatus ! = newEncryptionStatus )
2015-07-14 13:59:05 +02:00
Q_EMIT encryptionStatusChanged ( newEncryptionStatus ) ;
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
{
2014-04-23 08:40:48 +02:00
// 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 )
return ;
2017-05-05 13:26:27 +02:00
if ( fForceCheckBalanceChanged | | chainActive . Height ( ) ! = cachedNumBlocks | | privateSendClient . nPrivateSendRounds ! = cachedPrivateSendRounds | | cachedTxLocks ! = nCompleteTXLocks )
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
cachedNumBlocks = chainActive . Height ( ) ;
2017-05-05 13:26:27 +02:00
cachedPrivateSendRounds = privateSendClient . nPrivateSendRounds ;
2014-04-23 08:40:48 +02:00
2012-07-05 17:43:28 +02:00
checkBalanceChanged ( ) ;
2016-02-14 05:51:06 +01:00
if ( transactionTableModel )
2014-04-15 17:38:25 +02:00
transactionTableModel - > updateConfirmations ( ) ;
2012-07-05 17:43:28 +02:00
}
}
void WalletModel : : checkBalanceChanged ( )
{
2014-04-23 00:46:19 +02:00
CAmount newBalance = getBalance ( ) ;
CAmount newUnconfirmedBalance = getUnconfirmedBalance ( ) ;
CAmount newImmatureBalance = getImmatureBalance ( ) ;
2015-04-03 00:51:08 +02:00
CAmount newAnonymizedBalance = getAnonymizedBalance ( ) ;
2014-04-23 00:46:19 +02:00
CAmount newWatchOnlyBalance = 0 ;
CAmount newWatchUnconfBalance = 0 ;
CAmount newWatchImmatureBalance = 0 ;
2014-07-26 21:05:11 +02:00
if ( haveWatchOnly ( ) )
{
newWatchOnlyBalance = getWatchBalance ( ) ;
newWatchUnconfBalance = getWatchUnconfirmedBalance ( ) ;
newWatchImmatureBalance = getWatchImmatureBalance ( ) ;
}
2011-07-17 14:06:43 +02:00
2014-03-29 05:15:28 +01:00
if ( cachedBalance ! = newBalance | | cachedUnconfirmedBalance ! = newUnconfirmedBalance | | cachedImmatureBalance ! = newImmatureBalance | |
2015-04-03 00:51:08 +02:00
cachedAnonymizedBalance ! = newAnonymizedBalance | | cachedTxLocks ! = nCompleteTXLocks | |
2014-03-29 05:15:28 +01:00
cachedWatchOnlyBalance ! = newWatchOnlyBalance | | cachedWatchUnconfBalance ! = newWatchUnconfBalance | | cachedWatchImmatureBalance ! = newWatchImmatureBalance )
2012-07-10 15:19:57 +02:00
{
2012-07-05 17:43:28 +02:00
cachedBalance = newBalance ;
cachedUnconfirmedBalance = newUnconfirmedBalance ;
cachedImmatureBalance = newImmatureBalance ;
2014-12-09 02:17:57 +01:00
cachedAnonymizedBalance = newAnonymizedBalance ;
2015-02-02 16:04:09 +01:00
cachedTxLocks = nCompleteTXLocks ;
2014-03-29 05:15:28 +01:00
cachedWatchOnlyBalance = newWatchOnlyBalance ;
cachedWatchUnconfBalance = newWatchUnconfBalance ;
cachedWatchImmatureBalance = newWatchImmatureBalance ;
2016-02-02 16:28:56 +01:00
Q_EMIT balanceChanged ( newBalance , newUnconfirmedBalance , newImmatureBalance , newAnonymizedBalance ,
2014-03-29 05:15:28 +01:00
newWatchOnlyBalance , newWatchUnconfBalance , newWatchImmatureBalance ) ;
2012-07-05 17:43:28 +02:00
}
}
2012-02-14 12:08:00 +01:00
2015-02-10 14:24:05 +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
{
2011-07-26 15:38:31 +02:00
CBitcoinAddress addressParsed ( address . toStdString ( ) ) ;
return addressParsed . IsValid ( ) ;
2011-07-16 19:01:05 +02:00
}
2013-08-12 17:03:03 +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
}
2016-09-11 11:02:54 +02:00
// This should never really happen, yet another safety check, just in case.
if ( wallet - > IsLocked ( ) ) {
return TransactionCreationFailed ;
2014-12-09 02:17:57 +01: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
2015-07-14 13:59:05 +02:00
Q_FOREACH ( 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
2015-03-19 15:15:08 +01:00
{ // User-entered dash address / amount:
2013-07-22 08:50:39 +02:00
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
2014-09-11 19:15:29 +02:00
CScript scriptPubKey = GetScriptForDestination ( CBitcoinAddress ( rcp . address . toStdString ( ) ) . Get ( ) ) ;
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 ;
}
2014-04-23 00:46:19 +02:00
CAmount nBalance = getBalance ( coinControl ) ;
2013-08-12 17:03:03 +02:00
if ( total > nBalance )
2011-06-30 18:05:29 +02:00
{
return AmountExceedsBalance ;
}
{
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
2013-08-30 20:04:48 +02:00
transaction . newPossibleKeyChange ( wallet ) ;
2014-07-23 14:34:36 +02:00
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
CWalletTx * newTx = transaction . getTransaction ( ) ;
CReserveKey * keyChange = transaction . getPossibleKeyChange ( ) ;
2014-12-09 02:17:57 +01:00
2016-09-02 14:17:32 +02:00
if ( recipients [ 0 ] . fUseInstantSend & & total > sporkManager . GetSporkValue ( SPORK_5_INSTANTSEND_MAX_VALUE ) * COIN ) {
2016-09-01 16:55:25 +02:00
Q_EMIT message ( tr ( " Send Coins " ) , tr ( " InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH. " ) . arg ( sporkManager . GetSporkValue ( SPORK_5_INSTANTSEND_MAX_VALUE ) ) ,
2015-02-11 15:47:21 +01:00
CClientUIInterface : : MSG_ERROR ) ;
return TransactionCreationFailed ;
}
2016-09-02 14:17:32 +02:00
bool fCreated = wallet - > CreateTransaction ( vecSend , * newTx , * keyChange , nFeeRequired , nChangePosRet , strFailReason , coinControl , true , recipients [ 0 ] . inputType , recipients [ 0 ] . fUseInstantSend ) ;
2013-08-30 20:04:48 +02:00
transaction . setTransactionFee ( nFeeRequired ) ;
2014-07-23 14:34:36 +02:00
if ( fSubtractFeeFromAmount & & fCreated )
transaction . reassignAmounts ( nChangePosRet ) ;
2011-06-30 18:05:29 +02:00
2017-01-29 09:22:14 +01:00
if ( recipients [ 0 ] . fUseInstantSend ) {
2016-12-05 08:01:20 +01:00
if ( newTx - > tx - > GetValueOut ( ) > sporkManager . GetSporkValue ( SPORK_5_INSTANTSEND_MAX_VALUE ) * COIN ) {
2017-01-29 09:22:14 +01:00
Q_EMIT message ( tr ( " Send Coins " ) , tr ( " InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH. " ) . arg ( sporkManager . GetSporkValue ( SPORK_5_INSTANTSEND_MAX_VALUE ) ) ,
CClientUIInterface : : MSG_ERROR ) ;
return TransactionCreationFailed ;
}
2016-12-05 08:01:20 +01:00
if ( newTx - > tx - > vin . size ( ) > CTxLockRequest : : WARN_MANY_INPUTS ) {
2017-02-02 23:38:33 +01:00
Q_EMIT message ( tr ( " Send Coins " ) , tr ( " Used way too many inputs (>%1) for this InstantSend transaction, fees could be huge. " ) . arg ( CTxLockRequest : : WARN_MANY_INPUTS ) ,
CClientUIInterface : : MSG_WARNING ) ;
2017-01-29 09:22:14 +01:00
}
2015-09-11 20:19:14 +02:00
}
2011-07-16 19:01:05 +02:00
if ( ! fCreated )
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)
if ( nFeeRequired > maxTxFee )
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 */
{
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
CWalletTx * newTx = transaction . getTransaction ( ) ;
2015-02-16 00:42:08 +01:00
QList < SendCoinsRecipient > recipients = transaction . getRecipients ( ) ;
2013-08-30 20:04:48 +02:00
2016-02-02 16:28:56 +01:00
Q_FOREACH ( const SendCoinsRecipient & rcp , recipients )
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 key ( " PaymentRequest " ) ;
std : : string value ;
rcp . paymentRequest . SerializeToString ( & value ) ;
2013-08-30 20:04:48 +02:00
newTx - > vOrderForm . push_back ( make_pair ( key , value ) ) ;
2013-07-22 08:50:39 +02:00
}
2015-03-19 15:15:08 +01:00
else if ( ! rcp . message . isEmpty ( ) ) // Message from normal dash:URI (dash:XyZ...?message=example)
2014-12-09 02:17:57 +01:00
{
2014-01-21 23:39:29 +01:00
newTx - > vOrderForm . push_back ( make_pair ( " Message " , rcp . message . toStdString ( ) ) ) ;
2014-12-09 02:17:57 +01:00
}
2011-06-30 18:05:29 +02:00
}
2013-08-30 20:04:48 +02:00
CReserveKey * keyChange = transaction . getPossibleKeyChange ( ) ;
2016-10-28 13:49:04 +02:00
CValidationState state ;
if ( ! wallet - > CommitTransaction ( * newTx , * keyChange , g_connman . get ( ) , state , recipients [ 0 ] . fUseInstantSend ? NetMsgType : : TXLOCKREQUEST : NetMsgType : : TX ) )
2016-11-01 08:33:14 +01:00
return SendCoinsReturn ( TransactionCommitFailed , QString : : fromStdString ( state . GetRejectReason ( ) ) ) ;
2013-07-22 08:50:39 +02:00
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
2016-12-06 15:41:15 +01:00
ssTx < < * newTx - > tx ;
2013-08-30 20:04:48 +02:00
transaction_array . append ( & ( ssTx [ 0 ] ) , ssTx . size ( ) ) ;
2011-06-30 18:05:29 +02:00
}
2013-07-22 08:50:39 +02:00
// Add addresses / update labels that we've sent to to the address book,
2013-08-30 20:04:48 +02:00
// and emit coinsSent signal for each recipient
2015-07-14 13:59:05 +02:00
Q_FOREACH ( 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 ( ) ;
CTxDestination dest = CBitcoinAddress ( strAddress ) . Get ( ) ;
std : : string strLabel = rcp . label . toStdString ( ) ;
2012-05-03 14:52:15 +02:00
{
2013-10-08 14:23:57 +02:00
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 ( ) )
{
wallet - > SetAddressBook ( dest , strLabel , " send " ) ;
}
else if ( mi - > second . name ! = strLabel )
{
wallet - > SetAddressBook ( dest , strLabel , " " ) ; // "" means don't change purpose
}
2012-05-03 14:52:15 +02:00
}
2011-07-16 19:01:05 +02:00
}
2015-07-14 13:59:05 +02:00
Q_EMIT coinsSent ( wallet , rcp , transaction_array ) ;
2011-06-30 18:05:29 +02:00
}
2014-08-17 02:34:42 +02:00
checkBalanceChanged ( ) ; // 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
{
if ( ! wallet - > IsCrypted ( ) )
{
return Unencrypted ;
}
2016-09-11 11:02:54 +02:00
else if ( wallet - > IsLocked ( true ) )
2011-08-23 20:08:42 +02:00
{
return Locked ;
}
2016-09-11 11:02:54 +02:00
else if ( wallet - > IsLocked ( ) )
2014-12-09 02:17:57 +01:00
{
2016-09-11 11:02:54 +02:00
return UnlockedForMixingOnly ;
2014-12-09 02:17:57 +01:00
}
2011-08-23 20:08:42 +02:00
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
return wallet - > EncryptWallet ( passphrase ) ;
}
else
{
// Decrypt -- TODO; not supported yet
return false ;
}
}
2016-09-11 11:02:54 +02:00
bool WalletModel : : setWalletLocked ( bool locked , const SecureString & passPhrase , bool fMixing )
2011-08-24 22:07:26 +02:00
{
if ( locked )
{
// Lock
2016-09-11 11:02:54 +02:00
return wallet - > Lock ( fMixing ) ;
2011-08-24 22:07:26 +02:00
}
else
{
// Unlock
2016-09-11 11:02:54 +02:00
return wallet - > Unlock ( passPhrase , fMixing ) ;
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
{
bool retval ;
{
2012-04-06 18:39:12 +02:00
LOCK ( wallet - > cs_wallet ) ;
2011-08-24 22:07:26 +02:00
wallet - > Lock ( ) ; // Make sure wallet is locked before attempting pass change
retval = wallet - > ChangeWalletPassphrase ( oldPass , newPass ) ;
}
return retval ;
}
2012-02-14 13:14:43 +01:00
bool WalletModel : : backupWallet ( const QString & filename )
{
2016-05-25 18:06:23 +02:00
return wallet - > BackupWallet ( filename . toLocal8Bit ( ) . data ( ) ) ;
2012-02-14 13:14:43 +01:00
}
2012-05-06 19:40:58 +02:00
// Handlers for core signals
static void NotifyKeyStoreStatusChanged ( WalletModel * walletmodel , CCryptoKeyStore * wallet )
{
2013-09-04 11:52:45 +02:00
qDebug ( ) < < " NotifyKeyStoreStatusChanged " ;
2012-05-06 19:40:58 +02:00
QMetaObject : : invokeMethod ( walletmodel , " updateStatus " , Qt : : QueuedConnection ) ;
}
2013-08-29 16:19:43 +02:00
static void NotifyAddressBookChanged ( WalletModel * walletmodel , CWallet * wallet ,
const CTxDestination & address , const std : : string & label , bool isMine ,
const std : : string & purpose , ChangeType status )
2012-05-06 19:40:58 +02:00
{
2013-09-04 11:52:45 +02:00
QString strAddress = QString : : fromStdString ( CBitcoinAddress ( address ) . ToString ( ) ) ;
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 ) ) ;
}
static void NotifyTransactionChanged ( WalletModel * walletmodel , CWallet * wallet , const uint256 & hash , ChangeType status )
{
2016-02-14 05:51:06 +01:00
Q_UNUSED ( wallet ) ;
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 )
{
// emits signal "showProgress"
QMetaObject : : invokeMethod ( walletmodel , " showProgress " , Qt : : QueuedConnection ,
Q_ARG ( QString , QString : : fromStdString ( title ) ) ,
Q_ARG ( int , nProgress ) ) ;
}
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
wallet - > NotifyStatusChanged . connect ( boost : : bind ( & NotifyKeyStoreStatusChanged , this , _1 ) ) ;
2013-08-29 16:19:43 +02:00
wallet - > NotifyAddressBookChanged . connect ( boost : : bind ( NotifyAddressBookChanged , this , _1 , _2 , _3 , _4 , _5 , _6 ) ) ;
2012-05-06 19:40:58 +02:00
wallet - > NotifyTransactionChanged . connect ( boost : : bind ( NotifyTransactionChanged , this , _1 , _2 , _3 ) ) ;
2014-03-19 00:26:14 +01:00
wallet - > ShowProgress . connect ( boost : : bind ( ShowProgress , this , _1 , _2 ) ) ;
2014-07-26 21:05:11 +02:00
wallet - > NotifyWatchonlyChanged . connect ( boost : : bind ( NotifyWatchonlyChanged , this , _1 ) ) ;
2012-05-06 19:40:58 +02:00
}
void WalletModel : : unsubscribeFromCoreSignals ( )
{
// Disconnect signals from wallet
wallet - > NotifyStatusChanged . disconnect ( boost : : bind ( & NotifyKeyStoreStatusChanged , this , _1 ) ) ;
2013-08-29 16:19:43 +02:00
wallet - > NotifyAddressBookChanged . disconnect ( boost : : bind ( NotifyAddressBookChanged , this , _1 , _2 , _3 , _4 , _5 , _6 ) ) ;
2012-05-06 19:40:58 +02:00
wallet - > NotifyTransactionChanged . disconnect ( boost : : bind ( NotifyTransactionChanged , this , _1 , _2 , _3 ) ) ;
2014-03-19 00:26:14 +01:00
wallet - > ShowProgress . disconnect ( boost : : bind ( ShowProgress , this , _1 , _2 ) ) ;
2014-07-26 21:05:11 +02:00
wallet - > NotifyWatchonlyChanged . disconnect ( boost : : bind ( NotifyWatchonlyChanged , this , _1 ) ) ;
2012-05-06 19:40:58 +02:00
}
2011-08-24 22:07:26 +02:00
// WalletModel::UnlockContext implementation
2016-09-11 11:02:54 +02:00
WalletModel : : UnlockContext WalletModel : : requestUnlock ( bool fForMixingOnly )
2011-08-24 22:07:26 +02:00
{
2016-09-11 11:02:54 +02:00
EncryptionStatus encStatusOld = getEncryptionStatus ( ) ;
2014-12-09 02:17:57 +01:00
2016-09-11 11:02:54 +02:00
// Wallet was completely locked
bool was_locked = ( encStatusOld = = Locked ) ;
// Wallet was unlocked for mixing
bool was_mixing = ( encStatusOld = = UnlockedForMixingOnly ) ;
// Wallet was unlocked for mixing and now user requested to fully unlock it
bool fMixingToFullRequested = ! fForMixingOnly & & was_mixing ;
2014-12-09 02:17:57 +01:00
2016-09-11 11:02:54 +02:00
if ( was_locked | | fMixingToFullRequested ) {
2011-08-24 22:07:26 +02:00
// Request UI to unlock wallet
2016-09-11 11:02:54 +02:00
Q_EMIT requireUnlock ( fForMixingOnly ) ;
2011-08-24 22:07:26 +02:00
}
2016-09-11 11:02:54 +02:00
EncryptionStatus encStatusNew = getEncryptionStatus ( ) ;
// Wallet was locked, user requested to unlock it for mixing and failed to do so
bool fMixingUnlockFailed = fForMixingOnly & & ! ( encStatusNew = = UnlockedForMixingOnly ) ;
// Wallet was unlocked for mixing, user requested to fully unlock it and failed
bool fMixingToFullFailed = fMixingToFullRequested & & ! ( encStatusNew = = Unlocked ) ;
2016-03-15 22:15:18 +01:00
// If wallet is still locked, unlock failed or was cancelled, mark context as invalid
2016-09-11 11:02:54 +02:00
bool fInvalid = ( encStatusNew = = Locked ) | | fMixingUnlockFailed | | fMixingToFullFailed ;
// Wallet was not locked in any way or user tried to unlock it for mixing only and succeeded, keep it unlocked
bool fKeepUnlocked = ! was_locked | | ( fForMixingOnly & & ! fMixingUnlockFailed ) ;
2011-08-24 22:07:26 +02:00
2016-09-11 11:02:54 +02:00
return UnlockContext ( this , ! fInvalid , ! fKeepUnlocked , was_mixing ) ;
2011-08-24 22:07:26 +02:00
}
2016-09-23 12:44:09 +02:00
WalletModel : : UnlockContext : : UnlockContext ( WalletModel * _wallet , bool _valid , bool _was_locked , bool _was_mixing ) :
wallet ( _wallet ) ,
valid ( _valid ) ,
was_locked ( _was_locked ) ,
was_mixing ( _was_mixing )
2011-08-24 22:07:26 +02:00
{
}
WalletModel : : UnlockContext : : ~ UnlockContext ( )
{
2016-09-11 11:02:54 +02:00
if ( valid & & ( was_locked | | was_mixing ) )
2011-08-24 22:07:26 +02:00
{
2016-09-11 11:02:54 +02:00
wallet - > setWalletLocked ( true , " " , was_mixing ) ;
2011-08-24 22:07:26 +02:00
}
}
void WalletModel : : UnlockContext : : CopyFrom ( const UnlockContext & rhs )
{
// Transfer context; old object no longer relocks wallet
* this = rhs ;
2016-09-11 11:02:54 +02:00
rhs . was_locked = false ;
rhs . was_mixing = false ;
2011-08-24 22:07:26 +02:00
}
2013-08-12 17:03:03 +02:00
bool WalletModel : : getPubKey ( const CKeyID & address , CPubKey & vchPubKeyOut ) const
{
return wallet - > GetPubKey ( address , vchPubKeyOut ) ;
}
2015-06-10 10:04:08 +02:00
bool WalletModel : : havePrivKey ( const CKeyID & address ) const
{
return wallet - > HaveKey ( address ) ;
}
2016-10-19 17:07:42 +02:00
bool WalletModel : : getPrivKey ( const CKeyID & address , CKey & vchPrivKeyOut ) const
{
return wallet - > GetKey ( address , vchPrivKeyOut ) ;
}
2013-08-12 17:03:03 +02:00
// returns a list of COutputs from COutPoints
void WalletModel : : getOutputs ( const std : : vector < COutPoint > & vOutpoints , std : : vector < COutput > & vOutputs )
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
2013-08-12 17:03:03 +02:00
BOOST_FOREACH ( const COutPoint & outpoint , vOutpoints )
{
if ( ! wallet - > mapWallet . count ( outpoint . hash ) ) continue ;
2014-02-12 19:43:07 +01:00
int nDepth = wallet - > mapWallet [ outpoint . hash ] . GetDepthInMainChain ( ) ;
if ( nDepth < 0 ) continue ;
2017-09-09 09:04:02 +02:00
COutput out ( & wallet - > mapWallet [ outpoint . hash ] , outpoint . n , nDepth , true , true ) ;
2013-08-12 17:03:03 +02:00
vOutputs . push_back ( out ) ;
}
}
2014-02-15 22:38:28 +01:00
bool WalletModel : : isSpent ( const COutPoint & outpoint ) const
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
2014-02-15 22:38:28 +01:00
return wallet - > IsSpent ( outpoint . hash , outpoint . n ) ;
}
2013-08-12 17:03:03 +02:00
// 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
{
std : : vector < COutput > vCoins ;
wallet - > AvailableCoins ( vCoins ) ;
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , wallet - > cs_wallet ) ; // ListLockedCoins, mapWallet
2013-08-12 17:03:03 +02:00
std : : vector < COutPoint > vLockedCoins ;
wallet - > ListLockedCoins ( vLockedCoins ) ;
// add locked coins
BOOST_FOREACH ( const COutPoint & outpoint , vLockedCoins )
{
if ( ! wallet - > mapWallet . count ( outpoint . hash ) ) continue ;
2014-02-12 19:43:07 +01:00
int nDepth = wallet - > mapWallet [ outpoint . hash ] . GetDepthInMainChain ( ) ;
if ( nDepth < 0 ) continue ;
2017-09-09 09:04:02 +02:00
COutput out ( & wallet - > mapWallet [ outpoint . hash ] , outpoint . n , nDepth , true , true ) ;
2016-12-05 08:01:20 +01:00
if ( outpoint . n < out . tx - > tx - > vout . size ( ) & & wallet - > IsMine ( out . tx - > tx - > vout [ outpoint . n ] ) = = ISMINE_SPENDABLE )
2014-07-26 21:05:11 +02:00
vCoins . push_back ( out ) ;
2013-08-12 17:03:03 +02:00
}
BOOST_FOREACH ( const COutput & out , vCoins )
{
COutput cout = out ;
2016-12-05 08:01:20 +01:00
while ( wallet - > IsChange ( cout . tx - > tx - > vout [ cout . i ] ) & & cout . tx - > tx - > vin . size ( ) > 0 & & wallet - > IsMine ( cout . tx - > tx - > vin [ 0 ] ) )
2013-08-12 17:03:03 +02:00
{
2016-12-05 08:01:20 +01:00
if ( ! wallet - > mapWallet . count ( cout . tx - > tx - > vin [ 0 ] . prevout . hash ) ) break ;
cout = COutput ( & wallet - > mapWallet [ cout . tx - > tx - > vin [ 0 ] . prevout . hash ] , cout . tx - > tx - > vin [ 0 ] . prevout . n , 0 , true , true ) ;
2013-08-12 17:03:03 +02:00
}
CTxDestination address ;
2016-12-05 08:01:20 +01:00
if ( ! out . fSpendable | | ! ExtractDestination ( cout . tx - > tx - > vout [ cout . i ] . scriptPubKey , address ) )
2013-12-10 15:27:53 +01:00
continue ;
2014-09-08 12:25:52 +02:00
mapCoins [ QString : : fromStdString ( CBitcoinAddress ( address ) . ToString ( ) ) ] . push_back ( out ) ;
2013-08-12 17:03:03 +02:00
}
}
bool WalletModel : : isLockedCoin ( uint256 hash , unsigned int n ) const
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
2013-08-12 17:03:03 +02:00
return wallet - > IsLockedCoin ( hash , n ) ;
}
void WalletModel : : lockCoin ( COutPoint & output )
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
2013-08-12 17:03:03 +02:00
wallet - > LockCoin ( output ) ;
}
void WalletModel : : unlockCoin ( COutPoint & output )
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
2013-08-12 17:03:03 +02:00
wallet - > UnlockCoin ( output ) ;
}
void WalletModel : : listLockedCoins ( std : : vector < COutPoint > & vOutpts )
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
2013-08-12 17:03:03 +02:00
wallet - > ListLockedCoins ( vOutpts ) ;
}
2014-01-14 05:05:43 +01:00
void WalletModel : : loadReceiveRequests ( std : : vector < std : : string > & vReceiveRequests )
{
LOCK ( wallet - > cs_wallet ) ;
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , CAddressBookData ) & item , wallet - > mapAddressBook )
BOOST_FOREACH ( const PAIRTYPE ( std : : string , std : : string ) & item2 , item . second . destdata )
if ( item2 . first . size ( ) > 2 & & item2 . first . substr ( 0 , 2 ) = = " rr " ) // receive request
vReceiveRequests . push_back ( item2 . second ) ;
}
bool WalletModel : : saveReceiveRequest ( const std : : string & sAddress , const int64_t nId , const std : : string & sRequest )
{
CTxDestination dest = CBitcoinAddress ( sAddress ) . Get ( ) ;
std : : stringstream ss ;
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 ) ;
else
return wallet - > AddDestData ( dest , key , sRequest ) ;
}
2017-05-29 13:51:40 +02:00
2017-09-09 09:04:02 +02:00
bool WalletModel : : transactionCanBeAbandoned ( uint256 hash ) const
{
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
const CWalletTx * wtx = wallet - > GetWalletTx ( hash ) ;
if ( ! wtx | | wtx - > isAbandoned ( ) | | wtx - > GetDepthInMainChain ( ) > 0 | | wtx - > InMempool ( ) )
return false ;
return true ;
}
bool WalletModel : : abandonTransaction ( uint256 hash ) const
{
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
return wallet - > AbandonTransaction ( hash ) ;
}
2016-09-21 13:21:04 +02:00
bool WalletModel : : isWalletEnabled ( )
{
return ! GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) ;
}
2017-05-29 13:51:40 +02:00
bool WalletModel : : hdEnabled ( ) const
{
return wallet - > IsHDEnabled ( ) ;
}
2016-10-28 14:08:39 +02:00
int WalletModel : : getDefaultConfirmTarget ( ) const
{
return nTxConfirmTarget ;
}