Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Wallet] Locked sapling notes #2861

Merged
merged 5 commits into from
May 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 23 additions & 43 deletions src/qt/coincontroldialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,17 +230,18 @@ void CoinControlDialog::buttonSelectAllClicked()

void CoinControlDialog::toggleItemLock(QTreeWidgetItem* item)
{
COutPoint outpt(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt());
if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) {
model->unlockCoin(outpt);
uint256 hash = uint256S(item->text(COLUMN_TXHASH).toStdString());
int n = item->text(COLUMN_VOUT_INDEX).toUInt();
if (model->isLockedCoin(hash, n, fSelectTransparent)) {
model->unlockCoin(hash, n, fSelectTransparent);
item->setDisabled(false);
// restore cold-stake snowflake icon for P2CS which were previously locked
if (item->data(COLUMN_CHECKBOX, Qt::UserRole) == QString("Delegated"))
item->setIcon(COLUMN_CHECKBOX, QIcon("://ic-check-cold-staking-off"));
else
item->setIcon(COLUMN_CHECKBOX, QIcon());
} else {
model->lockCoin(outpt);
model->lockCoin(hash, n, fSelectTransparent);
item->setDisabled(true);
item->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed"));
}
Expand All @@ -267,12 +268,6 @@ void CoinControlDialog::toggleCoinLock()
// Toggle lock state
void CoinControlDialog::buttonToggleLockClicked()
{
if (!fSelectTransparent) { // todo: implement locked notes
ui->pushButtonToggleLock->setChecked(false);
return;
}

// Works in list-mode only
ui->treeWidget->setEnabled(false);
toggleCoinLock();
ui->treeWidget->setEnabled(true);
Expand All @@ -289,7 +284,7 @@ void CoinControlDialog::showMenu(const QPoint& point)
// disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu
if (item->text(COLUMN_TXHASH).length() == 64) { // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode)
copyTransactionHashAction->setEnabled(true);
if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) {
if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt(), fSelectTransparent)) {
lockAction->setEnabled(false);
unlockAction->setEnabled(true);
} else {
Expand Down Expand Up @@ -340,12 +335,11 @@ void CoinControlDialog::copyTransactionHash()
// context menu action: lock coin
void CoinControlDialog::lockCoin()
{
if (!fSelectTransparent) return; // todo: implement locked notes
if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked)
contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);

COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
model->lockCoin(outpt);
uint256 txHash = uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString());
int n = contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt();
model->lockCoin(txHash, n, fSelectTransparent);
contextMenuItem->setDisabled(true);
contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed"));
updateLabelLocked();
Expand All @@ -354,9 +348,9 @@ void CoinControlDialog::lockCoin()
// context menu action: unlock coin
void CoinControlDialog::unlockCoin()
{
if (!fSelectTransparent) return; // todo: implement locked notes
COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
model->unlockCoin(outpt);
uint256 txHash = uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString());
int n = contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt();
model->unlockCoin(txHash, n, fSelectTransparent);
contextMenuItem->setDisabled(false);
// restore cold-stake snowflake icon for P2CS which were previously locked
if (contextMenuItem->data(COLUMN_CHECKBOX, Qt::UserRole) == QString("Delegated"))
Expand Down Expand Up @@ -482,17 +476,12 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
// shows count of locked unspent outputs
void CoinControlDialog::updateLabelLocked()
{
if (fSelectTransparent) {
std::set<COutPoint> vOutpts = model->listLockedCoins();
if (!vOutpts.empty()) {
ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));
ui->labelLocked->setVisible(true);
} else
ui->labelLocked->setVisible(false);
} else {
int nLocked = fSelectTransparent ? model->listLockedCoins().size() : model->listLockedNotes().size();
if (nLocked > 0) {
ui->labelLocked->setText(tr("(%1 locked)").arg(nLocked));
ui->labelLocked->setVisible(true);
} else
ui->labelLocked->setVisible(false);
// TODO: implement locked notes functionality inside the wallet..
}
}

// serialized int size
Expand Down Expand Up @@ -726,16 +715,13 @@ void CoinControlDialog::loadAvailableCoin(bool treeMode,
// vout index
itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(outIndex));

// disable locked coins (!TODO: implement locked notes)
bool isLockedCoin{false};
if (fSelectTransparent) {
isLockedCoin = model->isLockedCoin(txhash, outIndex);
if (isLockedCoin) {
--nSelectableInputs;
coinControl->UnSelect({txhash, outIndex}); // just to be sure
itemOutput->setDisabled(true);
itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed"));
}
isLockedCoin = model->isLockedCoin(txhash, outIndex, fSelectTransparent);
if (isLockedCoin) {
--nSelectableInputs;
coinControl->UnSelect({txhash, outIndex}); // just to be sure
itemOutput->setDisabled(true);
itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed"));
}

// set checkbox
Expand Down Expand Up @@ -841,12 +827,6 @@ void CoinControlDialog::updateView()
// sort view
sortView(sortColumn, sortOrder);
ui->treeWidget->setEnabled(true);

// TODO: Remove this once note locking is functional
// Hide or show locking button and context menu items
lockAction->setVisible(fSelectTransparent);
unlockAction->setVisible(fSelectTransparent);
ui->pushButtonToggleLock->setVisible(fSelectTransparent);
}

