Fine-grained UI updates
Gets rid of `MainFrameRepaint` in favor of specific update functions that tell the UI exactly what changed. This improves the efficiency of various handlers. Also fixes problems with mined transactions not showing up until restart. The following notifications were added: - `NotifyBlocksChanged`: Block chain changed - `NotifyKeyStoreStatusChanged`: Wallet status (encrypted, locked) changed. - `NotifyAddressBookChanged`: Address book entry changed. - `NotifyTransactionChanged`: Wallet transaction added, removed or updated. - `NotifyNumConnectionsChanged`: Number of connections changed. - `NotifyAlertChanged`: New, updated or cancelled alert. As this finally makes it possible for the UI to know when a new alert arrived, it can be shown as OS notification. These notifications could also be useful for RPC clients. However, currently, they are ignored in bitcoind (in noui.cpp). Also brings back polling with timer for numBlocks in ClientModel. This value updates so frequently during initial download that the number of signals clogs the UI thread and causes heavy CPU usage. And after initial block download, the value changes so rarely that a delay of half a second until the UI updates is unnoticable.
This commit is contained in:
parent
563f3efda3
commit
fe4a655042
@ -5,6 +5,7 @@
|
||||
|
||||
#include "keystore.h"
|
||||
#include "script.h"
|
||||
#include "ui_interface.h"
|
||||
|
||||
bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const
|
||||
{
|
||||
@ -73,6 +74,20 @@ bool CCryptoKeyStore::SetCrypted()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::Lock()
|
||||
{
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
vMasterKey.clear();
|
||||
}
|
||||
|
||||
NotifyKeyStoreStatusChanged(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
||||
{
|
||||
{
|
||||
@ -99,6 +114,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
||||
}
|
||||
vMasterKey = vMasterKeyIn;
|
||||
}
|
||||
NotifyKeyStoreStatusChanged(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -143,18 +143,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Lock()
|
||||
{
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
vMasterKey.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Lock();
|
||||
|
||||
virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddKey(const CKey& key);
|
||||
|
22
src/main.cpp
22
src/main.cpp
@ -946,7 +946,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
|
||||
{
|
||||
bnBestInvalidWork = pindexNew->bnChainWork;
|
||||
CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
|
||||
MainFrameRepaint();
|
||||
NotifyBlocksChanged();
|
||||
}
|
||||
printf("InvalidChainFound: invalid block=%s height=%d work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str());
|
||||
printf("InvalidChainFound: current best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
|
||||
@ -1647,7 +1647,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
|
||||
hashPrevBestCoinBase = vtx[0].GetHash();
|
||||
}
|
||||
|
||||
MainFrameRepaint();
|
||||
NotifyBlocksChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2176,6 +2176,18 @@ string GetWarnings(string strFor)
|
||||
return "error";
|
||||
}
|
||||
|
||||
CAlert CAlert::getAlertByHash(const uint256 &hash)
|
||||
{
|
||||
CAlert retval;
|
||||
{
|
||||
LOCK(cs_mapAlerts);
|
||||
map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
|
||||
if(mi != mapAlerts.end())
|
||||
retval = mi->second;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool CAlert::ProcessAlert()
|
||||
{
|
||||
if (!CheckSignature())
|
||||
@ -2192,11 +2204,13 @@ bool CAlert::ProcessAlert()
|
||||
if (Cancels(alert))
|
||||
{
|
||||
printf("cancelling alert %d\n", alert.nID);
|
||||
NotifyAlertChanged((*mi).first, CT_DELETED);
|
||||
mapAlerts.erase(mi++);
|
||||
}
|
||||
else if (!alert.IsInEffect())
|
||||
{
|
||||
printf("expiring alert %d\n", alert.nID);
|
||||
NotifyAlertChanged((*mi).first, CT_DELETED);
|
||||
mapAlerts.erase(mi++);
|
||||
}
|
||||
else
|
||||
@ -2216,10 +2230,12 @@ bool CAlert::ProcessAlert()
|
||||
|
||||
// Add to mapAlerts
|
||||
mapAlerts.insert(make_pair(GetHash(), *this));
|
||||
// Notify UI if it applies to me
|
||||
if(AppliesToMe())
|
||||
NotifyAlertChanged(GetHash(), CT_NEW);
|
||||
}
|
||||
|
||||
printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
|
||||
MainFrameRepaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1574,6 +1574,11 @@ public:
|
||||
}
|
||||
|
||||
bool ProcessAlert();
|
||||
|
||||
/*
|
||||
* Get copy of (active) alert object by hash. Returns a null alert if it is not found.
|
||||
*/
|
||||
static CAlert getAlertByHash(const uint256 &hash);
|
||||
};
|
||||
|
||||
class CTxMemPool
|
||||
|
@ -705,7 +705,7 @@ void ThreadSocketHandler2(void* parg)
|
||||
if (vNodes.size() != nPrevNodeCount)
|
||||
{
|
||||
nPrevNodeCount = vNodes.size();
|
||||
MainFrameRepaint();
|
||||
NotifyNumConnectionsChanged(vNodes.size());
|
||||
}
|
||||
|
||||
|
||||
|
31
src/noui.cpp
31
src/noui.cpp
@ -19,14 +19,6 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainFrameRepaint()
|
||||
{
|
||||
}
|
||||
|
||||
void AddressBookRepaint()
|
||||
{
|
||||
}
|
||||
|
||||
void InitMessage(const std::string &message)
|
||||
{
|
||||
}
|
||||
@ -42,3 +34,26 @@ void QueueShutdown()
|
||||
CreateThread(Shutdown, NULL);
|
||||
}
|
||||
|
||||
void NotifyBlocksChanged()
|
||||
{
|
||||
}
|
||||
|
||||
void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet)
|
||||
{
|
||||
}
|
||||
|
||||
void NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, EntryStatus status)
|
||||
{
|
||||
}
|
||||
|
||||
void NotifyTransactionChanged(CWallet *wallet, const uint256 &hashTx, EntryStatus status)
|
||||
{
|
||||
}
|
||||
|
||||
void NotifyNumConnectionsChanged(int newNumConnections)
|
||||
{
|
||||
}
|
||||
|
||||
void NotifyAlertChanged(const uint256 &hash, EntryStatus status)
|
||||
{
|
||||
}
|
||||
|
@ -232,9 +232,10 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & pa
|
||||
}
|
||||
}
|
||||
|
||||
void AddressTableModel::update()
|
||||
void AddressTableModel::updateEntry(const QString &address, const QString &label, int status)
|
||||
{
|
||||
// Update address book model from Bitcoin core
|
||||
// TODO: use address, label, status to update only the specified entry (like in WalletModel)
|
||||
beginResetModel();
|
||||
priv->refreshAddressTable();
|
||||
endResetModel();
|
||||
|
@ -78,9 +78,9 @@ signals:
|
||||
void defaultAddressChanged(const QString &address);
|
||||
|
||||
public slots:
|
||||
/* Update address list from core. Invalidates any indices.
|
||||
/* Update address list from core.
|
||||
*/
|
||||
void update();
|
||||
void updateEntry(const QString &address, const QString &label, int status);
|
||||
};
|
||||
|
||||
#endif // ADDRESSTABLEMODEL_H
|
||||
|
@ -84,20 +84,6 @@ void ThreadSafeHandleURI(const std::string& strURI)
|
||||
Q_ARG(QString, QString::fromStdString(strURI)));
|
||||
}
|
||||
|
||||
void MainFrameRepaint()
|
||||
{
|
||||
if(clientmodel)
|
||||
QMetaObject::invokeMethod(clientmodel, "update", Qt::QueuedConnection);
|
||||
if(walletmodel)
|
||||
QMetaObject::invokeMethod(walletmodel, "update", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void AddressBookRepaint()
|
||||
{
|
||||
if(walletmodel)
|
||||
QMetaObject::invokeMethod(walletmodel, "updateAddressList", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void InitMessage(const std::string &message)
|
||||
{
|
||||
if(splashref)
|
||||
@ -120,6 +106,61 @@ std::string _(const char* psz)
|
||||
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
|
||||
}
|
||||
|
||||
void NotifyBlocksChanged()
|
||||
{
|
||||
// This notification is too frequent. Don't trigger a signal.
|
||||
// Don't remove it, though, as it might be useful later.
|
||||
}
|
||||
|
||||
void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet)
|
||||
{
|
||||
// This currently ignores the wallet argument. When multiple wallet support is implemented, this
|
||||
// parameter should be mapped to a specific WalletModel for that wallet.
|
||||
OutputDebugStringF("NotifyKeyStoreStatusChanged\n");
|
||||
if(walletmodel)
|
||||
QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, ChangeType status)
|
||||
{
|
||||
// This currently ignores the wallet argument. When multiple wallet support is implemented, this
|
||||
// parameter should be mapped to a specific WalletModel for that wallet.
|
||||
OutputDebugStringF("NotifyAddressBookChanged %s %s status=%i\n", address.c_str(), label.c_str(), status);
|
||||
if(walletmodel)
|
||||
QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
|
||||
Q_ARG(QString, QString::fromStdString(address)),
|
||||
Q_ARG(QString, QString::fromStdString(label)),
|
||||
Q_ARG(int, status));
|
||||
}
|
||||
|
||||
void NotifyTransactionChanged(CWallet *wallet, const uint256 &hash, ChangeType status)
|
||||
{
|
||||
// This currently ignores the wallet argument. When multiple wallet support is implemented, this
|
||||
// parameter should be mapped to a specific WalletModel for that wallet.
|
||||
OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
|
||||
if(walletmodel)
|
||||
QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
|
||||
Q_ARG(QString, QString::fromStdString(hash.GetHex())),
|
||||
Q_ARG(int, status));
|
||||
}
|
||||
|
||||
void NotifyNumConnectionsChanged(int newNumConnections)
|
||||
{
|
||||
// Too noisy: OutputDebugStringF("NotifyNumConnectionsChanged %i\n", newNumConnections);
|
||||
if(clientmodel)
|
||||
QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
|
||||
Q_ARG(int, newNumConnections));
|
||||
}
|
||||
|
||||
void NotifyAlertChanged(const uint256 &hash, ChangeType status)
|
||||
{
|
||||
OutputDebugStringF("NotifyAlertChanged %s status=%i\n", hash.GetHex().c_str(), status);
|
||||
if(clientmodel)
|
||||
QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
|
||||
Q_ARG(QString, QString::fromStdString(hash.GetHex())),
|
||||
Q_ARG(int, status));
|
||||
}
|
||||
|
||||
/* Handle runaway exceptions. Shows a message box with the problem and quits the program.
|
||||
*/
|
||||
static void handleRunawayException(std::exception *e)
|
||||
|
@ -350,11 +350,11 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
|
||||
setNumConnections(clientModel->getNumConnections());
|
||||
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
|
||||
|
||||
setNumBlocks(clientModel->getNumBlocks());
|
||||
connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
|
||||
setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers());
|
||||
connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
|
||||
|
||||
// Report errors from network/worker thread
|
||||
connect(clientModel, SIGNAL(error(QString,QString, bool)), this, SLOT(error(QString,QString,bool)));
|
||||
connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
|
||||
|
||||
rpcConsole->setClientModel(clientModel);
|
||||
}
|
||||
@ -493,7 +493,7 @@ void BitcoinGUI::setNumConnections(int count)
|
||||
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
|
||||
}
|
||||
|
||||
void BitcoinGUI::setNumBlocks(int count)
|
||||
void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
|
||||
{
|
||||
// don't show / hide progressBar and it's label if we have no connection(s) to the network
|
||||
if (!clientModel || clientModel->getNumConnections() == 0)
|
||||
@ -504,7 +504,6 @@ void BitcoinGUI::setNumBlocks(int count)
|
||||
return;
|
||||
}
|
||||
|
||||
int nTotalBlocks = clientModel->getNumBlocksOfPeers();
|
||||
QString tooltip;
|
||||
|
||||
if(count < nTotalBlocks)
|
||||
|
@ -111,7 +111,7 @@ public slots:
|
||||
/** Set number of connections shown in the UI */
|
||||
void setNumConnections(int count);
|
||||
/** Set number of blocks shown in the UI */
|
||||
void setNumBlocks(int count);
|
||||
void setNumBlocks(int count, int countOfPeers);
|
||||
/** Set the encryption status as shown in the UI.
|
||||
@param[in] status current encryption status
|
||||
@see WalletModel::EncryptionStatus
|
||||
|
@ -5,15 +5,23 @@
|
||||
#include "transactiontablemodel.h"
|
||||
|
||||
#include "main.h"
|
||||
static const int64 nClientStartupTime = GetTime();
|
||||
#include "ui_interface.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
|
||||
static const int64 nClientStartupTime = GetTime();
|
||||
|
||||
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
|
||||
QObject(parent), optionsModel(optionsModel),
|
||||
cachedNumConnections(0), cachedNumBlocks(0)
|
||||
cachedNumBlocks(0), cachedNumBlocksOfPeers(0), pollTimer(0)
|
||||
{
|
||||
numBlocksAtStartup = -1;
|
||||
|
||||
pollTimer = new QTimer();
|
||||
pollTimer->setInterval(MODEL_UPDATE_DELAY);
|
||||
pollTimer->start();
|
||||
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
|
||||
}
|
||||
|
||||
int ClientModel::getNumConnections() const
|
||||
@ -37,27 +45,42 @@ QDateTime ClientModel::getLastBlockDate() const
|
||||
return QDateTime::fromTime_t(pindexBest->GetBlockTime());
|
||||
}
|
||||
|
||||
void ClientModel::update()
|
||||
void ClientModel::updateTimer()
|
||||
{
|
||||
int newNumConnections = getNumConnections();
|
||||
// Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
|
||||
// Periodically check and update with a timer.
|
||||
int newNumBlocks = getNumBlocks();
|
||||
QString newStatusBar = getStatusBarWarnings();
|
||||
int newNumBlocksOfPeers = getNumBlocksOfPeers();
|
||||
|
||||
if(cachedNumConnections != newNumConnections)
|
||||
emit numConnectionsChanged(newNumConnections);
|
||||
if(cachedNumBlocks != newNumBlocks || cachedStatusBar != newStatusBar)
|
||||
if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers)
|
||||
emit numBlocksChanged(newNumBlocks, newNumBlocksOfPeers);
|
||||
|
||||
cachedNumBlocks = newNumBlocks;
|
||||
cachedNumBlocksOfPeers = newNumBlocksOfPeers;
|
||||
}
|
||||
|
||||
void ClientModel::updateNumConnections(int numConnections)
|
||||
{
|
||||
emit numConnectionsChanged(numConnections);
|
||||
}
|
||||
|
||||
void ClientModel::updateAlert(const QString &hash, int status)
|
||||
{
|
||||
// Show error message notification for new alert
|
||||
if(status == CT_NEW)
|
||||
{
|
||||
// Simply emit a numBlocksChanged for now in case the status message changes,
|
||||
// so that the view updates the status bar.
|
||||
// TODO: It should send a notification.
|
||||
// (However, this might generate looped notifications and needs to be thought through and tested carefully)
|
||||
// error(tr("Network Alert"), newStatusBar);
|
||||
emit numBlocksChanged(newNumBlocks);
|
||||
uint256 hash_256;
|
||||
hash_256.SetHex(hash.toStdString());
|
||||
CAlert alert = CAlert::getAlertByHash(hash_256);
|
||||
if(!alert.IsNull())
|
||||
{
|
||||
emit error(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false);
|
||||
}
|
||||
}
|
||||
|
||||
cachedNumConnections = newNumConnections;
|
||||
cachedNumBlocks = newNumBlocks;
|
||||
cachedStatusBar = newStatusBar;
|
||||
// Emit a numBlocksChanged when the status message changes,
|
||||
// so that the view recomputes and updates the status bar.
|
||||
emit numBlocksChanged(getNumBlocks(), getNumBlocksOfPeers());
|
||||
}
|
||||
|
||||
bool ClientModel::isTestNet() const
|
||||
|
@ -10,6 +10,7 @@ class CWallet;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDateTime;
|
||||
class QTimer;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
/** Model for Bitcoin network client. */
|
||||
@ -44,23 +45,24 @@ public:
|
||||
private:
|
||||
OptionsModel *optionsModel;
|
||||
|
||||
int cachedNumConnections;
|
||||
int cachedNumBlocks;
|
||||
QString cachedStatusBar;
|
||||
int cachedNumBlocksOfPeers;
|
||||
|
||||
int numBlocksAtStartup;
|
||||
|
||||
QTimer *pollTimer;
|
||||
|
||||
signals:
|
||||
void numConnectionsChanged(int count);
|
||||
void numBlocksChanged(int count);
|
||||
void numBlocksChanged(int count, int countOfPeers);
|
||||
|
||||
//! Asynchronous error notification
|
||||
void error(const QString &title, const QString &message, bool modal);
|
||||
|
||||
public slots:
|
||||
|
||||
private slots:
|
||||
void update();
|
||||
void updateTimer();
|
||||
void updateNumConnections(int numConnections);
|
||||
void updateAlert(const QString &hash, int status);
|
||||
};
|
||||
|
||||
#endif // CLIENTMODEL_H
|
||||
|
@ -157,7 +157,7 @@ void RPCConsole::setClientModel(ClientModel *model)
|
||||
{
|
||||
// Subscribe to information, replies, messages, errors
|
||||
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
|
||||
connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
|
||||
connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
|
||||
|
||||
// Provide initial values
|
||||
ui->clientVersion->setText(model->formatFullVersion());
|
||||
@ -168,7 +168,7 @@ void RPCConsole::setClientModel(ClientModel *model)
|
||||
setNumConnections(model->getNumConnections());
|
||||
ui->isTestNet->setChecked(model->isTestNet());
|
||||
|
||||
setNumBlocks(model->getNumBlocks());
|
||||
setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers());
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,9 +235,10 @@ void RPCConsole::setNumConnections(int count)
|
||||
ui->numberOfConnections->setText(QString::number(count));
|
||||
}
|
||||
|
||||
void RPCConsole::setNumBlocks(int count)
|
||||
void RPCConsole::setNumBlocks(int count, int countOfPeers)
|
||||
{
|
||||
ui->numberOfBlocks->setText(QString::number(count));
|
||||
ui->totalBlocks->setText(QString::number(countOfPeers));
|
||||
if(clientModel)
|
||||
{
|
||||
// If there is no current number available display N/A instead of 0, which can't ever be true
|
||||
|
@ -42,7 +42,7 @@ public slots:
|
||||
/** Set number of connections shown in the UI */
|
||||
void setNumConnections(int count);
|
||||
/** Set number of blocks shown in the UI */
|
||||
void setNumBlocks(int count);
|
||||
void setNumBlocks(int count, int countOfPeers);
|
||||
/** Go forward or back in history */
|
||||
void browseHistory(int offset);
|
||||
/** Scroll console view to end */
|
||||
|
@ -40,114 +40,111 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||
uint256 hash = wtx.GetHash();
|
||||
std::map<std::string, std::string> mapValue = wtx.mapValue;
|
||||
|
||||
if (showTransaction(wtx))
|
||||
if (nNet > 0 || wtx.IsCoinBase())
|
||||
{
|
||||
if (nNet > 0 || wtx.IsCoinBase())
|
||||
//
|
||||
// Credit
|
||||
//
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
{
|
||||
if(wallet->IsMine(txout))
|
||||
{
|
||||
TransactionRecord sub(hash, nTime);
|
||||
CBitcoinAddress address;
|
||||
sub.idx = parts.size(); // sequence number
|
||||
sub.credit = txout.nValue;
|
||||
if (wtx.IsCoinBase())
|
||||
{
|
||||
// Generated
|
||||
sub.type = TransactionRecord::Generated;
|
||||
}
|
||||
else if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address))
|
||||
{
|
||||
// Received by Bitcoin Address
|
||||
sub.type = TransactionRecord::RecvWithAddress;
|
||||
sub.address = address.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
|
||||
sub.type = TransactionRecord::RecvFromOther;
|
||||
sub.address = mapValue["from"];
|
||||
}
|
||||
|
||||
parts.append(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool fAllFromMe = true;
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
fAllFromMe = fAllFromMe && wallet->IsMine(txin);
|
||||
|
||||
bool fAllToMe = true;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
fAllToMe = fAllToMe && wallet->IsMine(txout);
|
||||
|
||||
if (fAllFromMe && fAllToMe)
|
||||
{
|
||||
// Payment to self
|
||||
int64 nChange = wtx.GetChange();
|
||||
|
||||
parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
|
||||
-(nDebit - nChange), nCredit - nChange));
|
||||
}
|
||||
else if (fAllFromMe)
|
||||
{
|
||||
//
|
||||
// Credit
|
||||
// Debit
|
||||
//
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
int64 nTxFee = nDebit - wtx.GetValueOut();
|
||||
|
||||
for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
|
||||
{
|
||||
const CTxOut& txout = wtx.vout[nOut];
|
||||
TransactionRecord sub(hash, nTime);
|
||||
sub.idx = parts.size();
|
||||
|
||||
if(wallet->IsMine(txout))
|
||||
{
|
||||
TransactionRecord sub(hash, nTime);
|
||||
CBitcoinAddress address;
|
||||
sub.idx = parts.size(); // sequence number
|
||||
sub.credit = txout.nValue;
|
||||
if (wtx.IsCoinBase())
|
||||
{
|
||||
// Generated
|
||||
sub.type = TransactionRecord::Generated;
|
||||
}
|
||||
else if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address))
|
||||
{
|
||||
// Received by Bitcoin Address
|
||||
sub.type = TransactionRecord::RecvWithAddress;
|
||||
sub.address = address.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
|
||||
sub.type = TransactionRecord::RecvFromOther;
|
||||
sub.address = mapValue["from"];
|
||||
}
|
||||
|
||||
parts.append(sub);
|
||||
// Ignore parts sent to self, as this is usually the change
|
||||
// from a transaction sent back to our own address.
|
||||
continue;
|
||||
}
|
||||
|
||||
CBitcoinAddress address;
|
||||
if (ExtractAddress(txout.scriptPubKey, address))
|
||||
{
|
||||
// Sent to Bitcoin Address
|
||||
sub.type = TransactionRecord::SendToAddress;
|
||||
sub.address = address.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sent to IP, or other non-address transaction like OP_EVAL
|
||||
sub.type = TransactionRecord::SendToOther;
|
||||
sub.address = mapValue["to"];
|
||||
}
|
||||
|
||||
int64 nValue = txout.nValue;
|
||||
/* Add fee to first output */
|
||||
if (nTxFee > 0)
|
||||
{
|
||||
nValue += nTxFee;
|
||||
nTxFee = 0;
|
||||
}
|
||||
sub.debit = -nValue;
|
||||
|
||||
parts.append(sub);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool fAllFromMe = true;
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
fAllFromMe = fAllFromMe && wallet->IsMine(txin);
|
||||
|
||||
bool fAllToMe = true;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
fAllToMe = fAllToMe && wallet->IsMine(txout);
|
||||
|
||||
if (fAllFromMe && fAllToMe)
|
||||
{
|
||||
// Payment to self
|
||||
int64 nChange = wtx.GetChange();
|
||||
|
||||
parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
|
||||
-(nDebit - nChange), nCredit - nChange));
|
||||
}
|
||||
else if (fAllFromMe)
|
||||
{
|
||||
//
|
||||
// Debit
|
||||
//
|
||||
int64 nTxFee = nDebit - wtx.GetValueOut();
|
||||
|
||||
for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
|
||||
{
|
||||
const CTxOut& txout = wtx.vout[nOut];
|
||||
TransactionRecord sub(hash, nTime);
|
||||
sub.idx = parts.size();
|
||||
|
||||
if(wallet->IsMine(txout))
|
||||
{
|
||||
// Ignore parts sent to self, as this is usually the change
|
||||
// from a transaction sent back to our own address.
|
||||
continue;
|
||||
}
|
||||
|
||||
CBitcoinAddress address;
|
||||
if (ExtractAddress(txout.scriptPubKey, address))
|
||||
{
|
||||
// Sent to Bitcoin Address
|
||||
sub.type = TransactionRecord::SendToAddress;
|
||||
sub.address = address.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sent to IP, or other non-address transaction like OP_EVAL
|
||||
sub.type = TransactionRecord::SendToOther;
|
||||
sub.address = mapValue["to"];
|
||||
}
|
||||
|
||||
int64 nValue = txout.nValue;
|
||||
/* Add fee to first output */
|
||||
if (nTxFee > 0)
|
||||
{
|
||||
nValue += nTxFee;
|
||||
nTxFee = 0;
|
||||
}
|
||||
sub.debit = -nValue;
|
||||
|
||||
parts.append(sub);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Mixed debit transaction, can't break down payees
|
||||
//
|
||||
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
|
||||
}
|
||||
//
|
||||
// Mixed debit transaction, can't break down payees
|
||||
//
|
||||
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "bitcoinunits.h"
|
||||
|
||||
#include "wallet.h"
|
||||
#include "ui_interface.h"
|
||||
|
||||
#include <QLocale>
|
||||
#include <QList>
|
||||
@ -66,15 +67,14 @@ public:
|
||||
*/
|
||||
void refreshWallet()
|
||||
{
|
||||
#ifdef WALLET_UPDATE_DEBUG
|
||||
qDebug() << "refreshWallet";
|
||||
#endif
|
||||
OutputDebugStringF("refreshWallet\n");
|
||||
cachedWallet.clear();
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
|
||||
{
|
||||
cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
|
||||
if(TransactionRecord::showTransaction(it->second))
|
||||
cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,49 +82,55 @@ public:
|
||||
/* Update our model of the wallet incrementally, to synchronize our model of the wallet
|
||||
with that of the core.
|
||||
|
||||
Call with list of hashes of transactions that were added, removed or changed.
|
||||
Call with transaction that was added, removed or changed.
|
||||
*/
|
||||
void updateWallet(const QList<uint256> &updated)
|
||||
void updateWallet(const uint256 &hash, int status)
|
||||
{
|
||||
// Walk through updated transactions, update model as needed.
|
||||
#ifdef WALLET_UPDATE_DEBUG
|
||||
qDebug() << "updateWallet";
|
||||
#endif
|
||||
// Sort update list, and iterate through it in reverse, so that model updates
|
||||
// can be emitted from end to beginning (so that earlier updates will not influence
|
||||
// the indices of latter ones).
|
||||
QList<uint256> updated_sorted = updated;
|
||||
qSort(updated_sorted);
|
||||
|
||||
OutputDebugStringF("updateWallet %s %i\n", hash.ToString().c_str(), status);
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx)
|
||||
|
||||
// Find transaction in wallet
|
||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
|
||||
bool inWallet = mi != wallet->mapWallet.end();
|
||||
|
||||
// Find bounds of this transaction in model
|
||||
QList<TransactionRecord>::iterator lower = qLowerBound(
|
||||
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
|
||||
QList<TransactionRecord>::iterator upper = qUpperBound(
|
||||
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
|
||||
int lowerIndex = (lower - cachedWallet.begin());
|
||||
int upperIndex = (upper - cachedWallet.begin());
|
||||
bool inModel = (lower != upper);
|
||||
|
||||
// Determine whether to show transaction or not
|
||||
bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second));
|
||||
|
||||
if(status == CT_UPDATED)
|
||||
{
|
||||
const uint256 &hash = updated_sorted.at(update_idx);
|
||||
// Find transaction in wallet
|
||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
|
||||
bool inWallet = mi != wallet->mapWallet.end();
|
||||
// Find bounds of this transaction in model
|
||||
QList<TransactionRecord>::iterator lower = qLowerBound(
|
||||
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
|
||||
QList<TransactionRecord>::iterator upper = qUpperBound(
|
||||
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
|
||||
int lowerIndex = (lower - cachedWallet.begin());
|
||||
int upperIndex = (upper - cachedWallet.begin());
|
||||
if(showTransaction && !inModel)
|
||||
status = CT_NEW; /* Not in model, but want to show, treat as new */
|
||||
if(!showTransaction && inModel)
|
||||
status = CT_DELETED; /* In model, but want to hide, treat as deleted */
|
||||
}
|
||||
|
||||
// Determine if transaction is in model already
|
||||
bool inModel = false;
|
||||
if(lower != upper)
|
||||
OutputDebugStringF(" inWallet=%i inModel=%i Index=%i-%i showTransaction=%i derivedStatus=%i\n",
|
||||
inWallet, inModel, lowerIndex, upperIndex, showTransaction, status);
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case CT_NEW:
|
||||
if(inModel)
|
||||
{
|
||||
inModel = true;
|
||||
OutputDebugStringF("Warning: updateWallet: Got CT_NEW, but transaction is already in model\n");
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WALLET_UPDATE_DEBUG
|
||||
qDebug() << " " << QString::fromStdString(hash.ToString()) << inWallet << " " << inModel
|
||||
<< lowerIndex << "-" << upperIndex;
|
||||
#endif
|
||||
|
||||
if(inWallet && !inModel)
|
||||
if(!inWallet)
|
||||
{
|
||||
OutputDebugStringF("Warning: updateWallet: Got CT_NEW, but transaction is not in wallet\n");
|
||||
break;
|
||||
}
|
||||
if(showTransaction)
|
||||
{
|
||||
// Added -- insert at the right position
|
||||
QList<TransactionRecord> toInsert =
|
||||
@ -141,17 +147,22 @@ public:
|
||||
parent->endInsertRows();
|
||||
}
|
||||
}
|
||||
else if(!inWallet && inModel)
|
||||
break;
|
||||
case CT_DELETED:
|
||||
if(!inModel)
|
||||
{
|
||||
// Removed -- remove entire transaction from table
|
||||
parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
|
||||
cachedWallet.erase(lower, upper);
|
||||
parent->endRemoveRows();
|
||||
}
|
||||
else if(inWallet && inModel)
|
||||
{
|
||||
// Updated -- nothing to do, status update will take care of this
|
||||
OutputDebugStringF("Warning: updateWallet: Got CT_DELETED, but transaction is not in model\n");
|
||||
break;
|
||||
}
|
||||
// Removed -- remove entire transaction from table
|
||||
parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
|
||||
cachedWallet.erase(lower, upper);
|
||||
parent->endRemoveRows();
|
||||
break;
|
||||
case CT_UPDATED:
|
||||
// Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
|
||||
// visible transactions.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,14 +220,15 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
|
||||
QAbstractTableModel(parent),
|
||||
wallet(wallet),
|
||||
walletModel(parent),
|
||||
priv(new TransactionTablePriv(wallet, this))
|
||||
priv(new TransactionTablePriv(wallet, this)),
|
||||
cachedNumBlocks(0)
|
||||
{
|
||||
columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount");
|
||||
|
||||
priv->refreshWallet();
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations()));
|
||||
timer->start(MODEL_UPDATE_DELAY);
|
||||
}
|
||||
|
||||
@ -225,29 +237,23 @@ TransactionTableModel::~TransactionTableModel()
|
||||
delete priv;
|
||||
}
|
||||
|
||||
void TransactionTableModel::update()
|
||||
void TransactionTableModel::updateTransaction(const QString &hash, int status)
|
||||
{
|
||||
QList<uint256> updated;
|
||||
uint256 updated;
|
||||
updated.SetHex(hash.toStdString());
|
||||
|
||||
// Check if there are changes to wallet map
|
||||
priv->updateWallet(updated, status);
|
||||
}
|
||||
|
||||
void TransactionTableModel::updateConfirmations()
|
||||
{
|
||||
if(nBestHeight != cachedNumBlocks)
|
||||
{
|
||||
TRY_LOCK(wallet->cs_wallet, lockWallet);
|
||||
if (lockWallet && !wallet->vWalletUpdated.empty())
|
||||
{
|
||||
BOOST_FOREACH(uint256 hash, wallet->vWalletUpdated)
|
||||
{
|
||||
updated.append(hash);
|
||||
}
|
||||
wallet->vWalletUpdated.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if(!updated.empty())
|
||||
{
|
||||
priv->updateWallet(updated);
|
||||
|
||||
// Status (number of confirmations) and (possibly) description
|
||||
// columns changed for all rows.
|
||||
cachedNumBlocks = nBestHeight;
|
||||
// Blocks came in since last poll.
|
||||
// Invalidate status (number of confirmations) and (possibly) description
|
||||
// for all rows. Qt is smart enough to only actually request the data for the
|
||||
// visible rows.
|
||||
emit dataChanged(index(0, Status), index(priv->size()-1, Status));
|
||||
emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ private:
|
||||
WalletModel *walletModel;
|
||||
QStringList columns;
|
||||
TransactionTablePriv *priv;
|
||||
int cachedNumBlocks;
|
||||
|
||||
QString lookupAddress(const std::string &address, bool tooltip) const;
|
||||
QVariant addressColor(const TransactionRecord *wtx) const;
|
||||
@ -72,8 +73,9 @@ private:
|
||||
QVariant txStatusDecoration(const TransactionRecord *wtx) const;
|
||||
QVariant txAddressDecoration(const TransactionRecord *wtx) const;
|
||||
|
||||
private slots:
|
||||
void update();
|
||||
public slots:
|
||||
void updateTransaction(const QString &hash, int status);
|
||||
void updateConfirmations();
|
||||
|
||||
friend class TransactionTablePriv;
|
||||
};
|
||||
|
@ -40,30 +40,38 @@ int WalletModel::getNumTransactions() const
|
||||
return numTransactions;
|
||||
}
|
||||
|
||||
void WalletModel::update()
|
||||
void WalletModel::updateStatus()
|
||||
{
|
||||
qint64 newBalance = getBalance();
|
||||
qint64 newUnconfirmedBalance = getUnconfirmedBalance();
|
||||
int newNumTransactions = getNumTransactions();
|
||||
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
|
||||
|
||||
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance)
|
||||
emit balanceChanged(newBalance, newUnconfirmedBalance);
|
||||
|
||||
if(cachedNumTransactions != newNumTransactions)
|
||||
emit numTransactionsChanged(newNumTransactions);
|
||||
|
||||
if(cachedEncryptionStatus != newEncryptionStatus)
|
||||
emit encryptionStatusChanged(newEncryptionStatus);
|
||||
}
|
||||
|
||||
void WalletModel::updateTransaction(const QString &hash, int status)
|
||||
{
|
||||
if(transactionTableModel)
|
||||
transactionTableModel->updateTransaction(hash, status);
|
||||
|
||||
// Balance and number of transactions might have changed
|
||||
qint64 newBalance = getBalance();
|
||||
qint64 newUnconfirmedBalance = getUnconfirmedBalance();
|
||||
int newNumTransactions = getNumTransactions();
|
||||
|
||||
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance)
|
||||
emit balanceChanged(newBalance, newUnconfirmedBalance);
|
||||
if(cachedNumTransactions != newNumTransactions)
|
||||
emit numTransactionsChanged(newNumTransactions);
|
||||
|
||||
cachedBalance = newBalance;
|
||||
cachedUnconfirmedBalance = newUnconfirmedBalance;
|
||||
cachedNumTransactions = newNumTransactions;
|
||||
}
|
||||
|
||||
void WalletModel::updateAddressList()
|
||||
void WalletModel::updateAddressBook(const QString &address, const QString &label, int status)
|
||||
{
|
||||
addressTableModel->update();
|
||||
if(addressTableModel)
|
||||
addressTableModel->updateEntry(address, label, status);
|
||||
}
|
||||
|
||||
bool WalletModel::validateAddress(const QString &address)
|
||||
|
@ -137,8 +137,12 @@ signals:
|
||||
void error(const QString &title, const QString &message, bool modal);
|
||||
|
||||
public slots:
|
||||
void update();
|
||||
void updateAddressList();
|
||||
/* 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, int status);
|
||||
};
|
||||
|
||||
|
||||
|
@ -73,8 +73,6 @@ Value importprivkey(const Array& params, bool fHelp)
|
||||
pwalletMain->ReacceptWalletTransactions();
|
||||
}
|
||||
|
||||
MainFrameRepaint();
|
||||
|
||||
return Value::null;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,10 @@
|
||||
#include <string>
|
||||
#include "util.h" // for int64
|
||||
|
||||
class CBasicKeyStore;
|
||||
class CWallet;
|
||||
class uint256;
|
||||
|
||||
#define wxYES 0x00000002
|
||||
#define wxOK 0x00000004
|
||||
#define wxNO 0x00000008
|
||||
@ -36,15 +40,46 @@
|
||||
// Force blocking, modal message box dialog (not just notification)
|
||||
#define wxMODAL 0x00040000
|
||||
|
||||
enum ChangeType
|
||||
{
|
||||
CT_NEW,
|
||||
CT_UPDATED,
|
||||
CT_DELETED
|
||||
};
|
||||
|
||||
/* These UI communication functions are implemented in bitcoin.cpp (for ui) and noui.cpp (no ui) */
|
||||
|
||||
extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK);
|
||||
extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption);
|
||||
extern void ThreadSafeHandleURI(const std::string& strURI);
|
||||
extern void MainFrameRepaint();
|
||||
extern void AddressBookRepaint();
|
||||
extern void QueueShutdown();
|
||||
extern void InitMessage(const std::string &message);
|
||||
extern std::string _(const char* psz);
|
||||
|
||||
/* Block chain changed. */
|
||||
extern void NotifyBlocksChanged();
|
||||
|
||||
/* Wallet status (encrypted, locked) changed.
|
||||
* Note: Called without locks held.
|
||||
*/
|
||||
extern void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet);
|
||||
|
||||
/* Address book entry changed.
|
||||
* Note: called with lock cs_wallet held.
|
||||
*/
|
||||
extern void NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, ChangeType status);
|
||||
|
||||
/* Wallet transaction added, removed or updated.
|
||||
* Note: called with lock cs_wallet held.
|
||||
*/
|
||||
extern void NotifyTransactionChanged(CWallet *wallet, const uint256 &hashTx, ChangeType status);
|
||||
|
||||
/* Number of connections changed. */
|
||||
extern void NotifyNumConnectionsChanged(int newNumConnections);
|
||||
|
||||
/* New, updated or cancelled alert.
|
||||
* Note: called with lock cs_mapAlerts held.
|
||||
*/
|
||||
extern void NotifyAlertChanged(const uint256 &hash, ChangeType status);
|
||||
|
||||
#endif
|
||||
|
@ -274,7 +274,9 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
||||
// Need to completely rewrite the wallet file; if we don't, bdb might keep
|
||||
// bits of the unencrypted private key in slack space in the database file.
|
||||
CDB::Rewrite(strWalletFile);
|
||||
|
||||
}
|
||||
NotifyKeyStoreStatusChanged(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -297,7 +299,7 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx)
|
||||
printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
|
||||
wtx.MarkSpent(txin.prevout.n);
|
||||
wtx.WriteToDisk();
|
||||
vWalletUpdated.push_back(txin.prevout.hash);
|
||||
NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -373,15 +375,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Notify UI
|
||||
vWalletUpdated.push_back(hash);
|
||||
|
||||
// since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
|
||||
WalletUpdateSpent(wtx);
|
||||
}
|
||||
|
||||
// Refresh UI
|
||||
MainFrameRepaint();
|
||||
// Notify UI of new or updated transaction
|
||||
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1183,7 +1182,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
||||
coin.BindWallet(this);
|
||||
coin.MarkSpent(txin.prevout.n);
|
||||
coin.WriteToDisk();
|
||||
vWalletUpdated.push_back(coin.GetHash());
|
||||
NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
|
||||
}
|
||||
|
||||
if (fFileBacked)
|
||||
@ -1202,7 +1201,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
||||
}
|
||||
wtxNew.RelayWalletTransaction();
|
||||
}
|
||||
MainFrameRepaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1237,7 +1235,6 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
|
||||
if (!CommitTransaction(wtxNew, reservekey))
|
||||
return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
|
||||
|
||||
MainFrameRepaint();
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -1290,8 +1287,9 @@ int CWallet::LoadWallet(bool& fFirstRunRet)
|
||||
|
||||
bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
|
||||
{
|
||||
std::map<CBitcoinAddress, std::string>::iterator mi = mapAddressBook.find(address);
|
||||
mapAddressBook[address] = strName;
|
||||
AddressBookRepaint();
|
||||
NotifyAddressBookChanged(this, address.ToString(), strName, (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED);
|
||||
if (!fFileBacked)
|
||||
return false;
|
||||
return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
|
||||
@ -1300,7 +1298,7 @@ bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& s
|
||||
bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
|
||||
{
|
||||
mapAddressBook.erase(address);
|
||||
AddressBookRepaint();
|
||||
NotifyAddressBookChanged(this, address.ToString(), "", CT_DELETED);
|
||||
if (!fFileBacked)
|
||||
return false;
|
||||
return CWalletDB(strWalletFile).EraseName(address.ToString());
|
||||
@ -1558,3 +1556,14 @@ void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress)
|
||||
setAddress.insert(address);
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::UpdatedTransaction(const uint256 &hashTx)
|
||||
{
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
// Only notify UI if this transaction is in this wallet
|
||||
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
|
||||
if (mi != mapWallet.end())
|
||||
NotifyTransactionChanged(this, hashTx, CT_UPDATED);
|
||||
}
|
||||
}
|
||||
|
10
src/wallet.h
10
src/wallet.h
@ -102,8 +102,6 @@ public:
|
||||
}
|
||||
|
||||
std::map<uint256, CWalletTx> mapWallet;
|
||||
std::vector<uint256> vWalletUpdated;
|
||||
|
||||
std::map<uint256, int> mapRequestCount;
|
||||
|
||||
std::map<CBitcoinAddress, std::string> mapAddressBook;
|
||||
@ -232,13 +230,7 @@ public:
|
||||
|
||||
bool DelAddressBookName(const CBitcoinAddress& address);
|
||||
|
||||
void UpdatedTransaction(const uint256 &hashTx)
|
||||
{
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
vWalletUpdated.push_back(hashTx);
|
||||
}
|
||||
}
|
||||
void UpdatedTransaction(const uint256 &hashTx);
|
||||
|
||||
void PrintWallet(const CBlock& block);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user