Changeset View
Changeset View
Standalone View
Standalone View
src/qt/coincontroldialog.cpp
// Copyright (c) 2011-2016 The Bitcoin Core developers | // Copyright (c) 2011-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "coincontroldialog.h" | #include <qt/coincontroldialog.h> | ||||
#include "ui_coincontroldialog.h" | #include <qt/forms/ui_coincontroldialog.h> | ||||
#include "addresstablemodel.h" | #include <dstencode.h> | ||||
#include "bitcoinunits.h" | #include <interfaces/node.h> | ||||
#include "guiutil.h" | #include <policy/policy.h> | ||||
#include "optionsmodel.h" | #include <qt/addresstablemodel.h> | ||||
#include "platformstyle.h" | #include <qt/bitcoinunits.h> | ||||
#include "txmempool.h" | #include <qt/guiutil.h> | ||||
#include "walletmodel.h" | #include <qt/optionsmodel.h> | ||||
#include <qt/platformstyle.h> | |||||
#include "dstencode.h" | #include <qt/walletmodel.h> | ||||
#include "init.h" | #include <txmempool.h> | ||||
#include "policy/policy.h" | #include <validation.h> // For mempool | ||||
#include "validation.h" // For mempool | #include <wallet/coincontrol.h> | ||||
#include "wallet/coincontrol.h" | #include <wallet/fees.h> | ||||
#include "wallet/fees.h" | #include <wallet/wallet.h> | ||||
#include "wallet/wallet.h" | |||||
#include <QApplication> | #include <QApplication> | ||||
#include <QCheckBox> | #include <QCheckBox> | ||||
#include <QCursor> | #include <QCursor> | ||||
#include <QDialogButtonBox> | #include <QDialogButtonBox> | ||||
#include <QFlags> | #include <QFlags> | ||||
#include <QIcon> | #include <QIcon> | ||||
#include <QSettings> | #include <QSettings> | ||||
▲ Show 20 Lines • Show All 434 Lines • ▼ Show 20 Lines | void CoinControlDialog::updateLabels(WalletModel *model, QDialog *dialog) { | ||||
CMutableTransaction txDummy; | CMutableTransaction txDummy; | ||||
for (const Amount amount : CoinControlDialog::payAmounts) { | for (const Amount amount : CoinControlDialog::payAmounts) { | ||||
nPayAmount += amount; | nPayAmount += amount; | ||||
if (amount > Amount::zero()) { | if (amount > Amount::zero()) { | ||||
CTxOut txout(amount, | CTxOut txout(amount, | ||||
static_cast<CScript>(std::vector<uint8_t>(24, 0))); | static_cast<CScript>(std::vector<uint8_t>(24, 0))); | ||||
txDummy.vout.push_back(txout); | txDummy.vout.push_back(txout); | ||||
if (txout.IsDust(dustRelayFee)) { | if (txout.IsDust(model->node().getDustRelayFee())) { | ||||
fDust = true; | fDust = true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
Amount nAmount = Amount::zero(); | Amount nAmount = Amount::zero(); | ||||
Amount nPayFee = Amount::zero(); | Amount nPayFee = Amount::zero(); | ||||
Amount nAfterFee = Amount::zero(); | Amount nAfterFee = Amount::zero(); | ||||
Amount nChange = Amount::zero(); | Amount nChange = Amount::zero(); | ||||
unsigned int nBytes = 0; | unsigned int nBytes = 0; | ||||
unsigned int nBytesInputs = 0; | unsigned int nBytesInputs = 0; | ||||
unsigned int nQuantity = 0; | unsigned int nQuantity = 0; | ||||
int nQuantityUncompressed = 0; | int nQuantityUncompressed = 0; | ||||
std::vector<COutPoint> vCoinControl; | std::vector<COutPoint> vCoinControl; | ||||
std::vector<COutput> vOutputs; | |||||
coinControl()->ListSelected(vCoinControl); | 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 | // unselect already spent, very unlikely scenario, this could happen | ||||
// when selected are spent elsewhere, like rpc or another computer | // when selected are spent elsewhere, like rpc or another computer | ||||
uint256 txhash = out.tx->GetId(); | const COutPoint &outpt = vCoinControl[i++]; | ||||
COutPoint outpt(txhash, out.i); | if (out.is_spent) { | ||||
if (model->isSpent(outpt)) { | |||||
coinControl()->UnSelect(outpt); | coinControl()->UnSelect(outpt); | ||||
continue; | continue; | ||||
} | } | ||||
// Quantity | // Quantity | ||||
nQuantity++; | nQuantity++; | ||||
// Amount | // Amount | ||||
nAmount += out.tx->tx->vout[out.i].nValue; | nAmount += out.txout.nValue; | ||||
// Bytes | // Bytes | ||||
CTxDestination address; | CTxDestination address; | ||||
if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) { | if (ExtractDestination(out.txout.scriptPubKey, address)) { | ||||
CPubKey pubkey; | CPubKey pubkey; | ||||
CKeyID *keyid = boost::get<CKeyID>(&address); | CKeyID *keyid = boost::get<CKeyID>(&address); | ||||
if (keyid && model->wallet().getPubKey(*keyid, pubkey)) { | if (keyid && model->wallet().getPubKey(*keyid, pubkey)) { | ||||
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); | nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); | ||||
if (!pubkey.IsCompressed()) { | if (!pubkey.IsCompressed()) { | ||||
nQuantityUncompressed++; | nQuantityUncompressed++; | ||||
} | } | ||||
} else { | } else { | ||||
Show All 21 Lines | if (nQuantity > 0) { | ||||
// accurate | // accurate | ||||
if (CoinControlDialog::fSubtractFeeFromAmount) { | if (CoinControlDialog::fSubtractFeeFromAmount) { | ||||
if (nAmount - nPayAmount == Amount::zero()) { | if (nAmount - nPayAmount == Amount::zero()) { | ||||
nBytes -= 34; | nBytes -= 34; | ||||
} | } | ||||
} | } | ||||
// Fee | // Fee | ||||
nPayFee = GetMinimumFee(nBytes, g_mempool, *coinControl()); | nPayFee = model->node().getMinimumFee(nBytes, *coinControl()); | ||||
if (nPayAmount > Amount::zero()) { | if (nPayAmount > Amount::zero()) { | ||||
nChange = nAmount - nPayAmount; | nChange = nAmount - nPayAmount; | ||||
if (!CoinControlDialog::fSubtractFeeFromAmount) { | if (!CoinControlDialog::fSubtractFeeFromAmount) { | ||||
nChange -= nPayFee; | nChange -= nPayFee; | ||||
} | } | ||||
// Never create dust outputs; if we would, just add the dust to the | // Never create dust outputs; if we would, just add the dust to the | ||||
// fee. | // fee. | ||||
if (nChange > Amount::zero() && nChange < MIN_CHANGE) { | if (nChange > Amount::zero() && nChange < MIN_CHANGE) { | ||||
CTxOut txout(nChange, | CTxOut txout(nChange, | ||||
static_cast<CScript>(std::vector<uint8_t>(24, 0))); | static_cast<CScript>(std::vector<uint8_t>(24, 0))); | ||||
if (txout.IsDust(dustRelayFee)) { | if (txout.IsDust(model->node().getDustRelayFee())) { | ||||
// dust-change will be raised until no dust | // dust-change will be raised until no dust | ||||
if (CoinControlDialog::fSubtractFeeFromAmount) { | if (CoinControlDialog::fSubtractFeeFromAmount) { | ||||
nChange = txout.GetDustThreshold(dustRelayFee); | nChange = txout.GetDustThreshold( | ||||
model->node().getDustRelayFee()); | |||||
} else { | } else { | ||||
nPayFee += nChange; | nPayFee += nChange; | ||||
nChange = Amount::zero(); | nChange = Amount::zero(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (nChange == Amount::zero() && | if (nChange == Amount::zero() && | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | void CoinControlDialog::updateView() { | ||||
QFlags<Qt::ItemFlag> flgCheckbox = | QFlags<Qt::ItemFlag> flgCheckbox = | ||||
Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; | Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; | ||||
QFlags<Qt::ItemFlag> flgTristate = | QFlags<Qt::ItemFlag> flgTristate = | ||||
Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | | Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | | ||||
Qt::ItemIsTristate; | Qt::ItemIsTristate; | ||||
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); | int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); | ||||
std::map<QString, std::vector<COutput>> mapCoins; | for (const auto &coins : model->wallet().listCoins()) { | ||||
model->listCoins(mapCoins); | |||||
for (const std::pair<QString, std::vector<COutput>> &coins : mapCoins) { | |||||
CCoinControlWidgetItem *itemWalletAddress = | CCoinControlWidgetItem *itemWalletAddress = | ||||
new CCoinControlWidgetItem(); | new CCoinControlWidgetItem(); | ||||
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); | itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); | ||||
QString sWalletAddress = coins.first; | QString sWalletAddress = | ||||
QString::fromStdString(EncodeDestination(coins.first)); | |||||
QString sWalletLabel = | QString sWalletLabel = | ||||
model->getAddressTableModel()->labelForAddress(sWalletAddress); | model->getAddressTableModel()->labelForAddress(sWalletAddress); | ||||
if (sWalletLabel.isEmpty()) { | if (sWalletLabel.isEmpty()) { | ||||
sWalletLabel = tr("(no label)"); | sWalletLabel = tr("(no label)"); | ||||
} | } | ||||
if (treeMode) { | if (treeMode) { | ||||
// wallet address | // wallet address | ||||
ui->treeWidget->addTopLevelItem(itemWalletAddress); | ui->treeWidget->addTopLevelItem(itemWalletAddress); | ||||
itemWalletAddress->setFlags(flgTristate); | itemWalletAddress->setFlags(flgTristate); | ||||
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); | itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); | ||||
// label | // label | ||||
itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel); | itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel); | ||||
// address | // address | ||||
itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress); | itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress); | ||||
} | } | ||||
Amount nSum = Amount::zero(); | Amount nSum = Amount::zero(); | ||||
int nChildren = 0; | int nChildren = 0; | ||||
for (const COutput &out : coins.second) { | for (const auto &outpair : coins.second) { | ||||
nSum += out.tx->tx->vout[out.i].nValue; | const COutPoint &output = std::get<0>(outpair); | ||||
const interfaces::WalletTxOut &out = std::get<1>(outpair); | |||||
nSum += out.txout.nValue; | |||||
nChildren++; | nChildren++; | ||||
CCoinControlWidgetItem *itemOutput; | CCoinControlWidgetItem *itemOutput; | ||||
if (treeMode) { | if (treeMode) { | ||||
itemOutput = new CCoinControlWidgetItem(itemWalletAddress); | itemOutput = new CCoinControlWidgetItem(itemWalletAddress); | ||||
} else { | } else { | ||||
itemOutput = new CCoinControlWidgetItem(ui->treeWidget); | itemOutput = new CCoinControlWidgetItem(ui->treeWidget); | ||||
} | } | ||||
itemOutput->setFlags(flgCheckbox); | itemOutput->setFlags(flgCheckbox); | ||||
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); | itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); | ||||
// address | // address | ||||
CTxDestination outputAddress; | CTxDestination outputAddress; | ||||
QString sAddress = ""; | QString sAddress = ""; | ||||
if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, | if (ExtractDestination(out.txout.scriptPubKey, outputAddress)) { | ||||
outputAddress)) { | |||||
sAddress = | sAddress = | ||||
QString::fromStdString(EncodeDestination(outputAddress)); | QString::fromStdString(EncodeDestination(outputAddress)); | ||||
// if listMode or change => show bitcoin address. In tree mode, | // if listMode or change => show bitcoin address. In tree mode, | ||||
// address is not shown again for direct wallet address outputs | // address is not shown again for direct wallet address outputs | ||||
if (!treeMode || (!(sAddress == sWalletAddress))) { | if (!treeMode || (!(sAddress == sWalletAddress))) { | ||||
itemOutput->setText(COLUMN_ADDRESS, sAddress); | itemOutput->setText(COLUMN_ADDRESS, sAddress); | ||||
} | } | ||||
Show All 13 Lines | for (const auto &coins : model->wallet().listCoins()) { | ||||
sLabel = tr("(no label)"); | sLabel = tr("(no label)"); | ||||
} | } | ||||
itemOutput->setText(COLUMN_LABEL, sLabel); | itemOutput->setText(COLUMN_LABEL, sLabel); | ||||
} | } | ||||
// amount | // amount | ||||
itemOutput->setText( | itemOutput->setText( | ||||
COLUMN_AMOUNT, | COLUMN_AMOUNT, | ||||
BitcoinUnits::format(nDisplayUnit, | BitcoinUnits::format(nDisplayUnit, out.txout.nValue)); | ||||
out.tx->tx->vout[out.i].nValue)); | |||||
// padding so that sorting works correctly | // padding so that sorting works correctly | ||||
itemOutput->setData( | itemOutput->setData( | ||||
COLUMN_AMOUNT, Qt::UserRole, | COLUMN_AMOUNT, Qt::UserRole, | ||||
QVariant(qlonglong(out.tx->tx->vout[out.i].nValue / SATOSHI))); | QVariant(qlonglong(out.txout.nValue / SATOSHI))); | ||||
// date | // date | ||||
itemOutput->setText(COLUMN_DATE, | itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.time)); | ||||
GUIUtil::dateTimeStr(out.tx->GetTxTime())); | |||||
itemOutput->setData(COLUMN_DATE, Qt::UserRole, | itemOutput->setData(COLUMN_DATE, Qt::UserRole, | ||||
QVariant((qlonglong)out.tx->GetTxTime())); | QVariant((qlonglong)out.time)); | ||||
// confirmations | // confirmations | ||||
itemOutput->setText(COLUMN_CONFIRMATIONS, | itemOutput->setText(COLUMN_CONFIRMATIONS, | ||||
QString::number(out.nDepth)); | QString::number(out.depth_in_main_chain)); | ||||
itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, | itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, | ||||
QVariant((qlonglong)out.nDepth)); | QVariant((qlonglong)out.depth_in_main_chain)); | ||||
// transaction id | // transaction id | ||||
const TxId txid = out.tx->GetId(); | itemOutput->setText(COLUMN_TXHASH, QString::fromStdString( | ||||
itemOutput->setText(COLUMN_TXHASH, | output.GetTxId().GetHex())); | ||||
QString::fromStdString(txid.GetHex())); | |||||
// vout index | // vout index | ||||
itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i)); | itemOutput->setText(COLUMN_VOUT_INDEX, | ||||
QString::number(output.GetN())); | |||||
// disable locked coins | // disable locked coins | ||||
if (model->wallet().isLockedCoin(COutPoint(txid, out.i))) { | if (model->wallet().isLockedCoin(output)) { | ||||
COutPoint outpt(txid, out.i); | |||||
// just to be sure | // just to be sure | ||||
coinControl()->UnSelect(outpt); | coinControl()->UnSelect(output); | ||||
itemOutput->setDisabled(true); | itemOutput->setDisabled(true); | ||||
itemOutput->setIcon( | itemOutput->setIcon( | ||||
COLUMN_CHECKBOX, | COLUMN_CHECKBOX, | ||||
platformStyle->SingleColorIcon(":/icons/lock_closed")); | platformStyle->SingleColorIcon(":/icons/lock_closed")); | ||||
} | } | ||||
// set checkbox | // set checkbox | ||||
if (coinControl()->IsSelected(COutPoint(txid, out.i))) { | if (coinControl()->IsSelected(output)) { | ||||
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked); | itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked); | ||||
} | } | ||||
} | } | ||||
// amount | // amount | ||||
if (treeMode) { | if (treeMode) { | ||||
itemWalletAddress->setText(COLUMN_CHECKBOX, | itemWalletAddress->setText(COLUMN_CHECKBOX, | ||||
"(" + QString::number(nChildren) + ")"); | "(" + QString::number(nChildren) + ")"); | ||||
Show All 20 Lines |