diff options
-rw-r--r-- | src/interface/node.cpp | 6 | ||||
-rw-r--r-- | src/interface/node.h | 7 | ||||
-rw-r--r-- | src/interface/wallet.cpp | 138 | ||||
-rw-r--r-- | src/interface/wallet.h | 69 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 4 | ||||
-rw-r--r-- | src/qt/recentrequeststablemodel.cpp | 3 | ||||
-rw-r--r-- | src/qt/recentrequeststablemodel.h | 4 | ||||
-rw-r--r-- | src/qt/test/wallettests.cpp | 2 | ||||
-rw-r--r-- | src/qt/transactiondesc.cpp | 138 | ||||
-rw-r--r-- | src/qt/transactiondesc.h | 12 | ||||
-rw-r--r-- | src/qt/transactionrecord.cpp | 86 | ||||
-rw-r--r-- | src/qt/transactionrecord.h | 16 | ||||
-rw-r--r-- | src/qt/transactiontablemodel.cpp | 100 | ||||
-rw-r--r-- | src/qt/transactiontablemodel.h | 13 | ||||
-rw-r--r-- | src/qt/walletmodel.cpp | 19 | ||||
-rw-r--r-- | src/qt/walletmodel.h | 3 |
16 files changed, 410 insertions, 210 deletions
diff --git a/src/interface/node.cpp b/src/interface/node.cpp index 0e6bc4a785..a8ed275dc5 100644 --- a/src/interface/node.cpp +++ b/src/interface/node.cpp @@ -60,6 +60,7 @@ class NodeImpl : public Node void initLogging() override { InitLogging(); } void initParameterInteraction() override { InitParameterInteraction(); } std::string getWarnings(const std::string& type) override { return GetWarnings(type); } + uint32_t getLogCategories() override { return ::logCategories; } bool baseInitialize() override { return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() && @@ -227,6 +228,11 @@ class NodeImpl : public Node std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); } void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); } void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); } + bool getUnspentOutput(const COutPoint& output, Coin& coin) override + { + LOCK(::cs_main); + return ::pcoinsTip->GetCoin(output, coin); + } std::vector<std::unique_ptr<Wallet>> getWallets() override { #ifdef ENABLE_WALLET diff --git a/src/interface/node.h b/src/interface/node.h index a31105f6f8..c73f45a1b0 100644 --- a/src/interface/node.h +++ b/src/interface/node.h @@ -22,6 +22,7 @@ class CCoinControl; class CFeeRate; class CNodeStats; +class Coin; class RPCTimerInterface; class UniValue; class proxyType; @@ -66,6 +67,9 @@ public: //! Get warnings. virtual std::string getWarnings(const std::string& type) = 0; + // Get log flags. + virtual uint32_t getLogCategories() = 0; + //! Initialize app dependencies. virtual bool baseInitialize() = 0; @@ -184,6 +188,9 @@ public: //! Unset RPC timer interface. virtual void rpcUnsetTimerInterface(RPCTimerInterface* iface) = 0; + //! Get unspent outputs associated with a transaction. + virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0; + //! Return interfaces for accessing wallets (if any). virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0; diff --git a/src/interface/wallet.cpp b/src/interface/wallet.cpp index efc9946fb6..a6bce7d3de 100644 --- a/src/interface/wallet.cpp +++ b/src/interface/wallet.cpp @@ -15,6 +15,7 @@ #include <script/standard.h> #include <support/allocators/secure.h> #include <sync.h> +#include <timedata.h> #include <ui_interface.h> #include <uint256.h> #include <validation.h> @@ -54,6 +55,54 @@ public: CReserveKey m_key; }; +//! Construct wallet tx struct. +WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) +{ + WalletTx result; + result.tx = wtx.tx; + result.txin_is_mine.reserve(wtx.tx->vin.size()); + for (const auto& txin : wtx.tx->vin) { + result.txin_is_mine.emplace_back(wallet.IsMine(txin)); + } + result.txout_is_mine.reserve(wtx.tx->vout.size()); + result.txout_address.reserve(wtx.tx->vout.size()); + result.txout_address_is_mine.reserve(wtx.tx->vout.size()); + for (const auto& txout : wtx.tx->vout) { + result.txout_is_mine.emplace_back(wallet.IsMine(txout)); + result.txout_address.emplace_back(); + result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ? + IsMine(wallet, result.txout_address.back()) : + ISMINE_NO); + } + result.credit = wtx.GetCredit(ISMINE_ALL); + result.debit = wtx.GetDebit(ISMINE_ALL); + result.change = wtx.GetChange(); + result.time = wtx.GetTxTime(); + result.value_map = wtx.mapValue; + result.is_coinbase = wtx.IsCoinBase(); + return result; +} + +//! Construct wallet tx status struct. +WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx) +{ + WalletTxStatus result; + auto mi = ::mapBlockIndex.find(wtx.hashBlock); + CBlockIndex* block = mi != ::mapBlockIndex.end() ? mi->second : nullptr; + result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max()), + result.blocks_to_maturity = wtx.GetBlocksToMaturity(); + result.depth_in_main_chain = wtx.GetDepthInMainChain(); + result.request_count = wtx.GetRequestCount(); + result.time_received = wtx.nTimeReceived; + result.lock_time = wtx.tx->nLockTime; + result.is_final = CheckFinalTx(*wtx.tx); + result.is_trusted = wtx.IsTrusted(); + result.is_abandoned = wtx.isAbandoned(); + result.is_coinbase = wtx.IsCoinBase(); + result.is_in_main_chain = wtx.IsInMainChain(); + return result; +} + //! Construct wallet TxOut struct. WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth) { @@ -205,6 +254,75 @@ public: return feebumper::CommitTransaction(&m_wallet, txid, std::move(mtx), errors, bumped_txid) == feebumper::Result::OK; } + CTransactionRef getTx(const uint256& txid) override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + auto mi = m_wallet.mapWallet.find(txid); + if (mi != m_wallet.mapWallet.end()) { + return mi->second.tx; + } + return {}; + } + WalletTx getWalletTx(const uint256& txid) override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + auto mi = m_wallet.mapWallet.find(txid); + if (mi != m_wallet.mapWallet.end()) { + return MakeWalletTx(m_wallet, mi->second); + } + return {}; + } + std::vector<WalletTx> getWalletTxs() override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + std::vector<WalletTx> result; + result.reserve(m_wallet.mapWallet.size()); + for (const auto& entry : m_wallet.mapWallet) { + result.emplace_back(MakeWalletTx(m_wallet, entry.second)); + } + return result; + } + bool tryGetTxStatus(const uint256& txid, + interface::WalletTxStatus& tx_status, + int& num_blocks, + int64_t& adjusted_time) override + { + TRY_LOCK(::cs_main, locked_chain); + if (!locked_chain) { + return false; + } + TRY_LOCK(m_wallet.cs_wallet, locked_wallet); + if (!locked_wallet) { + return false; + } + auto mi = m_wallet.mapWallet.find(txid); + if (mi == m_wallet.mapWallet.end()) { + return false; + } + num_blocks = ::chainActive.Height(); + adjusted_time = GetAdjustedTime(); + tx_status = MakeWalletTxStatus(mi->second); + return true; + } + WalletTx getWalletTxDetails(const uint256& txid, + WalletTxStatus& tx_status, + WalletOrderForm& order_form, + bool& in_mempool, + int& num_blocks, + int64_t& adjusted_time) override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + auto mi = m_wallet.mapWallet.find(txid); + if (mi != m_wallet.mapWallet.end()) { + num_blocks = ::chainActive.Height(); + adjusted_time = GetAdjustedTime(); + in_mempool = mi->second.InMempool(); + order_form = mi->second.vOrderForm; + tx_status = MakeWalletTxStatus(mi->second); + return MakeWalletTx(m_wallet, mi->second); + } + return {}; + } WalletBalances getBalances() override { WalletBalances result; @@ -236,6 +354,26 @@ public: { return m_wallet.GetAvailableBalance(&coin_control); } + isminetype txinIsMine(const CTxIn& txin) override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + return m_wallet.IsMine(txin); + } + isminetype txoutIsMine(const CTxOut& txout) override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + return m_wallet.IsMine(txout); + } + CAmount getDebit(const CTxIn& txin, isminefilter filter) override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + return m_wallet.GetDebit(txin, filter); + } + CAmount getCredit(const CTxOut& txout, isminefilter filter) override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + return m_wallet.GetCredit(txout, filter); + } CoinsList listCoins() override { LOCK2(::cs_main, m_wallet.cs_wallet); diff --git a/src/interface/wallet.h b/src/interface/wallet.h index 4510276446..b66ed63398 100644 --- a/src/interface/wallet.h +++ b/src/interface/wallet.h @@ -33,7 +33,9 @@ class Handler; class PendingWalletTx; struct WalletAddress; struct WalletBalances; +struct WalletTx; struct WalletTxOut; +struct WalletTxStatus; using WalletOrderForm = std::vector<std::pair<std::string, std::string>>; using WalletValueMap = std::map<std::string, std::string>; @@ -158,6 +160,29 @@ public: std::vector<std::string>& errors, uint256& bumped_txid) = 0; + //! Get a transaction. + virtual CTransactionRef getTx(const uint256& txid) = 0; + + //! Get transaction information. + virtual WalletTx getWalletTx(const uint256& txid) = 0; + + //! Get list of all wallet transactions. + virtual std::vector<WalletTx> getWalletTxs() = 0; + + //! Try to get updated status for a particular transaction, if possible without blocking. + virtual bool tryGetTxStatus(const uint256& txid, + WalletTxStatus& tx_status, + int& num_blocks, + int64_t& adjusted_time) = 0; + + //! Get transaction details. + virtual WalletTx getWalletTxDetails(const uint256& txid, + WalletTxStatus& tx_status, + WalletOrderForm& order_form, + bool& in_mempool, + int& num_blocks, + int64_t& adjusted_time) = 0; + //! Get balances. virtual WalletBalances getBalances() = 0; @@ -170,6 +195,18 @@ public: //! Get available balance. virtual CAmount getAvailableBalance(const CCoinControl& coin_control) = 0; + //! Return whether transaction input belongs to wallet. + virtual isminetype txinIsMine(const CTxIn& txin) = 0; + + //! Return whether transaction output belongs to wallet. + virtual isminetype txoutIsMine(const CTxOut& txout) = 0; + + //! Return debit amount if transaction input belongs to wallet. + virtual CAmount getDebit(const CTxIn& txin, isminefilter filter) = 0; + + //! Return credit amount if transaction input belongs to wallet. + virtual CAmount getCredit(const CTxOut& txout, isminefilter filter) = 0; + //! Return AvailableCoins + LockedCoins grouped by wallet address. //! (put change in one group with wallet address) using CoinsList = std::map<CTxDestination, std::vector<std::tuple<COutPoint, WalletTxOut>>>; @@ -265,6 +302,38 @@ struct WalletBalances } }; +// Wallet transaction information. +struct WalletTx +{ + CTransactionRef tx; + std::vector<isminetype> txin_is_mine; + std::vector<isminetype> txout_is_mine; + std::vector<CTxDestination> txout_address; + std::vector<isminetype> txout_address_is_mine; + CAmount credit; + CAmount debit; + CAmount change; + int64_t time; + std::map<std::string, std::string> value_map; + bool is_coinbase; +}; + +//! Updated transaction status. +struct WalletTxStatus +{ + int block_height; + int blocks_to_maturity; + int depth_in_main_chain; + int request_count; + unsigned int time_received; + uint32_t lock_time; + bool is_final; + bool is_trusted; + bool is_abandoned; + bool is_coinbase; + bool is_in_main_chain; +}; + //! Wallet transaction output. struct WalletTxOut { diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index a60f361dd1..54e7404b55 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -37,7 +37,6 @@ #ifdef ENABLE_WALLET #include <wallet/init.h> -#include <wallet/wallet.h> #endif #include <walletinitinterface.h> @@ -466,9 +465,8 @@ void BitcoinApplication::initializeResult(bool success) #ifdef ENABLE_WALLET bool fFirstWallet = true; auto wallets = m_node.getWallets(); - auto cwallet = ::vpwallets.begin(); for (auto& wallet : wallets) { - WalletModel * const walletModel = new WalletModel(std::move(wallet), m_node, platformStyle, *cwallet++, optionsModel); + WalletModel * const walletModel = new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel); window->addWallet(walletModel); if (fFirstWallet) { diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index f045053c3b..1c910926d4 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -12,10 +12,9 @@ #include <streams.h> -RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) : +RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : QAbstractTableModel(parent), walletModel(parent) { - Q_UNUSED(wallet); nReceiveRequestsMaxId = 0; // Load entries from wallet diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index ebad98cee8..80c7834a19 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -11,8 +11,6 @@ #include <QStringList> #include <QDateTime> -class CWallet; - class RecentRequestEntry { public: @@ -60,7 +58,7 @@ class RecentRequestsTableModel: public QAbstractTableModel Q_OBJECT public: - explicit RecentRequestsTableModel(CWallet *wallet, WalletModel *parent); + explicit RecentRequestsTableModel(WalletModel *parent); ~RecentRequestsTableModel(); enum ColumnIndex { diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index d28d4bd7e6..b266789595 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -179,7 +179,7 @@ void TestGUI() auto node = interface::MakeNode(); OptionsModel optionsModel(*node); vpwallets.insert(vpwallets.begin(), &wallet); - WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &wallet, &optionsModel); + WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel); vpwallets.erase(vpwallets.begin()); sendCoinsDialog.setModel(&walletModel); transactionView.setModel(&walletModel); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index ec5a66bc9f..409835592f 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -10,6 +10,7 @@ #include <qt/transactionrecord.h> #include <consensus/consensus.h> +#include <interface/node.h> #include <key_io.h> #include <validation.h> #include <script/script.h> @@ -22,25 +23,24 @@ #include <stdint.h> #include <string> -QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) +QString TransactionDesc::FormatTxStatus(const interface::WalletTx& wtx, const interface::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime) { - AssertLockHeld(cs_main); - if (!CheckFinalTx(*wtx.tx)) + if (!status.is_final) { if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD) - return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height()); + return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - numBlocks); else return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime)); } else { - int nDepth = wtx.GetDepthInMainChain(); + int nDepth = status.depth_in_main_chain; if (nDepth < 0) return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth); - else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + else if (adjustedTime - status.time_received > 2 * 60 && status.request_count == 0) return tr("%1/offline").arg(nDepth); else if (nDepth == 0) - return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : ""); + return tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + (status.is_abandoned ? ", "+tr("abandoned") : ""); else if (nDepth < 6) return tr("%1/unconfirmed").arg(nDepth); else @@ -48,21 +48,27 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) } } -QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit) +QString TransactionDesc::toHTML(interface::Node& node, interface::Wallet& wallet, TransactionRecord *rec, int unit) { + int numBlocks; + int64_t adjustedTime; + interface::WalletTxStatus status; + interface::WalletOrderForm orderForm; + bool inMempool; + interface::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, orderForm, inMempool, numBlocks, adjustedTime); + QString strHTML; - LOCK2(cs_main, wallet->cs_wallet); strHTML.reserve(4000); strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>"; - int64_t nTime = wtx.GetTxTime(); - CAmount nCredit = wtx.GetCredit(ISMINE_ALL); - CAmount nDebit = wtx.GetDebit(ISMINE_ALL); + int64_t nTime = wtx.time; + CAmount nCredit = wtx.credit; + CAmount nDebit = wtx.debit; CAmount nNet = nCredit - nDebit; - strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx); - int nRequests = wtx.GetRequestCount(); + strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks, adjustedTime); + int nRequests = status.request_count; if (nRequests != -1) { if (nRequests == 0) @@ -77,14 +83,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // From // - if (wtx.IsCoinBase()) + if (wtx.is_coinbase) { strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>"; } - else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty()) + else if (wtx.value_map.count("from") && !wtx.value_map["from"].empty()) { // Online transaction - strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>"; + strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.value_map["from"]) + "<br>"; } else { @@ -94,14 +100,16 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // Credit CTxDestination address = DecodeDestination(rec->address); if (IsValidDestination(address)) { - if (wallet->mapAddressBook.count(address)) + std::string name; + isminetype ismine; + if (wallet.getAddress(address, &name, &ismine)) { strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; strHTML += "<b>" + tr("To") + ":</b> "; strHTML += GUIUtil::HtmlEscape(rec->address); - QString addressOwned = (::IsMine(*wallet, address) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only"); - if (!wallet->mapAddressBook[address].name.empty()) - strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")"; + QString addressOwned = ismine == ISMINE_SPENDABLE ? tr("own address") : tr("watch-only"); + if (!name.empty()) + strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(name) + ")"; else strHTML += " (" + addressOwned + ")"; strHTML += "<br>"; @@ -113,31 +121,32 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // To // - if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty()) + if (wtx.value_map.count("to") && !wtx.value_map["to"].empty()) { // Online transaction - std::string strAddress = wtx.mapValue["to"]; + std::string strAddress = wtx.value_map["to"]; strHTML += "<b>" + tr("To") + ":</b> "; CTxDestination dest = DecodeDestination(strAddress); - if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty()) - strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " "; + std::string name; + if (wallet.getAddress(dest, &name) && !name.empty()) + strHTML += GUIUtil::HtmlEscape(name) + " "; strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>"; } // // Amount // - if (wtx.IsCoinBase() && nCredit == 0) + if (wtx.is_coinbase && nCredit == 0) { // // Coinbase // CAmount nUnmatured = 0; for (const CTxOut& txout : wtx.tx->vout) - nUnmatured += wallet->GetCredit(txout, ISMINE_ALL); + nUnmatured += wallet.getCredit(txout, ISMINE_ALL); strHTML += "<b>" + tr("Credit") + ":</b> "; - if (wtx.IsInMainChain()) - strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")"; + if (status.is_in_main_chain) + strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", status.blocks_to_maturity) + ")"; else strHTML += "(" + tr("not accepted") + ")"; strHTML += "<br>"; @@ -152,16 +161,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco else { isminetype fAllFromMe = ISMINE_SPENDABLE; - for (const CTxIn& txin : wtx.tx->vin) + for (isminetype mine : wtx.txin_is_mine) { - isminetype mine = wallet->IsMine(txin); if(fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; - for (const CTxOut& txout : wtx.tx->vout) + for (isminetype mine : wtx.txout_is_mine) { - isminetype mine = wallet->IsMine(txout); if(fAllToMe > mine) fAllToMe = mine; } @@ -173,22 +180,24 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Debit // + auto mine = wtx.txout_is_mine.begin(); for (const CTxOut& txout : wtx.tx->vout) { // Ignore change - isminetype toSelf = wallet->IsMine(txout); + isminetype toSelf = *(mine++); if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE)) continue; - if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty()) + if (!wtx.value_map.count("to") || wtx.value_map["to"].empty()) { // Offline transaction CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { strHTML += "<b>" + tr("To") + ":</b> "; - if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty()) - strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " "; + std::string name; + if (wallet.getAddress(address, &name) && !name.empty()) + strHTML += GUIUtil::HtmlEscape(name) + " "; strHTML += GUIUtil::HtmlEscape(EncodeDestination(address)); if(toSelf == ISMINE_SPENDABLE) strHTML += " (own address)"; @@ -206,7 +215,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (fAllToMe) { // Payment to self - CAmount nChange = wtx.GetChange(); + CAmount nChange = wtx.change; CAmount nValue = nCredit - nChange; strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>"; strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>"; @@ -221,12 +230,18 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Mixed debit transaction // - for (const CTxIn& txin : wtx.tx->vin) - if (wallet->IsMine(txin)) - strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>"; - for (const CTxOut& txout : wtx.tx->vout) - if (wallet->IsMine(txout)) - strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>"; + auto mine = wtx.txin_is_mine.begin(); + for (const CTxIn& txin : wtx.tx->vin) { + if (*(mine++)) { + strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "<br>"; + } + } + mine = wtx.txout_is_mine.begin(); + for (const CTxOut& txout : wtx.tx->vout) { + if (*(mine++)) { + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "<br>"; + } + } } } @@ -235,10 +250,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Message // - if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty()) - strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>"; - if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty()) - strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>"; + if (wtx.value_map.count("message") && !wtx.value_map["message"].empty()) + strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.value_map["message"], true) + "<br>"; + if (wtx.value_map.count("comment") && !wtx.value_map["comment"].empty()) + strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.value_map["comment"], true) + "<br>"; strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxHash() + "<br>"; strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->GetTotalSize()) + " bytes<br>"; @@ -246,14 +261,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>"; // Message from normal bitcoin:URI (bitcoin:123...?message=example) - for (const std::pair<std::string, std::string>& r : wtx.vOrderForm) + for (const std::pair<std::string, std::string>& r : orderForm) if (r.first == "Message") strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>"; // // PaymentRequest info: // - for (const std::pair<std::string, std::string>& r : wtx.vOrderForm) + for (const std::pair<std::string, std::string>& r : orderForm) { if (r.first == "PaymentRequest") { @@ -265,7 +280,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco } } - if (wtx.IsCoinBase()) + if (wtx.is_coinbase) { quint32 numBlocksToMaturity = COINBASE_MATURITY + 1; strHTML += "<br>" + tr("Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "<br>"; @@ -274,15 +289,15 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Debug view // - if (logCategories != BCLog::NONE) + if (node.getLogCategories() != BCLog::NONE) { strHTML += "<hr><br>" + tr("Debug information") + "<br><br>"; for (const CTxIn& txin : wtx.tx->vin) - if(wallet->IsMine(txin)) - strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>"; + if(wallet.txinIsMine(txin)) + strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "<br>"; for (const CTxOut& txout : wtx.tx->vout) - if(wallet->IsMine(txout)) - strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>"; + if(wallet.txoutIsMine(txout)) + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "<br>"; strHTML += "<br><b>" + tr("Transaction") + ":</b><br>"; strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true); @@ -295,7 +310,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco COutPoint prevout = txin.prevout; Coin prev; - if(pcoinsTip->GetCoin(prevout, prev)) + if(node.getUnspentOutput(prevout, prev)) { { strHTML += "<li>"; @@ -303,13 +318,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco CTxDestination address; if (ExtractDestination(vout.scriptPubKey, address)) { - if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty()) - strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " "; + std::string name; + if (wallet.getAddress(address, &name) && !name.empty()) + strHTML += GUIUtil::HtmlEscape(name) + " "; strHTML += QString::fromStdString(EncodeDestination(address)); } strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue); - strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>"; - strHTML = strHTML + " IsWatchOnly=" + (wallet->IsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>"; + strHTML = strHTML + " IsMine=" + (wallet.txoutIsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>"; + strHTML = strHTML + " IsWatchOnly=" + (wallet.txoutIsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>"; } } } diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h index 01b90b130f..ea9ab28ee3 100644 --- a/src/qt/transactiondesc.h +++ b/src/qt/transactiondesc.h @@ -10,8 +10,12 @@ class TransactionRecord; -class CWallet; -class CWalletTx; +namespace interface { +class Node; +class Wallet; +struct WalletTx; +struct WalletTxStatus; +} /** Provide a human-readable extended HTML description of a transaction. */ @@ -20,12 +24,12 @@ class TransactionDesc: public QObject Q_OBJECT public: - static QString toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit); + static QString toHTML(interface::Node& node, interface::Wallet& wallet, TransactionRecord *rec, int unit); private: TransactionDesc() {} - static QString FormatTxStatus(const CWalletTx& wtx); + static QString FormatTxStatus(const interface::WalletTx& wtx, const interface::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime); }; #endif // BITCOIN_QT_TRANSACTIONDESC_H diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index cc30cf747d..60ab2d57d7 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -5,17 +5,17 @@ #include <qt/transactionrecord.h> #include <consensus/consensus.h> +#include <interface/wallet.h> #include <key_io.h> -#include <validation.h> #include <timedata.h> -#include <wallet/wallet.h> +#include <validation.h> #include <stdint.h> /* Return positive answer if transaction should be shown in list. */ -bool TransactionRecord::showTransaction(const CWalletTx &wtx) +bool TransactionRecord::showTransaction() { // There are currently no cases where we hide transactions, but // we may want to use this in the future for things like RBF. @@ -25,17 +25,17 @@ bool TransactionRecord::showTransaction(const CWalletTx &wtx) /* * Decompose CWallet transaction to model transaction records. */ -QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) +QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface::WalletTx& wtx) { QList<TransactionRecord> parts; - int64_t nTime = wtx.GetTxTime(); - CAmount nCredit = wtx.GetCredit(ISMINE_ALL); - CAmount nDebit = wtx.GetDebit(ISMINE_ALL); + int64_t nTime = wtx.time; + CAmount nCredit = wtx.credit; + CAmount nDebit = wtx.debit; CAmount nNet = nCredit - nDebit; - uint256 hash = wtx.GetHash(); - std::map<std::string, std::string> mapValue = wtx.mapValue; + uint256 hash = wtx.tx->GetHash(); + std::map<std::string, std::string> mapValue = wtx.value_map; - if (nNet > 0 || wtx.IsCoinBase()) + if (nNet > 0 || wtx.is_coinbase) { // // Credit @@ -43,7 +43,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * for(unsigned int i = 0; i < wtx.tx->vout.size(); i++) { const CTxOut& txout = wtx.tx->vout[i]; - isminetype mine = wallet->IsMine(txout); + isminetype mine = wtx.txout_is_mine[i]; if(mine) { TransactionRecord sub(hash, nTime); @@ -51,11 +51,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * sub.idx = i; // vout index sub.credit = txout.nValue; sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; - if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) + if (wtx.txout_address_is_mine[i]) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; - sub.address = EncodeDestination(address); + sub.address = EncodeDestination(wtx.txout_address[i]); } else { @@ -63,7 +63,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } - if (wtx.IsCoinBase()) + if (wtx.is_coinbase) { // Generated sub.type = TransactionRecord::Generated; @@ -77,17 +77,15 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * { bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; - for (const CTxIn& txin : wtx.tx->vin) + for (isminetype mine : wtx.txin_is_mine) { - isminetype mine = wallet->IsMine(txin); if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; - for (const CTxOut& txout : wtx.tx->vout) + for (isminetype mine : wtx.txout_is_mine) { - isminetype mine = wallet->IsMine(txout); if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllToMe > mine) fAllToMe = mine; } @@ -95,7 +93,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * if (fAllFromMe && fAllToMe) { // Payment to self - CAmount nChange = wtx.GetChange(); + CAmount nChange = wtx.change; parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", -(nDebit - nChange), nCredit - nChange)); @@ -115,19 +113,18 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * sub.idx = nOut; sub.involvesWatchAddress = involvesWatchAddress; - if(wallet->IsMine(txout)) + if(wtx.txout_is_mine[nOut]) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } - CTxDestination address; - if (ExtractDestination(txout.scriptPubKey, address)) + if (!boost::get<CNoDestination>(&wtx.txout_address[nOut])) { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; - sub.address = EncodeDestination(address); + sub.address = EncodeDestination(wtx.txout_address[nOut]); } else { @@ -161,50 +158,46 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * return parts; } -void TransactionRecord::updateStatus(const CWalletTx &wtx) +void TransactionRecord::updateStatus(const interface::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime) { - AssertLockHeld(cs_main); // Determine transaction status - // Find the block the tx is in - const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock); - // Sort order, unrecorded transactions sort to the top status.sortKey = strprintf("%010d-%01d-%010u-%03d", - (pindex ? pindex->nHeight : std::numeric_limits<int>::max()), - (wtx.IsCoinBase() ? 1 : 0), - wtx.nTimeReceived, + wtx.block_height, + wtx.is_coinbase ? 1 : 0, + wtx.time_received, idx); - status.countsForBalance = wtx.IsTrusted() && !(wtx.GetBlocksToMaturity() > 0); - status.depth = wtx.GetDepthInMainChain(); - status.cur_num_blocks = chainActive.Height(); + status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0); + status.depth = wtx.depth_in_main_chain; + status.cur_num_blocks = numBlocks; - if (!CheckFinalTx(*wtx.tx)) + if (!wtx.is_final) { - if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD) + if (wtx.lock_time < LOCKTIME_THRESHOLD) { status.status = TransactionStatus::OpenUntilBlock; - status.open_for = wtx.tx->nLockTime - chainActive.Height(); + status.open_for = wtx.lock_time - numBlocks; } else { status.status = TransactionStatus::OpenUntilDate; - status.open_for = wtx.tx->nLockTime; + status.open_for = wtx.lock_time; } } // For generated transactions, determine maturity else if(type == TransactionRecord::Generated) { - if (wtx.GetBlocksToMaturity() > 0) + if (wtx.blocks_to_maturity > 0) { status.status = TransactionStatus::Immature; - if (wtx.IsInMainChain()) + if (wtx.is_in_main_chain) { - status.matures_in = wtx.GetBlocksToMaturity(); + status.matures_in = wtx.blocks_to_maturity; // Check if the block was requested by anyone - if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + if (adjustedTime - wtx.time_received > 2 * 60 && wtx.request_count == 0) status.status = TransactionStatus::MaturesWarning; } else @@ -223,14 +216,14 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) { status.status = TransactionStatus::Conflicted; } - else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + else if (adjustedTime - wtx.time_received > 2 * 60 && wtx.request_count == 0) { status.status = TransactionStatus::Offline; } else if (status.depth == 0) { status.status = TransactionStatus::Unconfirmed; - if (wtx.isAbandoned()) + if (wtx.is_abandoned) status.status = TransactionStatus::Abandoned; } else if (status.depth < RecommendedNumConfirmations) @@ -245,10 +238,9 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) status.needsUpdate = false; } -bool TransactionRecord::statusUpdateNeeded() const +bool TransactionRecord::statusUpdateNeeded(int numBlocks) const { - AssertLockHeld(cs_main); - return status.cur_num_blocks != chainActive.Height() || status.needsUpdate; + return status.cur_num_blocks != numBlocks || status.needsUpdate; } QString TransactionRecord::getTxHash() const diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 5321d05d15..c653584b52 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -11,8 +11,12 @@ #include <QList> #include <QString> -class CWallet; -class CWalletTx; +namespace interface { +class Node; +class Wallet; +struct WalletTx; +struct WalletTxStatus; +} /** UI model for transaction status. The transaction status is the part of a transaction that will change over time. */ @@ -106,8 +110,8 @@ public: /** Decompose CWallet transaction to model transaction records. */ - static bool showTransaction(const CWalletTx &wtx); - static QList<TransactionRecord> decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx); + static bool showTransaction(); + static QList<TransactionRecord> decomposeTransaction(const interface::WalletTx& wtx); /** @name Immutable transaction attributes @{*/ @@ -136,11 +140,11 @@ public: /** Update status from core wallet tx. */ - void updateStatus(const CWalletTx &wtx); + void updateStatus(const interface::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime); /** Return whether a status update is needed. */ - bool statusUpdateNeeded() const; + bool statusUpdateNeeded(int numBlocks) const; }; #endif // BITCOIN_QT_TRANSACTIONRECORD_H diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 84800125fe..2148ff1728 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -14,11 +14,12 @@ #include <qt/walletmodel.h> #include <core_io.h> +#include <interface/handler.h> +#include <interface/node.h> #include <validation.h> #include <sync.h> #include <uint256.h> #include <util.h> -#include <wallet/wallet.h> #include <QColor> #include <QDateTime> @@ -57,13 +58,11 @@ struct TxLessThan class TransactionTablePriv { public: - TransactionTablePriv(CWallet *_wallet, TransactionTableModel *_parent) : - wallet(_wallet), + TransactionTablePriv(TransactionTableModel *_parent) : parent(_parent) { } - CWallet *wallet; TransactionTableModel *parent; /* Local cache of wallet. @@ -74,16 +73,15 @@ public: /* Query entire wallet anew from core. */ - void refreshWallet() + void refreshWallet(interface::Wallet& wallet) { qDebug() << "TransactionTablePriv::refreshWallet"; cachedWallet.clear(); { - LOCK2(cs_main, wallet->cs_wallet); - for (const auto& entry : wallet->mapWallet) - { - if (TransactionRecord::showTransaction(entry.second)) - cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, entry.second)); + for (const auto& wtx : wallet.getWalletTxs()) { + if (TransactionRecord::showTransaction()) { + cachedWallet.append(TransactionRecord::decomposeTransaction(wtx)); + } } } } @@ -93,7 +91,7 @@ public: Call with transaction that was added, removed or changed. */ - void updateWallet(const uint256 &hash, int status, bool showTransaction) + void updateWallet(interface::Wallet& wallet, const uint256 &hash, int status, bool showTransaction) { qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status); @@ -128,17 +126,16 @@ public: } if(showTransaction) { - LOCK2(cs_main, wallet->cs_wallet); // Find transaction in wallet - std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash); - if(mi == wallet->mapWallet.end()) + interface::WalletTx wtx = wallet.getWalletTx(hash); + if(!wtx.tx) { qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet"; break; } // Added -- insert at the right position QList<TransactionRecord> toInsert = - TransactionRecord::decomposeTransaction(wallet, mi->second); + TransactionRecord::decomposeTransaction(wtx); if(!toInsert.isEmpty()) /* only if something to insert */ { parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1); @@ -179,7 +176,7 @@ public: return cachedWallet.size(); } - TransactionRecord *index(int idx) + TransactionRecord *index(interface::Wallet& wallet, int idx) { if(idx >= 0 && idx < cachedWallet.size()) { @@ -192,61 +189,42 @@ public: // If a status update is needed (blocks came in since last check), // update the status of this transaction from the wallet. Otherwise, // simply re-use the cached status. - TRY_LOCK(cs_main, lockMain); - if(lockMain) - { - TRY_LOCK(wallet->cs_wallet, lockWallet); - if(lockWallet && rec->statusUpdateNeeded()) - { - std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash); - - if(mi != wallet->mapWallet.end()) - { - rec->updateStatus(mi->second); - } - } + interface::WalletTxStatus wtx; + int numBlocks; + int64_t adjustedTime; + if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, adjustedTime) && rec->statusUpdateNeeded(numBlocks)) { + rec->updateStatus(wtx, numBlocks, adjustedTime); } return rec; } return 0; } - QString describe(TransactionRecord *rec, int unit) + QString describe(interface::Node& node, interface::Wallet& wallet, TransactionRecord *rec, int unit) { - { - LOCK2(cs_main, wallet->cs_wallet); - std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash); - if(mi != wallet->mapWallet.end()) - { - return TransactionDesc::toHTML(wallet, mi->second, rec, unit); - } - } - return QString(); + return TransactionDesc::toHTML(node, wallet, rec, unit); } - QString getTxHex(TransactionRecord *rec) + QString getTxHex(interface::Wallet& wallet, TransactionRecord *rec) { - LOCK2(cs_main, wallet->cs_wallet); - std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash); - if(mi != wallet->mapWallet.end()) - { - std::string strHex = EncodeHexTx(*mi->second.tx); + auto tx = wallet.getTx(rec->hash); + if (tx) { + std::string strHex = EncodeHexTx(*tx); return QString::fromStdString(strHex); } return QString(); } }; -TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle, CWallet* _wallet, WalletModel *parent): +TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle, WalletModel *parent): QAbstractTableModel(parent), - wallet(_wallet), walletModel(parent), - priv(new TransactionTablePriv(_wallet, this)), + priv(new TransactionTablePriv(this)), fProcessingQueuedTransactions(false), platformStyle(_platformStyle) { columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); - priv->refreshWallet(); + priv->refreshWallet(walletModel->wallet()); connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); @@ -271,7 +249,7 @@ void TransactionTableModel::updateTransaction(const QString &hash, int status, b uint256 updated; updated.SetHex(hash.toStdString()); - priv->updateWallet(updated, status, showTransaction); + priv->updateWallet(walletModel->wallet(), updated, status, showTransaction); } void TransactionTableModel::updateConfirmations() @@ -608,7 +586,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const case WatchonlyDecorationRole: return txWatchonlyDecoration(rec); case LongDescriptionRole: - return priv->describe(rec, walletModel->getOptionsModel()->getDisplayUnit()); + return priv->describe(walletModel->node(), walletModel->wallet(), rec, walletModel->getOptionsModel()->getDisplayUnit()); case AddressRole: return QString::fromStdString(rec->address); case LabelRole: @@ -618,7 +596,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const case TxHashRole: return rec->getTxHash(); case TxHexRole: - return priv->getTxHex(rec); + return priv->getTxHex(walletModel->wallet(), rec); case TxPlainTextRole: { QString details; @@ -694,10 +672,10 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const { Q_UNUSED(parent); - TransactionRecord *data = priv->index(row); + TransactionRecord *data = priv->index(walletModel->wallet(), row); if(data) { - return createIndex(row, column, priv->index(row)); + return createIndex(row, column, priv->index(walletModel->wallet(), row)); } return QModelIndex(); } @@ -735,13 +713,11 @@ private: static bool fQueueNotifications = false; static std::vector< TransactionNotification > vQueueNotifications; -static void NotifyTransactionChanged(TransactionTableModel *ttm, CWallet *wallet, const uint256 &hash, ChangeType status) +static void NotifyTransactionChanged(TransactionTableModel *ttm, const uint256 &hash, ChangeType status) { // Find transaction in wallet - std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash); // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread) - bool inWallet = mi != wallet->mapWallet.end(); - bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second)); + bool showTransaction = TransactionRecord::showTransaction(); TransactionNotification notification(hash, status, showTransaction); @@ -777,13 +753,13 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i void TransactionTableModel::subscribeToCoreSignals() { // Connect signals to wallet - wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); - wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); + m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2)); + m_handler_show_progress = walletModel->wallet().handleShowProgress(boost::bind(ShowProgress, this, _1, _2)); } void TransactionTableModel::unsubscribeFromCoreSignals() { // Disconnect signals from wallet - wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); - wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); + m_handler_transaction_changed->disconnect(); + m_handler_show_progress->disconnect(); } diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 781874d160..57566db638 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -10,13 +10,17 @@ #include <QAbstractTableModel> #include <QStringList> +#include <memory> + +namespace interface { +class Handler; +} + class PlatformStyle; class TransactionRecord; class TransactionTablePriv; class WalletModel; -class CWallet; - /** UI model for the transaction table of a wallet. */ class TransactionTableModel : public QAbstractTableModel @@ -24,7 +28,7 @@ class TransactionTableModel : public QAbstractTableModel Q_OBJECT public: - explicit TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent = 0); + explicit TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent = 0); ~TransactionTableModel(); enum ColumnIndex { @@ -80,8 +84,9 @@ public: bool processingQueuedTransactions() const { return fProcessingQueuedTransactions; } private: - CWallet* wallet; WalletModel *walletModel; + std::unique_ptr<interface::Handler> m_handler_transaction_changed; + std::unique_ptr<interface::Handler> m_handler_show_progress; QStringList columns; TransactionTablePriv *priv; bool fProcessingQueuedTransactions; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 79e1c834df..9e7955e9e3 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -5,31 +5,20 @@ #include <qt/walletmodel.h> #include <qt/addresstablemodel.h> -#include <consensus/validation.h> #include <qt/guiconstants.h> -#include <qt/guiutil.h> #include <qt/optionsmodel.h> #include <qt/paymentserver.h> #include <qt/recentrequeststablemodel.h> #include <qt/sendcoinsdialog.h> #include <qt/transactiontablemodel.h> -#include <chain.h> #include <interface/handler.h> #include <interface/node.h> #include <key_io.h> -#include <keystore.h> -#include <validation.h> -#include <net.h> // for g_connman -#include <policy/fees.h> -#include <policy/rbf.h> -#include <sync.h> #include <ui_interface.h> #include <util.h> // for GetBoolArg #include <wallet/coincontrol.h> -#include <wallet/feebumper.h> #include <wallet/wallet.h> -#include <wallet/walletdb.h> // for BackupWallet #include <stdint.h> @@ -39,8 +28,8 @@ #include <QTimer> -WalletModel::WalletModel(std::unique_ptr<interface::Wallet> wallet, interface::Node& node, const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) : - QObject(parent), m_wallet(std::move(wallet)), m_node(node), cwallet(_wallet), optionsModel(_optionsModel), addressTableModel(0), +WalletModel::WalletModel(std::unique_ptr<interface::Wallet> wallet, interface::Node& node, const PlatformStyle *platformStyle, OptionsModel *_optionsModel, QObject *parent) : + QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(0), transactionTableModel(0), recentRequestsTableModel(0), cachedEncryptionStatus(Unencrypted), @@ -50,8 +39,8 @@ WalletModel::WalletModel(std::unique_ptr<interface::Wallet> wallet, interface::N fForceCheckBalanceChanged = false; addressTableModel = new AddressTableModel(this); - transactionTableModel = new TransactionTableModel(platformStyle, cwallet, this); - recentRequestsTableModel = new RecentRequestsTableModel(cwallet, this); + transactionTableModel = new TransactionTableModel(platformStyle, this); + recentRequestsTableModel = new RecentRequestsTableModel(this); // This timer will be fired repeatedly to update the balance pollTimer = new QTimer(this); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 331c1c2a78..cf757fd2b3 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -111,7 +111,7 @@ class WalletModel : public QObject Q_OBJECT public: - explicit WalletModel(std::unique_ptr<interface::Wallet> wallet, interface::Node& node, const PlatformStyle *platformStyle, CWallet *cwallet, OptionsModel *optionsModel, QObject *parent = 0); + explicit WalletModel(std::unique_ptr<interface::Wallet> wallet, interface::Node& node, const PlatformStyle *platformStyle, OptionsModel *optionsModel, QObject *parent = 0); ~WalletModel(); enum StatusCode // Returned by sendCoins @@ -213,7 +213,6 @@ private: std::unique_ptr<interface::Handler> m_handler_watch_only_changed; interface::Node& m_node; - CWallet *cwallet; bool fHaveWatchOnly; bool fForceCheckBalanceChanged; |