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