]>
Commit | Line | Data |
---|---|---|
1 | #include "walletmodel.h" | |
2 | #include "guiconstants.h" | |
3 | #include "optionsmodel.h" | |
4 | #include "addresstablemodel.h" | |
5 | #include "transactiontablemodel.h" | |
6 | ||
7 | #include "headers.h" | |
8 | ||
9 | #include <QTimer> | |
10 | #include <QSet> | |
11 | ||
12 | WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : | |
13 | QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), | |
14 | transactionTableModel(0), | |
15 | cachedBalance(0), cachedUnconfirmedBalance(0), cachedNumTransactions(0), | |
16 | cachedEncryptionStatus(Unencrypted) | |
17 | { | |
18 | // Until signal notifications is built into the bitcoin core, | |
19 | // simply update everything after polling using a timer. | |
20 | QTimer *timer = new QTimer(this); | |
21 | connect(timer, SIGNAL(timeout()), this, SLOT(update())); | |
22 | timer->start(MODEL_UPDATE_DELAY); | |
23 | ||
24 | addressTableModel = new AddressTableModel(wallet, this); | |
25 | transactionTableModel = new TransactionTableModel(wallet, this); | |
26 | } | |
27 | ||
28 | qint64 WalletModel::getBalance() const | |
29 | { | |
30 | return wallet->GetBalance(); | |
31 | } | |
32 | ||
33 | qint64 WalletModel::getUnconfirmedBalance() const | |
34 | { | |
35 | return wallet->GetUnconfirmedBalance(); | |
36 | } | |
37 | ||
38 | int WalletModel::getNumTransactions() const | |
39 | { | |
40 | int numTransactions = 0; | |
41 | CRITICAL_BLOCK(wallet->cs_mapWallet) | |
42 | { | |
43 | numTransactions = wallet->mapWallet.size(); | |
44 | } | |
45 | return numTransactions; | |
46 | } | |
47 | ||
48 | void WalletModel::update() | |
49 | { | |
50 | qint64 newBalance = getBalance(); | |
51 | qint64 newUnconfirmedBalance = getUnconfirmedBalance(); | |
52 | int newNumTransactions = getNumTransactions(); | |
53 | EncryptionStatus newEncryptionStatus = getEncryptionStatus(); | |
54 | ||
55 | if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance) | |
56 | emit balanceChanged(newBalance, newUnconfirmedBalance); | |
57 | ||
58 | if(cachedNumTransactions != newNumTransactions) | |
59 | emit numTransactionsChanged(newNumTransactions); | |
60 | ||
61 | if(cachedEncryptionStatus != newEncryptionStatus) | |
62 | emit encryptionStatusChanged(newEncryptionStatus); | |
63 | ||
64 | cachedBalance = newBalance; | |
65 | cachedUnconfirmedBalance = newUnconfirmedBalance; | |
66 | cachedNumTransactions = newNumTransactions; | |
67 | ||
68 | addressTableModel->update(); | |
69 | } | |
70 | ||
71 | bool WalletModel::validateAddress(const QString &address) | |
72 | { | |
73 | CBitcoinAddress addressParsed(address.toStdString()); | |
74 | return addressParsed.IsValid(); | |
75 | } | |
76 | ||
77 | WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients) | |
78 | { | |
79 | qint64 total = 0; | |
80 | QSet<QString> setAddress; | |
81 | QString hex; | |
82 | ||
83 | if(recipients.empty()) | |
84 | { | |
85 | return OK; | |
86 | } | |
87 | ||
88 | // Pre-check input data for validity | |
89 | foreach(const SendCoinsRecipient &rcp, recipients) | |
90 | { | |
91 | if(!validateAddress(rcp.address)) | |
92 | { | |
93 | return InvalidAddress; | |
94 | } | |
95 | setAddress.insert(rcp.address); | |
96 | ||
97 | if(rcp.amount <= 0) | |
98 | { | |
99 | return InvalidAmount; | |
100 | } | |
101 | total += rcp.amount; | |
102 | } | |
103 | ||
104 | if(recipients.size() > setAddress.size()) | |
105 | { | |
106 | return DuplicateAddress; | |
107 | } | |
108 | ||
109 | if(total > getBalance()) | |
110 | { | |
111 | return AmountExceedsBalance; | |
112 | } | |
113 | ||
114 | if((total + nTransactionFee) > getBalance()) | |
115 | { | |
116 | return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); | |
117 | } | |
118 | ||
119 | CRITICAL_BLOCK(cs_main) | |
120 | CRITICAL_BLOCK(wallet->cs_mapWallet) | |
121 | { | |
122 | // Sendmany | |
123 | std::vector<std::pair<CScript, int64> > vecSend; | |
124 | foreach(const SendCoinsRecipient &rcp, recipients) | |
125 | { | |
126 | CScript scriptPubKey; | |
127 | scriptPubKey.SetBitcoinAddress(rcp.address.toStdString()); | |
128 | vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); | |
129 | } | |
130 | ||
131 | CWalletTx wtx; | |
132 | CReserveKey keyChange(wallet); | |
133 | int64 nFeeRequired = 0; | |
134 | bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); | |
135 | ||
136 | if(!fCreated) | |
137 | { | |
138 | if((total + nFeeRequired) > wallet->GetBalance()) | |
139 | { | |
140 | return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); | |
141 | } | |
142 | return TransactionCreationFailed; | |
143 | } | |
144 | if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString(), NULL)) | |
145 | { | |
146 | return Aborted; | |
147 | } | |
148 | if(!wallet->CommitTransaction(wtx, keyChange)) | |
149 | { | |
150 | return TransactionCommitFailed; | |
151 | } | |
152 | hex = QString::fromStdString(wtx.GetHash().GetHex()); | |
153 | } | |
154 | ||
155 | // Add addresses that we've sent to to the address book | |
156 | foreach(const SendCoinsRecipient &rcp, recipients) | |
157 | { | |
158 | std::string strAddress = rcp.address.toStdString(); | |
159 | CRITICAL_BLOCK(wallet->cs_mapAddressBook) | |
160 | { | |
161 | if (!wallet->mapAddressBook.count(strAddress)) | |
162 | wallet->SetAddressBookName(strAddress, rcp.label.toStdString()); | |
163 | } | |
164 | } | |
165 | ||
166 | // Update our model of the address table | |
167 | addressTableModel->updateList(); | |
168 | ||
169 | return SendCoinsReturn(OK, 0, hex); | |
170 | } | |
171 | ||
172 | OptionsModel *WalletModel::getOptionsModel() | |
173 | { | |
174 | return optionsModel; | |
175 | } | |
176 | ||
177 | AddressTableModel *WalletModel::getAddressTableModel() | |
178 | { | |
179 | return addressTableModel; | |
180 | } | |
181 | ||
182 | TransactionTableModel *WalletModel::getTransactionTableModel() | |
183 | { | |
184 | return transactionTableModel; | |
185 | } | |
186 | ||
187 | WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const | |
188 | { | |
189 | if(!wallet->IsCrypted()) | |
190 | { | |
191 | return Unencrypted; | |
192 | } | |
193 | else if(wallet->IsLocked()) | |
194 | { | |
195 | return Locked; | |
196 | } | |
197 | else | |
198 | { | |
199 | return Unlocked; | |
200 | } | |
201 | } |