]>
Commit | Line | Data |
---|---|---|
ef079e18 WL |
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> | |
a5e6d723 | 10 | #include <QSet> |
ef079e18 | 11 | |
ee014e5b WL |
12 | WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : |
13 | QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), | |
5df0b03c | 14 | transactionTableModel(0), |
ae8adeb9 WL |
15 | cachedBalance(0), cachedUnconfirmedBalance(0), cachedNumTransactions(0), |
16 | cachedEncryptionStatus(Unencrypted) | |
ef079e18 WL |
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 | ||
ef079e18 WL |
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 | ||
df5ccbd2 WL |
33 | qint64 WalletModel::getUnconfirmedBalance() const |
34 | { | |
35 | return wallet->GetUnconfirmedBalance(); | |
36 | } | |
37 | ||
ef079e18 WL |
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 | { | |
5df0b03c WL |
50 | qint64 newBalance = getBalance(); |
51 | qint64 newUnconfirmedBalance = getUnconfirmedBalance(); | |
52 | int newNumTransactions = getNumTransactions(); | |
ae8adeb9 | 53 | EncryptionStatus newEncryptionStatus = getEncryptionStatus(); |
5df0b03c WL |
54 | |
55 | if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance) | |
56 | emit balanceChanged(newBalance, newUnconfirmedBalance); | |
57 | ||
58 | if(cachedNumTransactions != newNumTransactions) | |
59 | emit numTransactionsChanged(newNumTransactions); | |
60 | ||
ae8adeb9 WL |
61 | if(cachedEncryptionStatus != newEncryptionStatus) |
62 | emit encryptionStatusChanged(newEncryptionStatus); | |
63 | ||
5df0b03c WL |
64 | cachedBalance = newBalance; |
65 | cachedUnconfirmedBalance = newUnconfirmedBalance; | |
66 | cachedNumTransactions = newNumTransactions; | |
ef079e18 WL |
67 | |
68 | addressTableModel->update(); | |
69 | } | |
70 | ||
a5e6d723 | 71 | bool WalletModel::validateAddress(const QString &address) |
ef079e18 | 72 | { |
491ad6db WL |
73 | CBitcoinAddress addressParsed(address.toStdString()); |
74 | return addressParsed.IsValid(); | |
a5e6d723 WL |
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()) | |
ef079e18 | 84 | { |
a5e6d723 | 85 | return OK; |
ef079e18 WL |
86 | } |
87 | ||
a5e6d723 WL |
88 | // Pre-check input data for validity |
89 | foreach(const SendCoinsRecipient &rcp, recipients) | |
ef079e18 | 90 | { |
491ad6db | 91 | if(!validateAddress(rcp.address)) |
a5e6d723 WL |
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; | |
ef079e18 WL |
102 | } |
103 | ||
a5e6d723 WL |
104 | if(recipients.size() > setAddress.size()) |
105 | { | |
106 | return DuplicateAddress; | |
107 | } | |
108 | ||
109 | if(total > getBalance()) | |
ef079e18 WL |
110 | { |
111 | return AmountExceedsBalance; | |
112 | } | |
113 | ||
a5e6d723 | 114 | if((total + nTransactionFee) > getBalance()) |
ef079e18 | 115 | { |
a5e6d723 | 116 | return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); |
ef079e18 WL |
117 | } |
118 | ||
119 | CRITICAL_BLOCK(cs_main) | |
a5e6d723 | 120 | CRITICAL_BLOCK(wallet->cs_mapWallet) |
ef079e18 | 121 | { |
a5e6d723 WL |
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 | ||
ef079e18 | 131 | CWalletTx wtx; |
a5e6d723 WL |
132 | CReserveKey keyChange(wallet); |
133 | int64 nFeeRequired = 0; | |
134 | bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); | |
ef079e18 | 135 | |
a5e6d723 | 136 | if(!fCreated) |
ef079e18 | 137 | { |
a5e6d723 WL |
138 | if((total + nFeeRequired) > wallet->GetBalance()) |
139 | { | |
140 | return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); | |
141 | } | |
142 | return TransactionCreationFailed; | |
ef079e18 | 143 | } |
a5e6d723 | 144 | if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString(), NULL)) |
ef079e18 WL |
145 | { |
146 | return Aborted; | |
147 | } | |
a5e6d723 | 148 | if(!wallet->CommitTransaction(wtx, keyChange)) |
ef079e18 | 149 | { |
a5e6d723 | 150 | return TransactionCommitFailed; |
ef079e18 | 151 | } |
a5e6d723 | 152 | hex = QString::fromStdString(wtx.GetHash().GetHex()); |
ef079e18 WL |
153 | } |
154 | ||
155 | // Add addresses that we've sent to to the address book | |
a5e6d723 | 156 | foreach(const SendCoinsRecipient &rcp, recipients) |
ef079e18 | 157 | { |
a5e6d723 WL |
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 | } | |
ef079e18 | 164 | } |
a5e13258 WL |
165 | |
166 | // Update our model of the address table | |
f0ec774d | 167 | addressTableModel->updateList(); |
ef079e18 | 168 | |
a5e6d723 | 169 | return SendCoinsReturn(OK, 0, hex); |
ef079e18 WL |
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 | } | |
ebff5c40 | 186 | |
ae8adeb9 WL |
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 | } |