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