void CoinControlDialog::refreshDialog()
Expand Down
6 changes: 3 additions & 3 deletions src/qt/pivx/mnmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "masternode.h"
#include "masternodeman.h"
#include "net.h" // for validateMasternodeIP
#include "primitives/transaction.h"
#include "qt/bitcoinunits.h"
#include "qt/optionsmodel.h"
#include "qt/pivx/guitransactionsutils.h"
Expand Down Expand Up @@ -408,7 +409,7 @@ CMasternodeConfig::CMasternodeEntry* MNModel::createLegacyMN(COutPoint& collater
auto ret_mn_entry = masternodeConfig.add(alias, serviceAddr+":"+port, mnKeyString, txID, indexOutStr);

// Lock collateral output
walletModel->lockCoin(collateralOut);
walletModel->lockCoin(collateralOut.hash, collateralOut.n);
return ret_mn_entry;
}

Expand Down Expand Up @@ -498,8 +499,7 @@ bool MNModel::removeLegacyMN(const std::string& alias_to_remove, const std::stri
rename(pathConfigFile, pathNewConfFile);

// Unlock collateral
COutPoint collateralOut(uint256S(tx_id), out_index);
walletModel->unlockCoin(collateralOut);
walletModel->unlockCoin(uint256S(tx_id), out_index);
// Remove alias
masternodeConfig.remove(alias_to_remove);
return true;
Expand Down
27 changes: 14 additions & 13 deletions src/qt/pivx/send.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "qt/pivx/send.h"
#include "qt/pivx/forms/ui_send.h"
#include "addresstablemodel.h"
#include "clientmodel.h"
#include "coincontrol.h"
#include "openuridialog.h"
#include "operationresult.h"
#include "optionsmodel.h"
#include "qt/pivx/addnewcontactdialog.h"
#include "qt/pivx/forms/ui_send.h"
#include "qt/pivx/guitransactionsutils.h"
#include "qt/pivx/loadingdialog.h"
#include "qt/pivx/optionbutton.h"
#include "qt/pivx/qtutils.h"
#include "qt/pivx/sendchangeaddressdialog.h"
#include "qt/pivx/optionbutton.h"
#include "qt/pivx/sendconfirmdialog.h"
#include "qt/pivx/guitransactionsutils.h"
#include "qt/pivx/loadingdialog.h"
#include "clientmodel.h"
#include "optionsmodel.h"
#include "operationresult.h"
#include "addresstablemodel.h"
#include "coincontrol.h"
#include "qt/walletmodel.h"
#include "script/standard.h"
#include "openuridialog.h"

#define REQUEST_PREPARE_TX 1
#define REQUEST_REFRESH_BALANCE 2
Expand Down Expand Up @@ -160,14 +161,14 @@ void SendWidget::refreshAmounts()
} else {
interfaces::WalletBalances balances = walletModel->GetWalletBalances();
if (isTransparent) {
totalAmount = balances.balance - balances.shielded_balance - walletModel->getLockedBalance() - total;
totalAmount = balances.balance - balances.shielded_balance - walletModel->getLockedBalance(isTransparent) - total;
if (!fDelegationsChecked) {
totalAmount -= balances.delegate_balance;
}
// show delegated balance if exist
delegatedBalance = balances.delegate_balance;
} else {
totalAmount = balances.shielded_balance - total;
totalAmount = balances.shielded_balance - total - walletModel->getLockedBalance(isTransparent);
}
titleTotalRemaining = tr("Unlocked remaining");
}
Expand Down Expand Up @@ -702,7 +703,7 @@ void SendWidget::onShieldCoinsClicked()
}

auto balances = walletModel->GetWalletBalances();
CAmount availableBalance = balances.balance - balances.shielded_balance - walletModel->getLockedBalance();
CAmount availableBalance = balances.balance - balances.shielded_balance - walletModel->getLockedBalance(true);
if (availableBalance > 0) {

// Calculate the required fee first. TODO future: Unify this code with the code in coincontroldialog into the model.
Expand Down
2 changes: 1 addition & 1 deletion src/qt/pivx/topbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ void TopBar::updateBalances(const interfaces::WalletBalances& newBalance)
// Locked balance. //TODO move this to the signal properly in the future..
CAmount nLockedBalance = 0;
if (walletModel) {
nLockedBalance = walletModel->getLockedBalance();
nLockedBalance = walletModel->getLockedBalance(true) + walletModel->getLockedBalance(false);
}
ui->labelTitle1->setText(nLockedBalance > 0 ? tr("Available (Locked included)") : tr("Available"));

Expand Down
25 changes: 17 additions & 8 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ CAmount WalletModel::getMinColdStakingAmount() const
return MIN_COLDSTAKING_AMOUNT;
}

