1 #include "walletmodel.h"
2 #include "guiconstants.h"
3 #include "optionsmodel.h"
4 #include "addresstablemodel.h"
5 #include "transactiontablemodel.h"
13 WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
14 QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
15 transactionTableModel(0),
16 cachedBalance(0), cachedUnconfirmedBalance(0), cachedNumTransactions(0),
17 cachedEncryptionStatus(Unencrypted)
19 // Until signal notifications is built into the bitcoin core,
20 // simply update everything after polling using a timer.
21 QTimer *timer = new QTimer(this);
22 connect(timer, SIGNAL(timeout()), this, SLOT(update()));
23 timer->start(MODEL_UPDATE_DELAY);
25 addressTableModel = new AddressTableModel(wallet, this);
26 transactionTableModel = new TransactionTableModel(wallet, this);
29 qint64 WalletModel::getBalance() const
31 return wallet->GetBalance();
34 qint64 WalletModel::getUnconfirmedBalance() const
36 return wallet->GetUnconfirmedBalance();
39 int WalletModel::getNumTransactions() const
41 int numTransactions = 0;
42 CRITICAL_BLOCK(wallet->cs_wallet)
44 numTransactions = wallet->mapWallet.size();
46 return numTransactions;
49 void WalletModel::update()
51 qint64 newBalance = getBalance();
52 qint64 newUnconfirmedBalance = getUnconfirmedBalance();
53 int newNumTransactions = getNumTransactions();
54 EncryptionStatus newEncryptionStatus = getEncryptionStatus();
56 if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance)
57 emit balanceChanged(newBalance, newUnconfirmedBalance);
59 if(cachedNumTransactions != newNumTransactions)
60 emit numTransactionsChanged(newNumTransactions);
62 if(cachedEncryptionStatus != newEncryptionStatus)
63 emit encryptionStatusChanged(newEncryptionStatus);
65 cachedBalance = newBalance;
66 cachedUnconfirmedBalance = newUnconfirmedBalance;
67 cachedNumTransactions = newNumTransactions;
69 addressTableModel->update();
72 bool WalletModel::validateAddress(const QString &address)
74 CBitcoinAddress addressParsed(address.toStdString());
75 return addressParsed.IsValid();
78 WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients)
81 QSet<QString> setAddress;
84 if(recipients.empty())
89 // Pre-check input data for validity
90 foreach(const SendCoinsRecipient &rcp, recipients)
92 if(!validateAddress(rcp.address))
94 return InvalidAddress;
96 setAddress.insert(rcp.address);
100 return InvalidAmount;
105 if(recipients.size() > setAddress.size())
107 return DuplicateAddress;
110 if(total > getBalance())
112 return AmountExceedsBalance;
115 if((total + nTransactionFee) > getBalance())
117 return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
120 CRITICAL_BLOCK(cs_main)
121 CRITICAL_BLOCK(wallet->cs_wallet)
124 std::vector<std::pair<CScript, qint64> > vecSend;
125 foreach(const SendCoinsRecipient &rcp, recipients)
127 CScript scriptPubKey;
128 scriptPubKey.SetBitcoinAddress(rcp.address.toStdString());
129 vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
133 CReserveKey keyChange(wallet);
134 qint64 nFeeRequired = 0;
135 bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
139 if((total + nFeeRequired) > wallet->GetBalance())
141 return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
143 return TransactionCreationFailed;
145 if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString(), NULL))
149 if(!wallet->CommitTransaction(wtx, keyChange))
151 return TransactionCommitFailed;
153 hex = QString::fromStdString(wtx.GetHash().GetHex());
156 // Add addresses that we've sent to to the address book
157 foreach(const SendCoinsRecipient &rcp, recipients)
159 std::string strAddress = rcp.address.toStdString();
160 CRITICAL_BLOCK(wallet->cs_wallet)
162 if (!wallet->mapAddressBook.count(strAddress))
163 wallet->SetAddressBookName(strAddress, rcp.label.toStdString());
167 // Update our model of the address table
168 addressTableModel->updateList();
170 return SendCoinsReturn(OK, 0, hex);
173 OptionsModel *WalletModel::getOptionsModel()
178 AddressTableModel *WalletModel::getAddressTableModel()
180 return addressTableModel;
183 TransactionTableModel *WalletModel::getTransactionTableModel()
185 return transactionTableModel;
188 WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
190 if(!wallet->IsCrypted())
194 else if(wallet->IsLocked())
204 bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
209 return wallet->EncryptWallet(passphrase);
213 // Decrypt -- TODO; not supported yet
218 bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
223 return wallet->Lock();
228 return wallet->Unlock(passPhrase);
232 bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
235 CRITICAL_BLOCK(wallet->cs_wallet)
237 wallet->Lock(); // Make sure wallet is locked before attempting pass change
238 retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
243 // WalletModel::UnlockContext implementation
244 WalletModel::UnlockContext WalletModel::requestUnlock()
246 bool was_locked = getEncryptionStatus() == Locked;
249 // Request UI to unlock wallet
250 emit requireUnlock();
252 // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
253 bool valid = getEncryptionStatus() != Locked;
255 return UnlockContext(this, valid, was_locked);
258 WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
265 WalletModel::UnlockContext::~UnlockContext()
269 wallet->setWalletLocked(true);
273 void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
275 // Transfer context; old object no longer relocks wallet