aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interface/node.cpp28
-rw-r--r--src/interface/node.h21
-rw-r--r--src/interface/wallet.cpp41
-rw-r--r--src/interface/wallet.h19
-rw-r--r--src/qt/coincontroldialog.cpp65
-rw-r--r--src/qt/walletmodel.cpp32
-rw-r--r--src/qt/walletmodel.h4
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);