CAmount WalletModel::getLockedBalance() const
CAmount WalletModel::getLockedBalance(bool isTransparent) const
{
return wallet->GetLockedCoins();
return isTransparent ? wallet->GetLockedCoins() : wallet->GetLockedShieldCoins();
}

bool WalletModel::haveWatchOnly() const
Expand Down Expand Up @@ -1112,22 +1112,25 @@ void WalletModel::listCoins(std::map<ListCoinsKey, std::vector<ListCoinsValue>>&
}
}

bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
bool WalletModel::isLockedCoin(uint256 hash, unsigned int n, bool isTransparent) const
{
LOCK(wallet->cs_wallet);
return wallet->IsLockedCoin(hash, n);
if (isTransparent)
return wallet->IsLockedCoin(hash, n);
else
return wallet->IsLockedNote(SaplingOutPoint(hash, n));
}

void WalletModel::lockCoin(COutPoint& output)
void WalletModel::lockCoin(uint256 hash, unsigned int n, bool isTransparent)
{
LOCK(wallet->cs_wallet);
wallet->LockCoin(output);
isTransparent ? wallet->LockCoin(COutPoint(hash, n)) : wallet->LockNote(SaplingOutPoint(hash, n));
}

void WalletModel::unlockCoin(COutPoint& output)
void WalletModel::unlockCoin(uint256 hash, unsigned int n, bool isTransparent)
{
LOCK(wallet->cs_wallet);
wallet->UnlockCoin(output);
isTransparent ? wallet->UnlockCoin(COutPoint(hash, n)) : wallet->UnlockNote(SaplingOutPoint(hash, n));
}

std::set<COutPoint> WalletModel::listLockedCoins()
Expand All @@ -1136,6 +1139,12 @@ std::set<COutPoint> WalletModel::listLockedCoins()
return wallet->ListLockedCoins();
}

std::set<SaplingOutPoint> WalletModel::listLockedNotes()
{
LOCK(wallet->cs_wallet);
return wallet->ListLockedNotes();
}

void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
{
vReceiveRequests = wallet->GetDestValues("rr"); // receive request
Expand Down
10 changes: 6 additions & 4 deletions src/qt/walletmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class WalletModel : public QObject

CAmount getBalance(const CCoinControl* coinControl = nullptr, bool fIncludeDelegated = true, bool fUnlockedOnly = false, bool fIncludeShielded = true) const;
CAmount getUnlockedBalance(const CCoinControl* coinControl = nullptr, bool fIncludeDelegated = true, bool fIncludeShielded = true) const;
CAmount getLockedBalance() const;
CAmount getLockedBalance(bool isTransparent) const;
bool haveWatchOnly() const;
CAmount getDelegatedBalance() const;

Expand Down Expand Up @@ -339,10 +339,12 @@ class WalletModel : public QObject
void listCoins(std::map<ListCoinsKey, std::vector<ListCoinsValue>>& mapCoins) const;
void listAvailableNotes(std::map<ListCoinsKey, std::vector<ListCoinsValue>>& mapCoins) const;

bool isLockedCoin(uint256 hash, unsigned int n) const;
void lockCoin(COutPoint& output);
void unlockCoin(COutPoint& output);
bool isLockedCoin(uint256 hash, unsigned int n, bool isTransparent = true) const;
void lockCoin(uint256 hash, unsigned int n, bool isTransparent = true);
void unlockCoin(uint256 hash, unsigned int n, bool isTransparent = true);

std::set<COutPoint> listLockedCoins();
std::set<SaplingOutPoint> listLockedNotes();

void loadReceiveRequests(std::vector<std::string>& vReceiveRequests);
bool saveReceiveRequest(const std::string& sAddress, const int64_t nId, const std::string& sRequest);
Expand Down
3 changes: 2 additions & 1 deletion src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ static const CRPCConvertParam vRPCConvertParams[] = {
{ "listunspent", 4, "query_options" },
{ "listunspent", 5, "include_unsafe" },
{ "lockunspent", 0, "unlock" },
{ "lockunspent", 1, "transactions" },
{ "lockunspent", 1, "transparent" },
{ "lockunspent", 2, "transactions" },
{ "logging", 0, "include" },
{ "logging", 1, "exclude" },
{ "mnbudgetvote", 4, "legacy" },
Expand Down
Loading