Remove direct bitcoin calls from qt transaction table files

This commit is contained in:
Russell Yanofsky 2017-04-18 16:42:30 -04:00 committed by John Newbery
parent 3cab2ce5f9
commit 58845587e1
16 changed files with 410 additions and 210 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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
{

View File

@ -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) {

View File

@ -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

View File

@ -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 {

View File

@ -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);

View File

@ -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>";
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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;

View File

@ -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);

View File

@ -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;