2020-04-16 13:14:08 -04:00
// Copyright (c) 2011-2020 The Bitcoin Core developers
2014-12-13 01:09:33 -03:00
// Distributed under the MIT software license, see the accompanying
2013-11-04 12:20:43 -03:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-11-06 15:12:47 -03:00
# if defined(HAVE_CONFIG_H)
# include <config/bitcoin-config.h>
# endif
2017-11-09 21:57:53 -03:00
# include <qt/walletmodel.h>
# include <qt/addresstablemodel.h>
2018-08-01 13:38:45 -04:00
# include <qt/clientmodel.h>
2017-11-09 21:57:53 -03:00
# include <qt/guiconstants.h>
2019-11-22 17:32:09 -03:00
# include <qt/guiutil.h>
2017-11-09 21:57:53 -03:00
# include <qt/optionsmodel.h>
# include <qt/paymentserver.h>
# include <qt/recentrequeststablemodel.h>
# include <qt/sendcoinsdialog.h>
# include <qt/transactiontablemodel.h>
2018-04-07 04:42:02 -03:00
# include <interfaces/handler.h>
# include <interfaces/node.h>
2017-09-19 22:12:25 -03:00
# include <key_io.h>
2020-06-19 18:14:17 -04:00
# include <node/ui_interface.h>
2020-01-24 19:02:41 -03:00
# include <psbt.h>
2018-10-22 19:51:11 -03:00
# include <util/system.h> // for GetBoolArg
2020-04-18 15:18:17 -04:00
# include <util/translation.h>
2017-11-09 21:57:53 -03:00
# include <wallet/coincontrol.h>
2017-12-05 17:57:12 -03:00
# include <wallet/wallet.h> // for CRecipient
2011-06-30 12:05:29 -04:00
2013-04-13 02:13:08 -03:00
# include <stdint.h>
# include <QDebug>
2017-02-03 18:04:39 -03:00
# include <QMessageBox>
2011-07-16 13:01:05 -04:00
# include <QSet>
2012-07-05 11:43:28 -04:00
# include <QTimer>
2011-06-30 12:05:29 -04:00
2015-07-05 09:17:46 -03:00
2018-08-01 13:38:45 -04:00
WalletModel : : WalletModel ( std : : unique_ptr < interfaces : : Wallet > wallet , ClientModel & client_model , const PlatformStyle * platformStyle , QObject * parent ) :
QObject ( parent ) ,
m_wallet ( std : : move ( wallet ) ) ,
2020-04-24 18:06:26 -04:00
m_client_model ( & client_model ) ,
2018-08-01 13:38:45 -04:00
m_node ( client_model . node ( ) ) ,
optionsModel ( client_model . getOptionsModel ( ) ) ,
addressTableModel ( nullptr ) ,
2018-07-30 06:37:09 -04:00
transactionTableModel ( nullptr ) ,
recentRequestsTableModel ( nullptr ) ,
2012-07-05 11:43:28 -04:00
cachedEncryptionStatus ( Unencrypted ) ,
2020-04-24 18:06:26 -04:00
timer ( new QTimer ( this ) )
2011-06-30 12:05:29 -04:00
{
2017-04-17 19:56:44 -03:00
fHaveWatchOnly = m_wallet - > haveWatchOnly ( ) ;
2017-04-18 14:01:23 -03:00
addressTableModel = new AddressTableModel ( this ) ;
2017-04-18 17:42:30 -03:00
transactionTableModel = new TransactionTableModel ( platformStyle , this ) ;
recentRequestsTableModel = new RecentRequestsTableModel ( this ) ;
2012-05-06 13:40:58 -04:00
subscribeToCoreSignals ( ) ;
}
WalletModel : : ~ WalletModel ( )
{
unsubscribeFromCoreSignals ( ) ;
2011-06-30 12:05:29 -04:00
}
2019-10-12 18:26:47 -03:00
void WalletModel : : startPollBalance ( )
{
// This timer will be fired repeatedly to update the balance
connect ( timer , & QTimer : : timeout , this , & WalletModel : : pollBalanceChanged ) ;
timer - > start ( MODEL_UPDATE_DELAY ) ;
}
2020-04-24 18:06:26 -04:00
void WalletModel : : setClientModel ( ClientModel * client_model )
{
m_client_model = client_model ;
if ( ! m_client_model ) timer - > stop ( ) ;
}
2012-05-05 10:07:14 -04:00
void WalletModel : : updateStatus ( )
2011-06-30 12:05:29 -04:00
{
2012-05-05 10:07:14 -04:00
EncryptionStatus newEncryptionStatus = getEncryptionStatus ( ) ;
2016-10-24 04:21:51 -03:00
if ( cachedEncryptionStatus ! = newEncryptionStatus ) {
Q_EMIT encryptionStatusChanged ( ) ;
}
2012-05-05 10:07:14 -04:00
}
2012-07-05 11:43:28 -04:00
void WalletModel : : pollBalanceChanged ( )
2012-05-05 10:07:14 -04:00
{
2020-04-02 08:42:01 -03:00
// Avoid recomputing wallet balances unless a TransactionChanged or
// BlockTip notification was received.
2020-06-22 16:35:48 -04:00
if ( ! fForceCheckBalanceChanged & & m_cached_last_update_tip = = getLastBlockProcessed ( ) ) return ;
2020-04-02 08:42:01 -03:00
2017-04-17 19:56:44 -03: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.
2018-04-07 04:42:02 -03:00
interfaces : : WalletBalances new_balances ;
2020-01-23 19:31:16 -03:00
uint256 block_hash ;
if ( ! m_wallet - > tryGetBalances ( new_balances , block_hash ) ) {
2014-04-23 03:40:48 -03:00
return ;
2017-04-17 19:56:44 -03:00
}
2014-04-23 03:40:48 -03:00
2020-01-23 19:31:16 -03:00
if ( fForceCheckBalanceChanged | | block_hash ! = m_cached_last_update_tip ) {
2020-04-02 08:55:14 -03:00
fForceCheckBalanceChanged = false ;
2014-08-16 20:34:42 -04:00
2020-04-02 08:55:14 -03:00
// Balance and number of transactions might have changed
2020-01-23 19:31:16 -03:00
m_cached_last_update_tip = block_hash ;
2014-04-23 03:40:48 -03:00
2020-04-02 08:55:14 -03:00
checkBalanceChanged ( new_balances ) ;
if ( transactionTableModel )
transactionTableModel - > updateConfirmations ( ) ;
}
2012-07-05 11:43:28 -04:00
}
2018-04-07 04:42:02 -03:00
void WalletModel : : checkBalanceChanged ( const interfaces : : WalletBalances & new_balances )
2012-07-05 11:43:28 -04:00
{
2017-04-17 19:56:44 -03:00
if ( new_balances . balanceChanged ( m_cached_balances ) ) {
m_cached_balances = new_balances ;
2018-03-31 07:41:33 -03:00
Q_EMIT balanceChanged ( new_balances ) ;
2012-07-05 11:43:28 -04:00
}
}
2012-02-14 08:08:00 -03:00
2014-10-28 15:52:21 -03:00
void WalletModel : : updateTransaction ( )
2012-07-05 11:43:28 -04:00
{
// Balance and number of transactions might have changed
2014-08-16 20:34:42 -04:00
fForceCheckBalanceChanged = true ;
2011-06-30 12:05:29 -04:00
}
2013-09-04 05:52:45 -04:00
void WalletModel : : updateAddressBook ( const QString & address , const QString & label ,
2013-08-29 10:19:43 -04:00
bool isMine , const QString & purpose , int status )
2012-03-24 14:48:18 -03:00
{
2012-05-05 10:07:14 -04:00
if ( addressTableModel )
2013-08-29 10:19:43 -04:00
addressTableModel - > updateEntry ( address , label , isMine , purpose , status ) ;
2012-03-24 14:48:18 -03:00
}
2014-07-26 15:05:11 -04:00
void WalletModel : : updateWatchOnlyFlag ( bool fHaveWatchonly )
{
fHaveWatchOnly = fHaveWatchonly ;
2015-07-14 08:59:05 -03:00
Q_EMIT notifyWatchonlyChanged ( fHaveWatchonly ) ;
2014-07-26 15:05:11 -04:00
}
2011-07-16 13:01:05 -04:00
bool WalletModel : : validateAddress ( const QString & address )
2011-06-30 12:05:29 -04:00
{
2017-08-22 22:02:33 -03:00
return IsValidDestinationString ( address . toStdString ( ) ) ;
2011-07-16 13:01:05 -04:00
}
2017-06-28 16:41:55 -04:00
WalletModel : : SendCoinsReturn WalletModel : : prepareTransaction ( WalletModelTransaction & transaction , const CCoinControl & coinControl )
2011-07-16 13:01:05 -04:00
{
2014-04-22 19:46:19 -03:00
CAmount total = 0 ;
2014-07-23 08:34:36 -04:00
bool fSubtractFeeFromAmount = false ;
2013-08-30 14:04:48 -04:00
QList < SendCoinsRecipient > recipients = transaction . getRecipients ( ) ;
2014-07-23 08:34:36 -04:00
std : : vector < CRecipient > vecSend ;
2011-07-16 13:01:05 -04:00
if ( recipients . empty ( ) )
2011-06-30 12:05:29 -04:00
{
2011-07-16 13:01:05 -04:00
return OK ;
2011-06-30 12:05:29 -04:00
}
2013-07-22 02:50:39 -04:00
QSet < QString > setAddress ; // Used to detect duplicates
int nAddresses = 0 ;
2011-07-16 13:01:05 -04:00
// Pre-check input data for validity
2017-06-01 21:25:02 -04:00
for ( const SendCoinsRecipient & rcp : recipients )
2011-06-30 12:05:29 -04:00
{
2014-07-23 08:34:36 -04:00
if ( rcp . fSubtractFeeFromAmount )
fSubtractFeeFromAmount = true ;
2013-07-22 02:50:39 -04:00
{ // 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 13:01:05 -04:00
2017-08-22 22:02:33 -03:00
CScript scriptPubKey = GetScriptForDestination ( DecodeDestination ( rcp . address . toStdString ( ) ) ) ;
2014-07-23 08:34:36 -04:00
CRecipient recipient = { scriptPubKey , rcp . amount , rcp . fSubtractFeeFromAmount } ;
vecSend . push_back ( recipient ) ;
2013-07-22 02:50:39 -04:00
total + = rcp . amount ;
2011-07-16 13:01:05 -04:00
}
2011-06-30 12:05:29 -04:00
}
2013-07-22 02:50:39 -04:00
if ( setAddress . size ( ) ! = nAddresses )
2011-07-16 13:01:05 -04:00
{
return DuplicateAddress ;
}
2017-04-17 19:56:44 -03:00
CAmount nBalance = m_wallet - > getAvailableBalance ( coinControl ) ;
2013-08-12 11:03:03 -04:00
if ( total > nBalance )
2011-06-30 12:05:29 -04:00
{
return AmountExceedsBalance ;
}
{
2014-04-22 19:46:19 -03:00
CAmount nFeeRequired = 0 ;
2014-07-23 08:34:36 -04:00
int nChangePosRet = - 1 ;
2020-04-18 15:18:17 -04:00
bilingual_str error ;
2013-08-30 14:04:48 -04:00
2017-04-17 19:56:44 -03:00
auto & newTx = transaction . getWtx ( ) ;
2020-04-18 15:18:17 -04:00
newTx = m_wallet - > createTransaction ( vecSend , coinControl , ! wallet ( ) . privateKeysDisabled ( ) /* sign */ , nChangePosRet , nFeeRequired , error ) ;
2013-08-30 14:04:48 -04:00
transaction . setTransactionFee ( nFeeRequired ) ;
2017-04-17 19:56:44 -03:00
if ( fSubtractFeeFromAmount & & newTx )
2014-07-23 08:34:36 -04:00
transaction . reassignAmounts ( nChangePosRet ) ;
2011-06-30 12:05:29 -04:00
2017-04-17 19:56:44 -03:00
if ( ! newTx )
2011-06-30 12:05:29 -04:00
{
2014-07-23 08:34:36 -04:00
if ( ! fSubtractFeeFromAmount & & ( total + nFeeRequired ) > nBalance )
2011-07-16 13:01:05 -04:00
{
2013-08-30 14:04:48 -04:00
return SendCoinsReturn ( AmountWithFeeExceedsBalance ) ;
2011-07-16 13:01:05 -04:00
}
2020-04-18 15:18:17 -04:00
Q_EMIT message ( tr ( " Send Coins " ) , QString : : fromStdString ( error . translated ) ,
CClientUIInterface : : MSG_ERROR ) ;
2011-07-16 13:01:05 -04:00
return TransactionCreationFailed ;
2011-06-30 12:05:29 -04:00
}
2014-11-01 20:14:47 -03:00
2019-07-02 10:16:36 -04:00
// Reject absurdly high fee. (This can never happen because the
// wallet never creates transactions with fee greater than
// m_default_max_tx_fee. This merely a belt-and-suspenders check).
if ( nFeeRequired > m_wallet - > getDefaultMaxTxFee ( ) ) {
2015-01-30 23:54:55 -03:00
return AbsurdFee ;
2019-07-02 10:16:36 -04:00
}
2013-08-30 14:04:48 -04:00
}
return SendCoinsReturn ( OK ) ;
}
WalletModel : : SendCoinsReturn WalletModel : : sendCoins ( WalletModelTransaction & transaction )
{
QByteArray transaction_array ; /* store serialized transaction */
{
2017-02-02 17:30:03 -03:00
std : : vector < std : : pair < std : : string , std : : string > > vOrderForm ;
2017-06-01 21:25:02 -04:00
for ( const SendCoinsRecipient & rcp : transaction . getRecipients ( ) )
2013-07-22 02:50:39 -04:00
{
2017-11-06 15:12:47 -03:00
if ( ! rcp . message . isEmpty ( ) ) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
2017-02-02 17:30:03 -03:00
vOrderForm . emplace_back ( " Message " , rcp . message . toStdString ( ) ) ;
2011-06-30 12:05:29 -04:00
}
2013-08-30 14:04:48 -04:00
2017-04-17 19:56:44 -03:00
auto & newTx = transaction . getWtx ( ) ;
2019-04-03 18:55:24 -03:00
wallet ( ) . commitTransaction ( newTx , { } /* mapValue */ , std : : move ( vOrderForm ) ) ;
2013-07-22 02:50:39 -04:00
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
2019-07-18 12:06:23 -04:00
ssTx < < * newTx ;
2013-08-30 14:04:48 -04:00
transaction_array . append ( & ( ssTx [ 0 ] ) , ssTx . size ( ) ) ;
2011-06-30 12:05:29 -04:00
}
2017-06-19 18:57:31 -04:00
// Add addresses / update labels that we've sent to the address book,
2013-08-30 14:04:48 -04:00
// and emit coinsSent signal for each recipient
2017-06-01 21:25:02 -04:00
for ( const SendCoinsRecipient & rcp : transaction . getRecipients ( ) )
2011-06-30 12:05:29 -04:00
{
2011-07-16 13:01:05 -04:00
{
2013-10-08 09:23:57 -03:00
std : : string strAddress = rcp . address . toStdString ( ) ;
2017-08-22 22:02:33 -03:00
CTxDestination dest = DecodeDestination ( strAddress ) ;
2013-10-08 09:23:57 -03:00
std : : string strLabel = rcp . label . toStdString ( ) ;
2012-05-03 08:52:15 -04:00
{
2013-10-08 09:23:57 -03:00
// Check if we have a new address or an updated label
2017-04-17 19:56:44 -03:00
std : : string name ;
2018-04-10 12:50:10 -03:00
if ( ! m_wallet - > getAddress (
dest , & name , /* is_mine= */ nullptr , /* purpose= */ nullptr ) )
2013-10-08 09:23:57 -03:00
{
2017-04-17 19:56:44 -03:00
m_wallet - > setAddressBook ( dest , strLabel , " send " ) ;
2013-10-08 09:23:57 -03:00
}
2017-04-17 19:56:44 -03:00
else if ( name ! = strLabel )
2013-10-08 09:23:57 -03:00
{
2017-04-17 19:56:44 -03:00
m_wallet - > setAddressBook ( dest , strLabel , " " ) ; // "" means don't change purpose
2013-10-08 09:23:57 -03:00
}
2012-05-03 08:52:15 -04:00
}
2011-07-16 13:01:05 -04:00
}
2018-03-23 18:14:39 -03:00
Q_EMIT coinsSent ( this , rcp , transaction_array ) ;
2011-06-30 12:05:29 -04:00
}
2017-04-17 19:56:44 -03:00
checkBalanceChanged ( m_wallet - > getBalances ( ) ) ; // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
2011-07-30 13:28:41 -04:00
2013-08-30 14:04:48 -04:00
return SendCoinsReturn ( OK ) ;
2011-06-30 12:05:29 -04:00
}
OptionsModel * WalletModel : : getOptionsModel ( )
{
return optionsModel ;
}
AddressTableModel * WalletModel : : getAddressTableModel ( )
{
return addressTableModel ;
}
TransactionTableModel * WalletModel : : getTransactionTableModel ( )
{
return transactionTableModel ;
}
2011-07-02 07:45:59 -04:00
2013-11-05 14:03:05 -03:00
RecentRequestsTableModel * WalletModel : : getRecentRequestsTableModel ( )
{
return recentRequestsTableModel ;
}
2011-08-23 15:08:42 -03:00
WalletModel : : EncryptionStatus WalletModel : : getEncryptionStatus ( ) const
{
2017-04-17 19:56:44 -03:00
if ( ! m_wallet - > isCrypted ( ) )
2011-08-23 15:08:42 -03:00
{
return Unencrypted ;
}
2017-04-17 19:56:44 -03:00
else if ( m_wallet - > isLocked ( ) )
2011-08-23 15:08:42 -03:00
{
return Locked ;
}
else
{
return Unlocked ;
}
}
2011-08-24 17:07:26 -03:00
2011-11-26 03:02:04 -03:00
bool WalletModel : : setWalletEncrypted ( bool encrypted , const SecureString & passphrase )
2011-08-24 17:07:26 -03:00
{
2020-05-17 11:02:17 -04:00
if ( encrypted ) {
2017-04-17 19:56:44 -03:00
return m_wallet - > encryptWallet ( passphrase ) ;
2011-08-24 17:07:26 -03:00
}
2020-05-17 11:02:17 -04:00
return false ;
2011-08-24 17:07:26 -03:00
}
2011-11-26 03:02:04 -03:00
bool WalletModel : : setWalletLocked ( bool locked , const SecureString & passPhrase )
2011-08-24 17:07:26 -03:00
{
if ( locked )
{
// Lock
2017-04-17 19:56:44 -03:00
return m_wallet - > lock ( ) ;
2011-08-24 17:07:26 -03:00
}
else
{
// Unlock
2017-04-17 19:56:44 -03:00
return m_wallet - > unlock ( passPhrase ) ;
2011-08-24 17:07:26 -03:00
}
}
2011-11-26 03:02:04 -03:00
bool WalletModel : : changePassphrase ( const SecureString & oldPass , const SecureString & newPass )
2011-08-24 17:07:26 -03:00
{
2017-04-17 19:56:44 -03:00
m_wallet - > lock ( ) ; // Make sure wallet is locked before attempting pass change
return m_wallet - > changeWalletPassphrase ( oldPass , newPass ) ;
2012-02-14 09:14:43 -03:00
}
2012-05-06 13:40:58 -04:00
// Handlers for core signals
2018-06-05 06:17:28 -04:00
static void NotifyUnload ( WalletModel * walletModel )
{
qDebug ( ) < < " NotifyUnload " ;
2019-07-06 12:16:01 -04:00
bool invoked = QMetaObject : : invokeMethod ( walletModel , " unload " ) ;
assert ( invoked ) ;
2018-06-05 06:17:28 -04:00
}
2017-04-17 19:56:44 -03:00
static void NotifyKeyStoreStatusChanged ( WalletModel * walletmodel )
2012-05-06 13:40:58 -04:00
{
2013-09-04 05:52:45 -04:00
qDebug ( ) < < " NotifyKeyStoreStatusChanged " ;
2019-07-06 12:16:01 -04:00
bool invoked = QMetaObject : : invokeMethod ( walletmodel , " updateStatus " , Qt : : QueuedConnection ) ;
assert ( invoked ) ;
2012-05-06 13:40:58 -04:00
}
2017-04-17 19:56:44 -03:00
static void NotifyAddressBookChanged ( WalletModel * walletmodel ,
2013-08-29 10:19:43 -04:00
const CTxDestination & address , const std : : string & label , bool isMine ,
const std : : string & purpose , ChangeType status )
2012-05-06 13:40:58 -04:00
{
2017-08-22 22:02:33 -03:00
QString strAddress = QString : : fromStdString ( EncodeDestination ( address ) ) ;
2013-09-04 05:52:45 -04:00
QString strLabel = QString : : fromStdString ( label ) ;
QString strPurpose = QString : : fromStdString ( purpose ) ;
2015-01-08 07:44:25 -03:00
qDebug ( ) < < " NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine= " + QString : : number ( isMine ) + " purpose= " + strPurpose + " status= " + QString : : number ( status ) ;
2019-07-06 12:16:01 -04:00
bool invoked = QMetaObject : : invokeMethod ( walletmodel , " updateAddressBook " , Qt : : QueuedConnection ,
2013-09-04 05:52:45 -04:00
Q_ARG ( QString , strAddress ) ,
Q_ARG ( QString , strLabel ) ,
2012-05-06 16:41:35 -04:00
Q_ARG ( bool , isMine ) ,
2013-09-04 05:52:45 -04:00
Q_ARG ( QString , strPurpose ) ,
2012-05-06 13:40:58 -04:00
Q_ARG ( int , status ) ) ;
2019-07-06 12:16:01 -04:00
assert ( invoked ) ;
2012-05-06 13:40:58 -04:00
}
2017-04-17 19:56:44 -03:00
static void NotifyTransactionChanged ( WalletModel * walletmodel , const uint256 & hash , ChangeType status )
2012-05-06 13:40:58 -04:00
{
2014-10-28 15:52:21 -03:00
Q_UNUSED ( hash ) ;
Q_UNUSED ( status ) ;
2019-07-06 12:16:01 -04:00
bool invoked = QMetaObject : : invokeMethod ( walletmodel , " updateTransaction " , Qt : : QueuedConnection ) ;
assert ( invoked ) ;
2012-05-06 13:40:58 -04:00
}
2014-03-18 20:26:14 -03:00
static void ShowProgress ( WalletModel * walletmodel , const std : : string & title , int nProgress )
{
2014-08-16 20:34:42 -04:00
// emits signal "showProgress"
2019-07-06 12:16:01 -04:00
bool invoked = QMetaObject : : invokeMethod ( walletmodel , " showProgress " , Qt : : QueuedConnection ,
2014-08-16 20:34:42 -04:00
Q_ARG ( QString , QString : : fromStdString ( title ) ) ,
Q_ARG ( int , nProgress ) ) ;
2019-07-06 12:16:01 -04:00
assert ( invoked ) ;
2014-03-18 20:26:14 -03:00
}
2014-07-26 15:05:11 -04:00
static void NotifyWatchonlyChanged ( WalletModel * walletmodel , bool fHaveWatchonly )
{
2019-07-06 12:16:01 -04:00
bool invoked = QMetaObject : : invokeMethod ( walletmodel , " updateWatchOnlyFlag " , Qt : : QueuedConnection ,
2014-07-26 15:05:11 -04:00
Q_ARG ( bool , fHaveWatchonly ) ) ;
2019-07-06 12:16:01 -04:00
assert ( invoked ) ;
2014-07-26 15:05:11 -04:00
}
2019-01-18 19:05:32 -03:00
static void NotifyCanGetAddressesChanged ( WalletModel * walletmodel )
{
2019-07-06 12:16:01 -04:00
bool invoked = QMetaObject : : invokeMethod ( walletmodel , " canGetAddressesChanged " ) ;
assert ( invoked ) ;
2019-01-18 19:05:32 -03:00
}
2012-05-06 13:40:58 -04:00
void WalletModel : : subscribeToCoreSignals ( )
{
// Connect signals to wallet
2018-10-17 12:51:17 -03:00
m_handler_unload = m_wallet - > handleUnload ( std : : bind ( & NotifyUnload , this ) ) ;
m_handler_status_changed = m_wallet - > handleStatusChanged ( std : : bind ( & NotifyKeyStoreStatusChanged , this ) ) ;
m_handler_address_book_changed = m_wallet - > handleAddressBookChanged ( std : : bind ( NotifyAddressBookChanged , this , std : : placeholders : : _1 , std : : placeholders : : _2 , std : : placeholders : : _3 , std : : placeholders : : _4 , std : : placeholders : : _5 ) ) ;
m_handler_transaction_changed = m_wallet - > handleTransactionChanged ( std : : bind ( NotifyTransactionChanged , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
m_handler_show_progress = m_wallet - > handleShowProgress ( std : : bind ( ShowProgress , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
m_handler_watch_only_changed = m_wallet - > handleWatchOnlyChanged ( std : : bind ( NotifyWatchonlyChanged , this , std : : placeholders : : _1 ) ) ;
2019-01-18 19:05:32 -03:00
m_handler_can_get_addrs_changed = m_wallet - > handleCanGetAddressesChanged ( boost : : bind ( NotifyCanGetAddressesChanged , this ) ) ;
2012-05-06 13:40:58 -04:00
}
void WalletModel : : unsubscribeFromCoreSignals ( )
{
// Disconnect signals from wallet
2018-06-05 06:17:28 -04:00
m_handler_unload - > disconnect ( ) ;
2017-04-17 19:56:44 -03: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 ( ) ;
2019-01-18 19:05:32 -03:00
m_handler_can_get_addrs_changed - > disconnect ( ) ;
2012-05-06 13:40:58 -04:00
}
2011-08-24 17:07:26 -03:00
// WalletModel::UnlockContext implementation
WalletModel : : UnlockContext WalletModel : : requestUnlock ( )
{
bool was_locked = getEncryptionStatus ( ) = = Locked ;
if ( was_locked )
{
// Request UI to unlock wallet
2015-07-14 08:59:05 -03:00
Q_EMIT requireUnlock ( ) ;
2011-08-24 17:07:26 -03: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 08:43:29 -03:00
WalletModel : : UnlockContext : : UnlockContext ( WalletModel * _wallet , bool _valid , bool _relock ) :
wallet ( _wallet ) ,
valid ( _valid ) ,
relock ( _relock )
2011-08-24 17:07:26 -03:00
{
}
WalletModel : : UnlockContext : : ~ UnlockContext ( )
{
if ( valid & & relock )
{
wallet - > setWalletLocked ( true ) ;
}
}
2019-05-09 21:07:33 -04:00
void WalletModel : : UnlockContext : : CopyFrom ( UnlockContext & & rhs )
2011-08-24 17:07:26 -03:00
{
// Transfer context; old object no longer relocks wallet
* this = rhs ;
rhs . relock = false ;
}
2013-08-12 11:03:03 -04:00
2014-01-14 01:05:43 -03:00
void WalletModel : : loadReceiveRequests ( std : : vector < std : : string > & vReceiveRequests )
{
2017-04-17 19:56:44 -03:00
vReceiveRequests = m_wallet - > getDestValues ( " rr " ) ; // receive request
2014-01-14 01:05:43 -03:00
}
bool WalletModel : : saveReceiveRequest ( const std : : string & sAddress , const int64_t nId , const std : : string & sRequest )
{
2017-08-22 22:02:33 -03:00
CTxDestination dest = DecodeDestination ( sAddress ) ;
2014-01-14 01:05:43 -03:00
std : : stringstream ss ;
ss < < nId ;
std : : string key = " rr " + ss . str ( ) ; // "rr" prefix = "receive request" in destdata
if ( sRequest . empty ( ) )
2017-04-17 19:56:44 -03:00
return m_wallet - > eraseDestData ( dest , key ) ;
2014-01-14 01:05:43 -03:00
else
2017-04-17 19:56:44 -03:00
return m_wallet - > addDestData ( dest , key , sRequest ) ;
2017-02-03 18:04:39 -03:00
}
2018-08-01 12:43:46 -04:00
bool WalletModel : : bumpFee ( uint256 hash , uint256 & new_hash )
2017-02-03 18:04:39 -03:00
{
2017-06-15 10:34:17 -04:00
CCoinControl coin_control ;
2018-04-07 13:12:46 -03:00
coin_control . m_signal_bip125_rbf = true ;
2020-04-18 15:18:17 -04:00
std : : vector < bilingual_str > errors ;
2017-06-15 10:34:17 -04:00
CAmount old_fee ;
CAmount new_fee ;
CMutableTransaction mtx ;
2020-03-10 14:40:57 -03:00
if ( ! m_wallet - > createBumpTransaction ( hash , coin_control , errors , old_fee , new_fee , mtx ) ) {
2018-07-31 14:02:34 -04:00
QMessageBox : : critical ( nullptr , tr ( " Fee bump error " ) , tr ( " Increasing transaction fee failed " ) + " <br />( " +
2020-04-18 15:18:17 -04:00
( errors . size ( ) ? QString : : fromStdString ( errors [ 0 ] . translated ) : " " ) + " ) " ) ;
return false ;
2017-02-03 18:04:39 -03:00
}
2017-12-05 17:57:12 -03:00
const bool create_psbt = m_wallet - > privateKeysDisabled ( ) ;
2019-11-22 17:32:09 -03:00
2017-02-03 18:04:39 -03:00
// allow a user based fee verification
2019-11-22 17:32:09 -03:00
QString questionString = create_psbt ? tr ( " Do you want to draft a transaction with fee increase? " ) : tr ( " Do you want to increase the fee? " ) ;
2017-04-26 04:55:54 -03:00
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 10:34:17 -04:00
questionString . append ( BitcoinUnits : : formatHtmlWithUnit ( getOptionsModel ( ) - > getDisplayUnit ( ) , old_fee ) ) ;
2017-04-26 04:55:54 -03:00
questionString . append ( " </td></tr><tr><td> " ) ;
questionString . append ( tr ( " Increase: " ) ) ;
questionString . append ( " </td><td> " ) ;
2017-06-15 10:34:17 -04:00
questionString . append ( BitcoinUnits : : formatHtmlWithUnit ( getOptionsModel ( ) - > getDisplayUnit ( ) , new_fee - old_fee ) ) ;
2017-04-26 04:55:54 -03:00
questionString . append ( " </td></tr><tr><td> " ) ;
questionString . append ( tr ( " New fee: " ) ) ;
questionString . append ( " </td><td> " ) ;
2017-06-15 10:34:17 -04:00
questionString . append ( BitcoinUnits : : formatHtmlWithUnit ( getOptionsModel ( ) - > getDisplayUnit ( ) , new_fee ) ) ;
2017-04-26 04:55:54 -03:00
questionString . append ( " </td></tr></table> " ) ;
2017-02-03 18:04:39 -03:00
SendConfirmationDialog confirmationDialog ( tr ( " Confirm fee bump " ) , questionString ) ;
confirmationDialog . exec ( ) ;
2017-06-01 10:13:35 -04:00
QMessageBox : : StandardButton retval = static_cast < QMessageBox : : StandardButton > ( confirmationDialog . result ( ) ) ;
2017-02-03 18:04:39 -03:00
2018-03-18 11:26:45 -03:00
// cancel sign&broadcast if user doesn't want to bump the fee
2017-02-03 18:04:39 -03:00
if ( retval ! = QMessageBox : : Yes ) {
return false ;
}
WalletModel : : UnlockContext ctx ( requestUnlock ( ) ) ;
if ( ! ctx . isValid ( ) )
{
return false ;
}
2019-11-22 17:32:09 -03:00
// Short-circuit if we are returning a bumped transaction PSBT to clipboard
if ( create_psbt ) {
PartiallySignedTransaction psbtx ( mtx ) ;
bool complete = false ;
2020-01-31 23:12:14 -03:00
const TransactionError err = wallet ( ) . fillPSBT ( SIGHASH_ALL , false /* sign */ , true /* bip32derivs */ , psbtx , complete , nullptr ) ;
2020-01-14 11:27:08 -03:00
if ( err ! = TransactionError : : OK | | complete ) {
QMessageBox : : critical ( nullptr , tr ( " Fee bump error " ) , tr ( " Can't draft transaction. " ) ) ;
return false ;
}
2019-11-22 17:32:09 -03:00
// Serialize the PSBT
CDataStream ssTx ( SER_NETWORK , PROTOCOL_VERSION ) ;
ssTx < < psbtx ;
GUIUtil : : setClipboard ( EncodeBase64 ( ssTx . str ( ) ) . c_str ( ) ) ;
Q_EMIT message ( tr ( " PSBT copied " ) , " Copied to clipboard " , CClientUIInterface : : MSG_INFORMATION ) ;
return true ;
}
2017-02-03 18:04:39 -03:00
// sign bumped transaction
2017-04-17 19:56:44 -03:00
if ( ! m_wallet - > signBumpTransaction ( mtx ) ) {
2018-07-31 14:02:34 -04:00
QMessageBox : : critical ( nullptr , tr ( " Fee bump error " ) , tr ( " Can't sign transaction. " ) ) ;
2017-02-03 18:04:39 -03:00
return false ;
}
// commit the bumped transaction
2018-08-01 12:43:46 -04:00
if ( ! m_wallet - > commitBumpTransaction ( hash , std : : move ( mtx ) , errors , new_hash ) ) {
2018-07-31 14:02:34 -04:00
QMessageBox : : critical ( nullptr , tr ( " Fee bump error " ) , tr ( " Could not commit transaction " ) + " <br />( " +
2020-04-18 15:18:17 -04:00
QString : : fromStdString ( errors [ 0 ] . translated ) + " ) " ) ;
return false ;
2017-02-03 18:04:39 -03:00
}
return true ;
}
2016-09-21 07:37:00 -03:00
bool WalletModel : : isWalletEnabled ( )
{
2017-08-01 15:17:40 -04:00
return ! gArgs . GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) ;
2016-09-21 07:37:00 -03:00
}
2018-03-06 01:26:40 -03:00
QString WalletModel : : getWalletName ( ) const
{
2017-04-17 19:56:44 -03:00
return QString : : fromStdString ( m_wallet - > getWalletName ( ) ) ;
2018-03-06 01:26:40 -03:00
}
2018-06-25 17:22:01 -04:00
QString WalletModel : : getDisplayName ( ) const
{
const QString name = getWalletName ( ) ;
return name . isEmpty ( ) ? " [ " + tr ( " default wallet " ) + " ] " : name ;
}
2018-03-06 01:26:40 -03:00
bool WalletModel : : isMultiwallet ( )
{
2017-04-17 19:56:44 -03:00
return m_node . getWallets ( ) . size ( ) > 1 ;
2018-03-06 01:26:40 -03:00
}
2020-01-13 15:50:44 -03:00
void WalletModel : : refresh ( bool pk_hash_only )
{
addressTableModel = new AddressTableModel ( this , pk_hash_only ) ;
}
2020-06-22 16:35:48 -04:00
uint256 WalletModel : : getLastBlockProcessed ( ) const
{
return m_client_model ? m_client_model - > getBestBlockHash ( ) : uint256 { } ;
}