diff options
author | Russell Yanofsky <russ@yanofsky.org> | 2017-04-17 19:46:08 -0400 |
---|---|---|
committer | John Newbery <john@johnnewbery.com> | 2018-04-04 16:52:40 -0400 |
commit | 827de038ab6fa58aa3d46151eb2f8dc6add7743e (patch) | |
tree | f468c36b2f2b8a8e6f34c1ad1fc0dd4dfa275089 | |
parent | a0704a8996bb950ae3c4d5b5a30e9dfe34cde1d3 (diff) |
Remove direct bitcoin calls from qt/coincontroldialog.cpp
-rw-r--r-- | src/interface/node.cpp | 28 | ||||
-rw-r--r-- | src/interface/node.h | 21 | ||||
-rw-r--r-- | src/interface/wallet.cpp | 41 | ||||
-rw-r--r-- | src/interface/wallet.h | 19 | ||||
-rw-r--r-- | src/qt/coincontroldialog.cpp | 65 | ||||
-rw-r--r-- | src/qt/walletmodel.cpp | 32 | ||||
-rw-r--r-- | src/qt/walletmodel.h | 4 |
7 files changed, 140 insertions, 70 deletions
diff --git a/src/interface/node.cpp b/src/interface/node.cpp index db03cc0627..1bd7e48b05 100644 --- a/src/interface/node.cpp +++ b/src/interface/node.cpp @@ -15,6 +15,9 @@ #include <net_processing.h> #include <netaddress.h> #include <netbase.h> +#include <policy/feerate.h> +#include <policy/fees.h> +#include <policy/policy.h> #include <primitives/block.h> #include <rpc/server.h> #include <scheduler.h> @@ -29,6 +32,7 @@ #include <config/bitcoin-config.h> #endif #ifdef ENABLE_WALLET +#include <wallet/fees.h> #include <wallet/wallet.h> #define CHECK_WALLET(x) x #else @@ -186,7 +190,31 @@ class NodeImpl : public Node } bool getNetworkActive() override { return g_connman && g_connman->GetNetworkActive(); } unsigned int getTxConfirmTarget() override { CHECK_WALLET(return ::nTxConfirmTarget); } + CAmount getRequiredFee(unsigned int tx_bytes) override { CHECK_WALLET(return GetRequiredFee(tx_bytes)); } + CAmount getMinimumFee(unsigned int tx_bytes, + const CCoinControl& coin_control, + int* returned_target, + FeeReason* reason) override + { + FeeCalculation fee_calc; + CAmount result; + CHECK_WALLET(result = GetMinimumFee(tx_bytes, coin_control, ::mempool, ::feeEstimator, &fee_calc)); + if (returned_target) *returned_target = fee_calc.returnedTarget; + if (reason) *reason = fee_calc.reason; + return result; + } CAmount getMaxTxFee() override { return ::maxTxFee; } + CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override + { + FeeCalculation fee_calc; + CFeeRate result = ::feeEstimator.estimateSmartFee(num_blocks, &fee_calc, conservative); + if (returned_target) { + *returned_target = fee_calc.returnedTarget; + } + return result; + } + CFeeRate getDustRelayFee() override { return ::dustRelayFee; } + CFeeRate getPayTxFee() override { CHECK_WALLET(return ::payTxFee); } UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override { JSONRPCRequest req; diff --git a/src/interface/node.h b/src/interface/node.h index b0d435695e..606d1238e0 100644 --- a/src/interface/node.h +++ b/src/interface/node.h @@ -19,10 +19,13 @@ #include <tuple> #include <vector> +class CCoinControl; +class CFeeRate; class CNodeStats; class RPCTimerInterface; class UniValue; class proxyType; +enum class FeeReason; struct CNodeStateStats; namespace interface { @@ -145,9 +148,27 @@ public: //! Get tx confirm target. virtual unsigned int getTxConfirmTarget() = 0; + //! Get required fee. + virtual CAmount getRequiredFee(unsigned int tx_bytes) = 0; + + //! Get minimum fee. + virtual CAmount getMinimumFee(unsigned int tx_bytes, + const CCoinControl& coin_control, + int* returned_target, + FeeReason* reason) = 0; + //! Get max tx fee. virtual CAmount getMaxTxFee() = 0; + //! Estimate smart fee. + virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) = 0; + + //! Get dust relay fee. + virtual CFeeRate getDustRelayFee() = 0; + + //! Get pay tx fee. + virtual CFeeRate getPayTxFee() = 0; + //! Execute rpc command. virtual UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) = 0; diff --git a/src/interface/wallet.cpp b/src/interface/wallet.cpp index 8dae7ac547..cbf30f49bc 100644 --- a/src/interface/wallet.cpp +++ b/src/interface/wallet.cpp @@ -54,6 +54,17 @@ public: CReserveKey m_key; }; +//! Construct wallet TxOut struct. +WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth) +{ + WalletTxOut result; + result.txout = wtx.tx->vout[n]; + result.time = wtx.GetTxTime(); + result.depth_in_main_chain = depth; + result.is_spent = wallet.IsSpent(wtx.GetHash(), n); + return result; +} + class WalletImpl : public Wallet { public: @@ -207,6 +218,36 @@ public: { return m_wallet.GetAvailableBalance(&coin_control); } + CoinsList listCoins() override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + CoinsList result; + for (const auto& entry : m_wallet.ListCoins()) { + auto& group = result[entry.first]; + for (const auto& coin : entry.second) { + group.emplace_back( + COutPoint(coin.tx->GetHash(), coin.i), MakeWalletTxOut(m_wallet, *coin.tx, coin.i, coin.nDepth)); + } + } + return result; + } + std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override + { + LOCK2(::cs_main, m_wallet.cs_wallet); + std::vector<WalletTxOut> result; + result.reserve(outputs.size()); + for (const auto& output : outputs) { + result.emplace_back(); + auto it = m_wallet.mapWallet.find(output.hash); + if (it != m_wallet.mapWallet.end()) { + int depth = it->second.GetDepthInMainChain(); + if (depth >= 0) { + result.back() = MakeWalletTxOut(m_wallet, it->second, output.n, depth); + } + } + } + return result; + } bool hdEnabled() override { return m_wallet.IsHDEnabled(); } OutputType getDefaultAddressType() override { return m_wallet.m_default_address_type; } OutputType getDefaultChangeType() override { return m_wallet.m_default_change_type; } diff --git a/src/interface/wallet.h b/src/interface/wallet.h index 317b5c683c..6cc196fd94 100644 --- a/src/interface/wallet.h +++ b/src/interface/wallet.h @@ -16,6 +16,7 @@ #include <memory> #include <stdint.h> #include <string> +#include <tuple> #include <utility> #include <vector> @@ -30,6 +31,7 @@ namespace interface { class Handler; class PendingWalletTx; struct WalletBalances; +struct WalletTxOut; using WalletOrderForm = std::vector<std::pair<std::string, std::string>>; using WalletValueMap = std::map<std::string, std::string>; @@ -153,6 +155,14 @@ public: //! Get available balance. virtual CAmount getAvailableBalance(const CCoinControl& coin_control) = 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>>>; + virtual CoinsList listCoins() = 0; + + //! Return wallet transaction output information. + virtual std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) = 0; + // Return whether HD enabled. virtual bool hdEnabled() = 0; @@ -226,6 +236,15 @@ struct WalletBalances } }; +//! Wallet transaction output. +struct WalletTxOut +{ + CTxOut txout; + int64_t time; + int depth_in_main_chain = -1; + bool is_spent = false; +}; + //! Return implementation of Wallet interface. This function will be undefined //! in builds where ENABLE_WALLET is false. std::unique_ptr<Wallet> MakeWallet(CWallet& wallet); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 0a656a6f9b..2081d6ca08 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -14,7 +14,7 @@ #include <qt/walletmodel.h> #include <wallet/coincontrol.h> -#include <init.h> +#include <interface/node.h> #include <key_io.h> #include <policy/fees.h> #include <policy/policy.h> @@ -431,7 +431,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) { CTxOut txout(amount, static_cast<CScript>(std::vector<unsigned char>(24, 0))); txDummy.vout.push_back(txout); - fDust |= IsDust(txout, ::dustRelayFee); + fDust |= IsDust(txout, model->node().getDustRelayFee()); } } @@ -445,16 +445,16 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) bool fWitness = false; std::vector<COutPoint> vCoinControl; - std::vector<COutput> vOutputs; coinControl()->ListSelected(vCoinControl); - model->getOutputs(vCoinControl, vOutputs); - for (const COutput& out : vOutputs) { + size_t i = 0; + for (const auto& out : model->wallet().getCoins(vCoinControl)) { + if (out.depth_in_main_chain < 0) continue; + // unselect already spent, very unlikely scenario, this could happen // when selected are spent elsewhere, like rpc or another computer - uint256 txhash = out.tx->GetHash(); - COutPoint outpt(txhash, out.i); - if (model->isSpent(outpt)) + const COutPoint& outpt = vCoinControl[i++]; + if (out.is_spent) { coinControl()->UnSelect(outpt); continue; @@ -464,18 +464,18 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nQuantity++; // Amount - nAmount += out.tx->tx->vout[out.i].nValue; + nAmount += out.txout.nValue; // Bytes CTxDestination address; int witnessversion = 0; std::vector<unsigned char> witnessprogram; - if (out.tx->tx->vout[out.i].scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) + if (out.txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { nBytesInputs += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4); fWitness = true; } - else if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) + else if(ExtractDestination(out.txout.scriptPubKey, address)) { CPubKey pubkey; CKeyID *keyid = boost::get<CKeyID>(&address); @@ -509,7 +509,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nBytes -= 34; // Fee - nPayFee = GetMinimumFee(nBytes, *coinControl(), ::mempool, ::feeEstimator, nullptr /* FeeCalculation */); + nPayFee = model->node().getMinimumFee(nBytes, *coinControl(), nullptr /* returned_target */, nullptr /* reason */); if (nPayAmount > 0) { @@ -521,7 +521,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) if (nChange > 0 && nChange < MIN_CHANGE) { CTxOut txout(nChange, static_cast<CScript>(std::vector<unsigned char>(24, 0))); - if (IsDust(txout, ::dustRelayFee)) + if (IsDust(txout, model->node().getDustRelayFee())) { nPayFee += nChange; nChange = 0; @@ -621,13 +621,10 @@ void CoinControlDialog::updateView() int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); - std::map<QString, std::vector<COutput> > mapCoins; - model->listCoins(mapCoins); - - for (const std::pair<QString, std::vector<COutput>>& coins : mapCoins) { + for (const auto& coins : model->wallet().listCoins()) { CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem(); itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); - QString sWalletAddress = coins.first; + QString sWalletAddress = QString::fromStdString(EncodeDestination(coins.first)); QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); if (sWalletLabel.isEmpty()) sWalletLabel = tr("(no label)"); @@ -649,8 +646,10 @@ void CoinControlDialog::updateView() CAmount nSum = 0; int nChildren = 0; - for (const COutput& out : coins.second) { - nSum += out.tx->tx->vout[out.i].nValue; + for (const auto& outpair : coins.second) { + const COutPoint& output = std::get<0>(outpair); + const interface::WalletTxOut& out = std::get<1>(outpair); + nSum += out.txout.nValue; nChildren++; CCoinControlWidgetItem *itemOutput; @@ -662,7 +661,7 @@ void CoinControlDialog::updateView() // address CTxDestination outputAddress; QString sAddress = ""; - if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress)) + if(ExtractDestination(out.txout.scriptPubKey, outputAddress)) { sAddress = QString::fromStdString(EncodeDestination(outputAddress)); @@ -687,35 +686,33 @@ void CoinControlDialog::updateView() } // amount - itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->tx->vout[out.i].nValue)); - itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->tx->vout[out.i].nValue)); // padding so that sorting works correctly + itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.txout.nValue)); + itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.txout.nValue)); // padding so that sorting works correctly // date - itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); - itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.tx->GetTxTime())); + itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.time)); + itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.time)); // confirmations - itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth)); - itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.nDepth)); + itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.depth_in_main_chain)); + itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.depth_in_main_chain)); // transaction hash - uint256 txhash = out.tx->GetHash(); - itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex())); + itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(output.hash.GetHex())); // vout index - itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i)); + itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(output.n)); // disable locked coins - if (model->wallet().isLockedCoin(COutPoint(txhash, out.i))) + if (model->wallet().isLockedCoin(output)) { - COutPoint outpt(txhash, out.i); - coinControl()->UnSelect(outpt); // just to be sure + coinControl()->UnSelect(output); // just to be sure itemOutput->setDisabled(true); itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed")); } // set checkbox - if (coinControl()->IsSelected(COutPoint(txhash, out.i))) + if (coinControl()->IsSelected(output)) itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked); } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 7a19773cf7..8010b6097e 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -475,38 +475,6 @@ void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs) rhs.relock = false; } -// returns a list of COutputs from COutPoints -void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs) -{ - LOCK2(cs_main, cwallet->cs_wallet); - for (const COutPoint& outpoint : vOutpoints) - { - auto it = cwallet->mapWallet.find(outpoint.hash); - if (it == cwallet->mapWallet.end()) continue; - int nDepth = it->second.GetDepthInMainChain(); - if (nDepth < 0) continue; - COutput out(&it->second, outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */); - vOutputs.push_back(out); - } -} - -bool WalletModel::isSpent(const COutPoint& outpoint) const -{ - LOCK2(cs_main, cwallet->cs_wallet); - return cwallet->IsSpent(outpoint.hash, outpoint.n); -} - -// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address) -void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const -{ - for (auto& group : cwallet->ListCoins()) { - auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))]; - for (auto& coin : group.second) { - resultGroup.emplace_back(std::move(coin)); - } - } -} - void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests) { vReceiveRequests = m_wallet->getDestValues("rr"); // receive request diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 8ff19f4ae5..6a4974e957 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -191,10 +191,6 @@ public: UnlockContext requestUnlock(); - void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs); - bool isSpent(const COutPoint& outpoint) const; - void listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const; - void loadReceiveRequests(std::vector<std::string>& vReceiveRequests); bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest); |