diff options
Diffstat (limited to 'src/qt/walletmodel.cpp')
-rw-r--r-- | src/qt/walletmodel.cpp | 188 |
1 files changed, 128 insertions, 60 deletions
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index fb3ffc5c91..417bac9928 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -5,12 +5,12 @@ #include "transactiontablemodel.h" #include "ui_interface.h" -#include "wallet.h" #include "walletdb.h" // for BackupWallet #include "base58.h" #include <QSet> #include <QTimer> +#include <QDebug> WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), @@ -73,10 +73,10 @@ void WalletModel::updateStatus() void WalletModel::pollBalanceChanged() { - if(nBestHeight != cachedNumBlocks) + if(chainActive.Height() != cachedNumBlocks) { // Balance and number of transactions might have changed - cachedNumBlocks = nBestHeight; + cachedNumBlocks = chainActive.Height(); checkBalanceChanged(); } } @@ -112,10 +112,11 @@ void WalletModel::updateTransaction(const QString &hash, int status) } } -void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status) +void WalletModel::updateAddressBook(const QString &address, const QString &label, + bool isMine, const QString &purpose, int status) { if(addressTableModel) - addressTableModel->updateEntry(address, label, isMine, status); + addressTableModel->updateEntry(address, label, isMine, purpose, status); } bool WalletModel::validateAddress(const QString &address) @@ -124,34 +125,63 @@ bool WalletModel::validateAddress(const QString &address) return addressParsed.IsValid(); } -WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients) +WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction) { qint64 total = 0; - QSet<QString> setAddress; - QString hex; + QList<SendCoinsRecipient> recipients = transaction.getRecipients(); + std::vector<std::pair<CScript, int64> > vecSend; if(recipients.empty()) { return OK; } + QSet<QString> setAddress; // Used to detect duplicates + int nAddresses = 0; + // Pre-check input data for validity foreach(const SendCoinsRecipient &rcp, recipients) { - if(!validateAddress(rcp.address)) - { - return InvalidAddress; + if (rcp.paymentRequest.IsInitialized()) + { // PaymentRequest... + int64 subtotal = 0; + const payments::PaymentDetails& details = rcp.paymentRequest.getDetails(); + for (int i = 0; i < details.outputs_size(); i++) + { + const payments::Output& out = details.outputs(i); + if (out.amount() <= 0) continue; + subtotal += out.amount(); + const unsigned char* scriptStr = (const unsigned char*)out.script().data(); + CScript scriptPubKey(scriptStr, scriptStr+out.script().size()); + vecSend.push_back(std::pair<CScript, int64>(scriptPubKey, out.amount())); + } + if (subtotal <= 0) + { + return InvalidAmount; + } + total += subtotal; } - setAddress.insert(rcp.address); + else + { // User-entered bitcoin address / amount: + if(!validateAddress(rcp.address)) + { + return InvalidAddress; + } + if(rcp.amount <= 0) + { + return InvalidAmount; + } + setAddress.insert(rcp.address); + ++nAddresses; - if(rcp.amount <= 0) - { - return InvalidAmount; + CScript scriptPubKey; + scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); + vecSend.push_back(std::pair<CScript, int64>(scriptPubKey, rcp.amount)); + + total += rcp.amount; } - total += rcp.amount; } - - if(recipients.size() > setAddress.size()) + if(setAddress.size() != nAddresses) { return DuplicateAddress; } @@ -163,68 +193,97 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie if((total + nTransactionFee) > getBalance()) { - return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); + transaction.setTransactionFee(nTransactionFee); + return SendCoinsReturn(AmountWithFeeExceedsBalance); } { LOCK2(cs_main, wallet->cs_wallet); - // Sendmany - std::vector<std::pair<CScript, int64> > vecSend; - foreach(const SendCoinsRecipient &rcp, recipients) - { - CScript scriptPubKey; - scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); - vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); - } - - CWalletTx wtx; - CReserveKey keyChange(wallet); + transaction.newPossibleKeyChange(wallet); int64 nFeeRequired = 0; std::string strFailReason; - bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); + + CWalletTx *newTx = transaction.getTransaction(); + CReserveKey *keyChange = transaction.getPossibleKeyChange(); + bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, strFailReason); + transaction.setTransactionFee(nFeeRequired); if(!fCreated) { if((total + nFeeRequired) > wallet->GetBalance()) { - return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); + return SendCoinsReturn(AmountWithFeeExceedsBalance); } emit message(tr("Send Coins"), QString::fromStdString(strFailReason), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } - if(!uiInterface.ThreadSafeAskFee(nFeeRequired)) + } + + return SendCoinsReturn(OK); +} + +WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction) +{ + QByteArray transaction_array; /* store serialized transaction */ + + { + LOCK2(cs_main, wallet->cs_wallet); + CWalletTx *newTx = transaction.getTransaction(); + + // Store PaymentRequests in wtx.vOrderForm in wallet. + foreach(const SendCoinsRecipient &rcp, transaction.getRecipients()) { - return Aborted; + if (rcp.paymentRequest.IsInitialized()) + { + std::string key("PaymentRequest"); + std::string value; + rcp.paymentRequest.SerializeToString(&value); + newTx->vOrderForm.push_back(make_pair(key, value)); + } } - if(!wallet->CommitTransaction(wtx, keyChange)) - { + + CReserveKey *keyChange = transaction.getPossibleKeyChange(); + if(!wallet->CommitTransaction(*newTx, *keyChange)) return TransactionCommitFailed; - } - hex = QString::fromStdString(wtx.GetHash().GetHex()); + + CTransaction* t = (CTransaction*)newTx; + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << *t; + transaction_array.append(&(ssTx[0]), ssTx.size()); } - // Add addresses / update labels that we've sent to to the address book - foreach(const SendCoinsRecipient &rcp, recipients) + // Add addresses / update labels that we've sent to to the address book, + // and emit coinsSent signal for each recipient + foreach(const SendCoinsRecipient &rcp, transaction.getRecipients()) { - std::string strAddress = rcp.address.toStdString(); - CTxDestination dest = CBitcoinAddress(strAddress).Get(); - std::string strLabel = rcp.label.toStdString(); + // Don't touch the address book when we have a secure payment-request + if (rcp.authenticatedMerchant.isEmpty()) { - LOCK(wallet->cs_wallet); - - std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(dest); - - // Check if we have a new address or an updated label - if (mi == wallet->mapAddressBook.end() || mi->second != strLabel) + std::string strAddress = rcp.address.toStdString(); + CTxDestination dest = CBitcoinAddress(strAddress).Get(); + std::string strLabel = rcp.label.toStdString(); { - wallet->SetAddressBookName(dest, strLabel); + LOCK(wallet->cs_wallet); + + std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest); + + // Check if we have a new address or an updated label + if (mi == wallet->mapAddressBook.end()) + { + wallet->SetAddressBook(dest, strLabel, "send"); + } + else if (mi->second.name != strLabel) + { + wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose + } } } + emit coinsSent(wallet, rcp, transaction_array); } - return SendCoinsReturn(OK, 0, hex); + return SendCoinsReturn(OK); } OptionsModel *WalletModel::getOptionsModel() @@ -305,25 +364,34 @@ bool WalletModel::backupWallet(const QString &filename) // Handlers for core signals static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet) { - OutputDebugStringF("NotifyKeyStoreStatusChanged\n"); + qDebug() << "NotifyKeyStoreStatusChanged"; QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection); } -static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status) +static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, + const CTxDestination &address, const std::string &label, bool isMine, + const std::string &purpose, ChangeType status) { - OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, status); + QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString()); + QString strLabel = QString::fromStdString(label); + QString strPurpose = QString::fromStdString(purpose); + + qDebug() << "NotifyAddressBookChanged : " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status); QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())), - Q_ARG(QString, QString::fromStdString(label)), + Q_ARG(QString, strAddress), + Q_ARG(QString, strLabel), Q_ARG(bool, isMine), + Q_ARG(QString, strPurpose), Q_ARG(int, status)); } static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status) { - OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status); + QString strHash = QString::fromStdString(hash.GetHex()); + + qDebug() << "NotifyTransactionChanged : " + strHash + " status= " + QString::number(status); QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(hash.GetHex())), + Q_ARG(QString, strHash), Q_ARG(int, status)); } @@ -331,7 +399,7 @@ void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); - wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5)); + wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); } @@ -339,7 +407,7 @@ void WalletModel::unsubscribeFromCoreSignals() { // Disconnect signals from wallet wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); - wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5)); + wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); } |