Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F12944898
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
32 KB
Subscribers
None
View Options
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 0ad123f39..c5f8fb6a9 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -1,665 +1,645 @@
// Copyright (c) 2011-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "walletmodel.h"
#include "addresstablemodel.h"
#include "guiconstants.h"
#include "recentrequeststablemodel.h"
#include "transactiontablemodel.h"
#include "base58.h"
#include "db.h"
#include "keystore.h"
#include "main.h"
#include "sync.h"
#include "ui_interface.h"
#include "wallet.h"
#include "walletdb.h" // for BackupWallet
#include <stdint.h>
#include <QDebug>
#include <QSet>
#include <QTimer>
using namespace std;
WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
transactionTableModel(0),
recentRequestsTableModel(0),
cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
- cachedNumTransactions(0),
cachedEncryptionStatus(Unencrypted),
cachedNumBlocks(0)
{
fProcessingQueuedTransactions = false;
addressTableModel = new AddressTableModel(wallet, this);
transactionTableModel = new TransactionTableModel(wallet, this);
recentRequestsTableModel = new RecentRequestsTableModel(wallet, this);
// This timer will be fired repeatedly to update the balance
pollTimer = new QTimer(this);
connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged()));
pollTimer->start(MODEL_UPDATE_DELAY);
subscribeToCoreSignals();
}
WalletModel::~WalletModel()
{
unsubscribeFromCoreSignals();
}
qint64 WalletModel::getBalance(const CCoinControl *coinControl) const
{
if (coinControl)
{
qint64 nBalance = 0;
std::vector<COutput> vCoins;
wallet->AvailableCoins(vCoins, true, coinControl);
BOOST_FOREACH(const COutput& out, vCoins)
if(out.fSpendable)
nBalance += out.tx->vout[out.i].nValue;
return nBalance;
}
return wallet->GetBalance();
}
qint64 WalletModel::getUnconfirmedBalance() const
{
return wallet->GetUnconfirmedBalance();
}
qint64 WalletModel::getImmatureBalance() const
{
return wallet->GetImmatureBalance();
}
qint64 WalletModel::getWatchBalance() const
{
return wallet->GetWatchOnlyBalance();
}
qint64 WalletModel::getWatchUnconfirmedBalance() const
{
return wallet->GetUnconfirmedWatchOnlyBalance();
}
qint64 WalletModel::getWatchImmatureBalance() const
{
return wallet->GetImmatureWatchOnlyBalance();
}
-int WalletModel::getNumTransactions() const
-{
- int numTransactions = 0;
- {
- LOCK(wallet->cs_wallet);
- // the size of mapWallet contains the number of unique transaction IDs
- // (e.g. payments to yourself generate 2 transactions, but both share the same transaction ID)
- numTransactions = wallet->mapWallet.size();
- }
- return numTransactions;
-}
-
void WalletModel::updateStatus()
{
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
if(cachedEncryptionStatus != newEncryptionStatus)
emit encryptionStatusChanged(newEncryptionStatus);
}
void WalletModel::pollBalanceChanged()
{
// Get required locks upfront. This avoids the GUI from getting stuck on
// periodical polls if the core is holding the locks for a longer time -
// for example, during a wallet rescan.
TRY_LOCK(cs_main, lockMain);
if(!lockMain)
return;
TRY_LOCK(wallet->cs_wallet, lockWallet);
if(!lockWallet)
return;
if(chainActive.Height() != cachedNumBlocks)
{
// Balance and number of transactions might have changed
cachedNumBlocks = chainActive.Height();
checkBalanceChanged();
if(transactionTableModel)
transactionTableModel->updateConfirmations();
}
}
void WalletModel::checkBalanceChanged()
{
qint64 newBalance = getBalance();
qint64 newUnconfirmedBalance = getUnconfirmedBalance();
qint64 newImmatureBalance = getImmatureBalance();
qint64 newWatchOnlyBalance = getWatchBalance();
qint64 newWatchUnconfBalance = getWatchUnconfirmedBalance();
qint64 newWatchImmatureBalance = getWatchImmatureBalance();
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance ||
cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance)
{
cachedBalance = newBalance;
cachedUnconfirmedBalance = newUnconfirmedBalance;
cachedImmatureBalance = newImmatureBalance;
cachedWatchOnlyBalance = newWatchOnlyBalance;
cachedWatchUnconfBalance = newWatchUnconfBalance;
cachedWatchImmatureBalance = newWatchImmatureBalance;
emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance);
}
}
void WalletModel::updateTransaction(const QString &hash, int status)
{
if(transactionTableModel)
transactionTableModel->updateTransaction(hash, status);
// Balance and number of transactions might have changed
checkBalanceChanged();
-
- int newNumTransactions = getNumTransactions();
- if(cachedNumTransactions != newNumTransactions)
- {
- cachedNumTransactions = newNumTransactions;
- emit numTransactionsChanged(newNumTransactions);
- }
}
void WalletModel::updateAddressBook(const QString &address, const QString &label,
bool isMine, const QString &purpose, int status)
{
if(addressTableModel)
addressTableModel->updateEntry(address, label, isMine, purpose, status);
}
bool WalletModel::validateAddress(const QString &address)
{
CBitcoinAddress addressParsed(address.toStdString());
return addressParsed.IsValid();
}
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl)
{
qint64 total = 0;
QList<SendCoinsRecipient> recipients = transaction.getRecipients();
std::vector<std::pair<CScript, int64_t> > 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 (rcp.paymentRequest.IsInitialized())
{ // PaymentRequest...
int64_t 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_t>(scriptPubKey, out.amount()));
}
if (subtotal <= 0)
{
return InvalidAmount;
}
total += subtotal;
}
else
{ // User-entered bitcoin address / amount:
if(!validateAddress(rcp.address))
{
return InvalidAddress;
}
if(rcp.amount <= 0)
{
return InvalidAmount;
}
setAddress.insert(rcp.address);
++nAddresses;
CScript scriptPubKey;
scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
vecSend.push_back(std::pair<CScript, int64_t>(scriptPubKey, rcp.amount));
total += rcp.amount;
}
}
if(setAddress.size() != nAddresses)
{
return DuplicateAddress;
}
qint64 nBalance = getBalance(coinControl);
if(total > nBalance)
{
return AmountExceedsBalance;
}
{
LOCK2(cs_main, wallet->cs_wallet);
transaction.newPossibleKeyChange(wallet);
int64_t nFeeRequired = 0;
std::string strFailReason;
CWalletTx *newTx = transaction.getTransaction();
CReserveKey *keyChange = transaction.getPossibleKeyChange();
bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, strFailReason, coinControl);
transaction.setTransactionFee(nFeeRequired);
if(!fCreated)
{
if((total + nFeeRequired) > nBalance)
{
return SendCoinsReturn(AmountWithFeeExceedsBalance);
}
emit message(tr("Send Coins"), QString::fromStdString(strFailReason),
CClientUIInterface::MSG_ERROR);
return TransactionCreationFailed;
}
}
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())
{
if (rcp.paymentRequest.IsInitialized())
{
std::string key("PaymentRequest");
std::string value;
rcp.paymentRequest.SerializeToString(&value);
newTx->vOrderForm.push_back(make_pair(key, value));
}
else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString()));
}
CReserveKey *keyChange = transaction.getPossibleKeyChange();
if(!wallet->CommitTransaction(*newTx, *keyChange))
return TransactionCommitFailed;
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,
// and emit coinsSent signal for each recipient
foreach(const SendCoinsRecipient &rcp, transaction.getRecipients())
{
// Don't touch the address book when we have a payment request
if (!rcp.paymentRequest.IsInitialized())
{
std::string strAddress = rcp.address.toStdString();
CTxDestination dest = CBitcoinAddress(strAddress).Get();
std::string strLabel = rcp.label.toStdString();
{
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);
}
OptionsModel *WalletModel::getOptionsModel()
{
return optionsModel;
}
AddressTableModel *WalletModel::getAddressTableModel()
{
return addressTableModel;
}
TransactionTableModel *WalletModel::getTransactionTableModel()
{
return transactionTableModel;
}
RecentRequestsTableModel *WalletModel::getRecentRequestsTableModel()
{
return recentRequestsTableModel;
}
WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
if(!wallet->IsCrypted())
{
return Unencrypted;
}
else if(wallet->IsLocked())
{
return Locked;
}
else
{
return Unlocked;
}
}
bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
{
if(encrypted)
{
// Encrypt
return wallet->EncryptWallet(passphrase);
}
else
{
// Decrypt -- TODO; not supported yet
return false;
}
}
bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
{
if(locked)
{
// Lock
return wallet->Lock();
}
else
{
// Unlock
return wallet->Unlock(passPhrase);
}
}
bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
{
bool retval;
{
LOCK(wallet->cs_wallet);
wallet->Lock(); // Make sure wallet is locked before attempting pass change
retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
}
return retval;
}
bool WalletModel::backupWallet(const QString &filename)
{
return BackupWallet(*wallet, filename.toLocal8Bit().data());
}
// Handlers for core signals
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
{
qDebug() << "NotifyKeyStoreStatusChanged";
QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
}
static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
const CTxDestination &address, const std::string &label, bool isMine,
const std::string &purpose, ChangeType 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, strAddress),
Q_ARG(QString, strLabel),
Q_ARG(bool, isMine),
Q_ARG(QString, strPurpose),
Q_ARG(int, status));
}
// queue notifications to show a non freezing progress dialog e.g. for rescan
static bool fQueueNotifications = false;
static std::vector<std::pair<uint256, ChangeType> > vQueueNotifications;
static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
{
if (fQueueNotifications)
{
vQueueNotifications.push_back(make_pair(hash, status));
return;
}
QString strHash = QString::fromStdString(hash.GetHex());
qDebug() << "NotifyTransactionChanged : " + strHash + " status= " + QString::number(status);
QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
Q_ARG(QString, strHash),
Q_ARG(int, status));
}
static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress)
{
// emits signal "showProgress"
QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(title)),
Q_ARG(int, nProgress));
if (nProgress == 0)
fQueueNotifications = true;
if (nProgress == 100)
{
fQueueNotifications = false;
if (vQueueNotifications.size() > 10) // prevent balloon spam, show maximum 10 balloons
QMetaObject::invokeMethod(walletmodel, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
{
if (vQueueNotifications.size() - i <= 10)
QMetaObject::invokeMethod(walletmodel, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
NotifyTransactionChanged(walletmodel, NULL, vQueueNotifications[i].first, vQueueNotifications[i].second);
}
std::vector<std::pair<uint256, ChangeType> >().swap(vQueueNotifications); // clear
}
}
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, _6));
wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
}
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, _6));
wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
}
// WalletModel::UnlockContext implementation
WalletModel::UnlockContext WalletModel::requestUnlock()
{
bool was_locked = getEncryptionStatus() == Locked;
if(was_locked)
{
// Request UI to unlock wallet
emit requireUnlock();
}
// If wallet is still locked, unlock was failed or cancelled, mark context as invalid
bool valid = getEncryptionStatus() != Locked;
return UnlockContext(this, valid, was_locked);
}
WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
wallet(wallet),
valid(valid),
relock(relock)
{
}
WalletModel::UnlockContext::~UnlockContext()
{
if(valid && relock)
{
wallet->setWalletLocked(true);
}
}
void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
{
// Transfer context; old object no longer relocks wallet
*this = rhs;
rhs.relock = false;
}
bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
return wallet->GetPubKey(address, vchPubKeyOut);
}
// returns a list of COutputs from COutPoints
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
LOCK2(cs_main, wallet->cs_wallet);
BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
{
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
vOutputs.push_back(out);
}
}
bool WalletModel::isSpent(const COutPoint& outpoint) const
{
LOCK2(cs_main, wallet->cs_wallet);
return wallet->IsSpent(outpoint.hash, outpoint.n);
}
// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
std::vector<COutput> vCoins;
wallet->AvailableCoins(vCoins);
LOCK2(cs_main, wallet->cs_wallet); // ListLockedCoins, mapWallet
std::vector<COutPoint> vLockedCoins;
wallet->ListLockedCoins(vLockedCoins);
// add locked coins
BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
{
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
vCoins.push_back(out);
}
BOOST_FOREACH(const COutput& out, vCoins)
{
COutput cout = out;
while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
{
if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0, true);
}
CTxDestination address;
if(!out.fSpendable || !ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address))
continue;
mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
}
}
bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
{
LOCK2(cs_main, wallet->cs_wallet);
return wallet->IsLockedCoin(hash, n);
}
void WalletModel::lockCoin(COutPoint& output)
{
LOCK2(cs_main, wallet->cs_wallet);
wallet->LockCoin(output);
}
void WalletModel::unlockCoin(COutPoint& output)
{
LOCK2(cs_main, wallet->cs_wallet);
wallet->UnlockCoin(output);
}
void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
{
LOCK2(cs_main, wallet->cs_wallet);
wallet->ListLockedCoins(vOutpts);
}
void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
{
LOCK(wallet->cs_wallet);
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook)
BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item2, item.second.destdata)
if (item2.first.size() > 2 && item2.first.substr(0,2) == "rr") // receive request
vReceiveRequests.push_back(item2.second);
}
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
{
CTxDestination dest = CBitcoinAddress(sAddress).Get();
std::stringstream ss;
ss << nId;
std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
LOCK(wallet->cs_wallet);
if (sRequest.empty())
return wallet->EraseDestData(dest, key);
else
return wallet->AddDestData(dest, key, sRequest);
}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 2bb91d85a..2a74a6aa7 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -1,265 +1,260 @@
// Copyright (c) 2011-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef WALLETMODEL_H
#define WALLETMODEL_H
#include "paymentrequestplus.h"
#include "walletmodeltransaction.h"
#include "allocators.h" /* for SecureString */
#include <map>
#include <vector>
#include <QObject>
class AddressTableModel;
class OptionsModel;
class RecentRequestsTableModel;
class TransactionTableModel;
class WalletModelTransaction;
class CCoinControl;
class CKeyID;
class COutPoint;
class COutput;
class CPubKey;
class CWallet;
class uint256;
QT_BEGIN_NAMESPACE
class QTimer;
QT_END_NAMESPACE
class SendCoinsRecipient
{
public:
explicit SendCoinsRecipient() : amount(0), nVersion(SendCoinsRecipient::CURRENT_VERSION) { }
explicit SendCoinsRecipient(const QString &addr, const QString &label, quint64 amount, const QString &message):
address(addr), label(label), amount(amount), message(message), nVersion(SendCoinsRecipient::CURRENT_VERSION) {}
// If from an insecure payment request, this is used for storing
// the addresses, e.g. address-A<br />address-B<br />address-C.
// Info: As we don't need to process addresses in here when using
// payment requests, we can abuse it for displaying an address list.
// Todo: This is a hack, should be replaced with a cleaner solution!
QString address;
QString label;
qint64 amount;
// If from a payment request, this is used for storing the memo
QString message;
// If from a payment request, paymentRequest.IsInitialized() will be true
PaymentRequestPlus paymentRequest;
// Empty if no authentication or invalid signature/cert/etc.
QString authenticatedMerchant;
static const int CURRENT_VERSION = 1;
int nVersion;
IMPLEMENT_SERIALIZE
(
SendCoinsRecipient* pthis = const_cast<SendCoinsRecipient*>(this);
std::string sAddress = pthis->address.toStdString();
std::string sLabel = pthis->label.toStdString();
std::string sMessage = pthis->message.toStdString();
std::string sPaymentRequest;
if (!fRead && pthis->paymentRequest.IsInitialized())
pthis->paymentRequest.SerializeToString(&sPaymentRequest);
std::string sAuthenticatedMerchant = pthis->authenticatedMerchant.toStdString();
READWRITE(pthis->nVersion);
nVersion = pthis->nVersion;
READWRITE(sAddress);
READWRITE(sLabel);
READWRITE(amount);
READWRITE(sMessage);
READWRITE(sPaymentRequest);
READWRITE(sAuthenticatedMerchant);
if (fRead)
{
pthis->address = QString::fromStdString(sAddress);
pthis->label = QString::fromStdString(sLabel);
pthis->message = QString::fromStdString(sMessage);
if (!sPaymentRequest.empty())
pthis->paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size()));
pthis->authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant);
}
)
};
/** Interface to Bitcoin wallet from Qt view code. */
class WalletModel : public QObject
{
Q_OBJECT
public:
explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
~WalletModel();
enum StatusCode // Returned by sendCoins
{
OK,
InvalidAmount,
InvalidAddress,
AmountExceedsBalance,
AmountWithFeeExceedsBalance,
DuplicateAddress,
TransactionCreationFailed, // Error returned when wallet is still locked
TransactionCommitFailed
};
enum EncryptionStatus
{
Unencrypted, // !wallet->IsCrypted()
Locked, // wallet->IsCrypted() && wallet->IsLocked()
Unlocked // wallet->IsCrypted() && !wallet->IsLocked()
};
OptionsModel *getOptionsModel();
AddressTableModel *getAddressTableModel();
TransactionTableModel *getTransactionTableModel();
RecentRequestsTableModel *getRecentRequestsTableModel();
qint64 getBalance(const CCoinControl *coinControl = NULL) const;
qint64 getUnconfirmedBalance() const;
qint64 getImmatureBalance() const;
qint64 getWatchBalance() const;
qint64 getWatchUnconfirmedBalance() const;
qint64 getWatchImmatureBalance() const;
- int getNumTransactions() const;
EncryptionStatus getEncryptionStatus() const;
bool processingQueuedTransactions() { return fProcessingQueuedTransactions; }
// Check address for validity
bool validateAddress(const QString &address);
// Return status record for SendCoins, contains error id + information
struct SendCoinsReturn
{
SendCoinsReturn(StatusCode status = OK):
status(status) {}
StatusCode status;
};
// prepare transaction for getting txfee before sending coins
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl = NULL);
// Send coins to a list of recipients
SendCoinsReturn sendCoins(WalletModelTransaction &transaction);
// Wallet encryption
bool setWalletEncrypted(bool encrypted, const SecureString &passphrase);
// Passphrase only needed when unlocking
bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString());
bool changePassphrase(const SecureString &oldPass, const SecureString &newPass);
// Wallet backup
bool backupWallet(const QString &filename);
// RAI object for unlocking wallet, returned by requestUnlock()
class UnlockContext
{
public:
UnlockContext(WalletModel *wallet, bool valid, bool relock);
~UnlockContext();
bool isValid() const { return valid; }
// Copy operator and constructor transfer the context
UnlockContext(const UnlockContext& obj) { CopyFrom(obj); }
UnlockContext& operator=(const UnlockContext& rhs) { CopyFrom(rhs); return *this; }
private:
WalletModel *wallet;
bool valid;
mutable bool relock; // mutable, as it can be set to false by copying
void CopyFrom(const UnlockContext& rhs);
};
UnlockContext requestUnlock();
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs);
bool isSpent(const COutPoint& outpoint) const;
void listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const;
bool isLockedCoin(uint256 hash, unsigned int n) const;
void lockCoin(COutPoint& output);
void unlockCoin(COutPoint& output);
void listLockedCoins(std::vector<COutPoint>& vOutpts);
void loadReceiveRequests(std::vector<std::string>& vReceiveRequests);
bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest);
private:
CWallet *wallet;
bool fProcessingQueuedTransactions;
// Wallet has an options model for wallet-specific options
// (transaction fee, for example)
OptionsModel *optionsModel;
AddressTableModel *addressTableModel;
TransactionTableModel *transactionTableModel;
RecentRequestsTableModel *recentRequestsTableModel;
// Cache some values to be able to detect changes
qint64 cachedBalance;
qint64 cachedUnconfirmedBalance;
qint64 cachedImmatureBalance;
qint64 cachedWatchOnlyBalance;
qint64 cachedWatchUnconfBalance;
qint64 cachedWatchImmatureBalance;
- qint64 cachedNumTransactions;
EncryptionStatus cachedEncryptionStatus;
int cachedNumBlocks;
QTimer *pollTimer;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
void checkBalanceChanged();
signals:
// Signal that balance in wallet changed
void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance,
qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance);
- // Number of transactions in wallet changed
- void numTransactionsChanged(int count);
-
// Encryption status of wallet changed
void encryptionStatusChanged(int status);
// Signal emitted when wallet needs to be unlocked
// It is valid behaviour for listeners to keep the wallet locked after this signal;
// this means that the unlocking failed or was cancelled.
void requireUnlock();
// Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
// Coins sent: from wallet, to recipient, in (serialized) transaction:
void coinsSent(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction);
// Show progress dialog e.g. for rescan
void showProgress(const QString &title, int nProgress);
public slots:
/* Wallet status might have changed */
void updateStatus();
/* New transaction, or transaction changed status */
void updateTransaction(const QString &hash, int status);
/* New, updated or removed address book entry */
void updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status);
/* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */
void pollBalanceChanged();
/* Needed to update fProcessingQueuedTransactions through a QueuedConnection */
void setProcessingQueuedTransactions(bool value) { fProcessingQueuedTransactions = value; }
};
#endif // WALLETMODEL_H
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Feb 7, 16:00 (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5082653
Default Alt Text
(32 KB)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment