1 // Copyright (c) 2011-2019 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. 4 5 #ifndef BITCOIN_QT_WALLETMODEL_H 6 #define BITCOIN_QT_WALLETMODEL_H 7 8 #include <amount.h> 9 #include <key.h> 10 #include <serialize.h> 11 #include <script/standard.h> 12 13 #if defined(HAVE_CONFIG_H) 14 #include <config/bitcoin-config.h> 15 #endif 16 17 #ifdef ENABLE_BIP70 18 #include <qt/paymentrequestplus.h> 19 #endif 20 #include <qt/walletmodeltransaction.h> 21 22 #include <interfaces/wallet.h> 23 #include <support/allocators/secure.h> 24 25 #include <map> 26 #include <vector> 27 28 #include <QObject> 29 30 enum class OutputType; 31 32 class AddressTableModel; 33 class OptionsModel; 34 class PlatformStyle; 35 class RecentRequestsTableModel; 36 class TransactionTableModel; 37 class WalletModelTransaction; 38 39 class CCoinControl; 40 class CKeyID; 41 class COutPoint; 42 class COutput; 43 class CPubKey; 44 class uint256; 45 46 namespace interfaces { 47 class Node; 48 } // namespace interfaces 49 50 QT_BEGIN_NAMESPACE 51 class QTimer; 52 QT_END_NAMESPACE 53 54 class SendCoinsRecipient 55 { 56 public: SendCoinsRecipient()57 explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) { } SendCoinsRecipient(const QString & addr,const QString & _label,const CAmount & _amount,const QString & _message)58 explicit SendCoinsRecipient(const QString &addr, const QString &_label, const CAmount& _amount, const QString &_message): 59 address(addr), label(_label), amount(_amount), message(_message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} 60 61 // If from an unauthenticated payment request, this is used for storing 62 // the addresses, e.g. address-A<br />address-B<br />address-C. 63 // Info: As we don't need to process addresses in here when using 64 // payment requests, we can abuse it for displaying an address list. 65 // Todo: This is a hack, should be replaced with a cleaner solution! 66 QString address; 67 QString label; 68 CAmount amount; 69 // If from a payment request, this is used for storing the memo 70 QString message; 71 72 #ifdef ENABLE_BIP70 73 // If from a payment request, paymentRequest.IsInitialized() will be true 74 PaymentRequestPlus paymentRequest; 75 #else 76 // If building with BIP70 is disabled, keep the payment request around as 77 // serialized string to ensure load/store is lossless 78 std::string sPaymentRequest; 79 #endif 80 // Empty if no authentication or invalid signature/cert/etc. 81 QString authenticatedMerchant; 82 83 bool fSubtractFeeFromAmount; // memory only 84 85 static const int CURRENT_VERSION = 1; 86 int nVersion; 87 88 ADD_SERIALIZE_METHODS; 89 90 template <typename Stream, typename Operation> SerializationOp(Stream & s,Operation ser_action)91 inline void SerializationOp(Stream& s, Operation ser_action) { 92 std::string sAddress = address.toStdString(); 93 std::string sLabel = label.toStdString(); 94 std::string sMessage = message.toStdString(); 95 #ifdef ENABLE_BIP70 96 std::string sPaymentRequest; 97 if (!ser_action.ForRead() && paymentRequest.IsInitialized()) 98 paymentRequest.SerializeToString(&sPaymentRequest); 99 #endif 100 std::string sAuthenticatedMerchant = authenticatedMerchant.toStdString(); 101 102 READWRITE(this->nVersion); 103 READWRITE(sAddress); 104 READWRITE(sLabel); 105 READWRITE(amount); 106 READWRITE(sMessage); 107 READWRITE(sPaymentRequest); 108 READWRITE(sAuthenticatedMerchant); 109 110 if (ser_action.ForRead()) 111 { 112 address = QString::fromStdString(sAddress); 113 label = QString::fromStdString(sLabel); 114 message = QString::fromStdString(sMessage); 115 #ifdef ENABLE_BIP70 116 if (!sPaymentRequest.empty()) 117 paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size())); 118 #endif 119 authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant); 120 } 121 } 122 }; 123 124 /** Interface to Bitcoin wallet from Qt view code. */ 125 class WalletModel : public QObject 126 { 127 Q_OBJECT 128 129 public: 130 explicit WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *optionsModel, QObject *parent = nullptr); 131 ~WalletModel(); 132 133 enum StatusCode // Returned by sendCoins 134 { 135 OK, 136 InvalidAmount, 137 InvalidAddress, 138 AmountExceedsBalance, 139 AmountWithFeeExceedsBalance, 140 DuplicateAddress, 141 TransactionCreationFailed, // Error returned when wallet is still locked 142 TransactionCommitFailed, 143 AbsurdFee, 144 PaymentRequestExpired 145 }; 146 147 enum EncryptionStatus 148 { 149 Unencrypted, // !wallet->IsCrypted() 150 Locked, // wallet->IsCrypted() && wallet->IsLocked() 151 Unlocked // wallet->IsCrypted() && !wallet->IsLocked() 152 }; 153 154 OptionsModel *getOptionsModel(); 155 AddressTableModel *getAddressTableModel(); 156 TransactionTableModel *getTransactionTableModel(); 157 RecentRequestsTableModel *getRecentRequestsTableModel(); 158 159 EncryptionStatus getEncryptionStatus() const; 160 161 // Check address for validity 162 bool validateAddress(const QString &address); 163 164 // Return status record for SendCoins, contains error id + information 165 struct SendCoinsReturn 166 { 167 SendCoinsReturn(StatusCode _status = OK, QString _reasonCommitFailed = "") statusSendCoinsReturn168 : status(_status), 169 reasonCommitFailed(_reasonCommitFailed) 170 { 171 } 172 StatusCode status; 173 QString reasonCommitFailed; 174 }; 175 176 // prepare transaction for getting txfee before sending coins 177 SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl); 178 179 // Send coins to a list of recipients 180 SendCoinsReturn sendCoins(WalletModelTransaction &transaction); 181 182 // Wallet encryption 183 bool setWalletEncrypted(bool encrypted, const SecureString &passphrase); 184 // Passphrase only needed when unlocking 185 bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString()); 186 bool changePassphrase(const SecureString &oldPass, const SecureString &newPass); 187 188 // RAI object for unlocking wallet, returned by requestUnlock() 189 class UnlockContext 190 { 191 public: 192 UnlockContext(WalletModel *wallet, bool valid, bool relock); 193 ~UnlockContext(); 194 isValid()195 bool isValid() const { return valid; } 196 197 // Copy operator and constructor transfer the context UnlockContext(const UnlockContext & obj)198 UnlockContext(const UnlockContext& obj) { CopyFrom(obj); } 199 UnlockContext& operator=(const UnlockContext& rhs) { CopyFrom(rhs); return *this; } 200 private: 201 WalletModel *wallet; 202 bool valid; 203 mutable bool relock; // mutable, as it can be set to false by copying 204 205 void CopyFrom(const UnlockContext& rhs); 206 }; 207 208 UnlockContext requestUnlock(); 209 210 void loadReceiveRequests(std::vector<std::string>& vReceiveRequests); 211 bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest); 212 213 bool bumpFee(uint256 hash, uint256& new_hash); 214 215 static bool isWalletEnabled(); 216 bool privateKeysDisabled() const; 217 bool canGetAddresses() const; 218 node()219 interfaces::Node& node() const { return m_node; } wallet()220 interfaces::Wallet& wallet() const { return *m_wallet; } 221 222 QString getWalletName() const; 223 QString getDisplayName() const; 224 225 bool isMultiwallet(); 226 getAddressTableModel()227 AddressTableModel* getAddressTableModel() const { return addressTableModel; } 228 private: 229 std::unique_ptr<interfaces::Wallet> m_wallet; 230 std::unique_ptr<interfaces::Handler> m_handler_unload; 231 std::unique_ptr<interfaces::Handler> m_handler_status_changed; 232 std::unique_ptr<interfaces::Handler> m_handler_address_book_changed; 233 std::unique_ptr<interfaces::Handler> m_handler_transaction_changed; 234 std::unique_ptr<interfaces::Handler> m_handler_show_progress; 235 std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed; 236 std::unique_ptr<interfaces::Handler> m_handler_can_get_addrs_changed; 237 interfaces::Node& m_node; 238 239 bool fHaveWatchOnly; 240 bool fForceCheckBalanceChanged{false}; 241 242 // Wallet has an options model for wallet-specific options 243 // (transaction fee, for example) 244 OptionsModel *optionsModel; 245 246 AddressTableModel *addressTableModel; 247 TransactionTableModel *transactionTableModel; 248 RecentRequestsTableModel *recentRequestsTableModel; 249 250 // Cache some values to be able to detect changes 251 interfaces::WalletBalances m_cached_balances; 252 EncryptionStatus cachedEncryptionStatus; 253 int cachedNumBlocks; 254 255 QTimer *pollTimer; 256 257 void subscribeToCoreSignals(); 258 void unsubscribeFromCoreSignals(); 259 void checkBalanceChanged(const interfaces::WalletBalances& new_balances); 260 261 Q_SIGNALS: 262 // Signal that balance in wallet changed 263 void balanceChanged(const interfaces::WalletBalances& balances); 264 265 // Encryption status of wallet changed 266 void encryptionStatusChanged(); 267 268 // Signal emitted when wallet needs to be unlocked 269 // It is valid behaviour for listeners to keep the wallet locked after this signal; 270 // this means that the unlocking failed or was cancelled. 271 void requireUnlock(); 272 273 // Fired when a message should be reported to the user 274 void message(const QString &title, const QString &message, unsigned int style); 275 276 // Coins sent: from wallet, to recipient, in (serialized) transaction: 277 void coinsSent(WalletModel* wallet, SendCoinsRecipient recipient, QByteArray transaction); 278 279 // Show progress dialog e.g. for rescan 280 void showProgress(const QString &title, int nProgress); 281 282 // Watch-only address added 283 void notifyWatchonlyChanged(bool fHaveWatchonly); 284 285 // Signal that wallet is about to be removed 286 void unload(); 287 288 // Notify that there are now keys in the keypool 289 void canGetAddressesChanged(); 290 291 public Q_SLOTS: 292 /* Wallet status might have changed */ 293 void updateStatus(); 294 /* New transaction, or transaction changed status */ 295 void updateTransaction(); 296 /* New, updated or removed address book entry */ 297 void updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status); 298 /* Watch-only added */ 299 void updateWatchOnlyFlag(bool fHaveWatchonly); 300 /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ 301 void pollBalanceChanged(); 302 }; 303 304 #endif // BITCOIN_QT_WALLETMODEL_H 305