PIVX Core  5.6.99
P2P Digital Currency
coldstakingmodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2021 The PIVX Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "coldstakingmodel.h"
6 #include "addressbook.h"
7 #include "bitcoinunits.h"
8 #include "guiutil.h"
9 #include "uint256.h"
10 #include <iostream>
11 
13  TransactionTableModel* _tableModel,
14  AddressTableModel* _addressTableModel,
15  QObject *parent) : QAbstractTableModel(parent), model(_model), tableModel(_tableModel), addressTableModel(_addressTableModel), cachedAmount(0){
16 }
17 
19 {
20  refresh();
21  QMetaObject::invokeMethod(this, "emitDataSetChanged", Qt::QueuedConnection);
22 }
23 
25 {
26  Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(cachedDelegations.size(), COLUMN_COUNT, QModelIndex()) );
27 }
28 
30 {
31  cachedDelegations.clear();
32  cachedAmount = 0;
33  // First get all of the p2cs utxo inside the wallet
34  std::vector<COutput> utxoList;
35  model->getAvailableP2CSCoins(utxoList);
36 
37  if (!utxoList.empty()) {
38  // Loop over each COutput into a CSDelegation
39  for (const auto& utxo : utxoList) {
40 
41  const auto *wtx = utxo.tx;
42  const QString txId = QString::fromStdString(wtx->GetHash().GetHex());
43  const CTxOut& out = wtx->tx->vout[utxo.i];
44 
45  // First parse the cs delegation
46  CSDelegation delegation;
47  if (!parseCSDelegation(out, delegation, txId, utxo.i))
48  continue;
49 
50  // it's spendable only when this wallet has the keys to spend it, a.k.a is the owner
51  delegation.isSpendable = utxo.fSpendable;
52  delegation.cachedTotalAmount += out.nValue;
53  delegation.delegatedUtxo.insert(txId, utxo.i);
54 
55  // Now verify if the delegation exists in the cached list
56  int indexDel = cachedDelegations.indexOf(delegation);
57  if (indexDel == -1) {
58  // If it doesn't, let's append it.
59  cachedDelegations.append(delegation);
60  } else {
61  CSDelegation& del = cachedDelegations[indexDel];
62  del.delegatedUtxo.unite(delegation.delegatedUtxo);
63  del.cachedTotalAmount += delegation.cachedTotalAmount;
64  }
65 
66  // add amount to cachedAmount if either:
67  // - this is a owned delegation
68  // - this is a staked delegation, and the owner is whitelisted
69  if (!delegation.isSpendable && !addressTableModel->isWhitelisted(delegation.ownerAddress)) continue;
70  cachedAmount += delegation.cachedTotalAmount;
71  }
72  }
73 }
74 
75 bool ColdStakingModel::parseCSDelegation(const CTxOut& out, CSDelegation& ret, const QString& txId, const int utxoIndex)
76 {
77  txnouttype type;
78  std::vector<CTxDestination> addresses;
79  int nRequired;
80 
81  if (!ExtractDestinations(out.scriptPubKey, type, addresses, nRequired) || addresses.size() != 2) {
82  return error("%s : Error extracting P2CS destinations for utxo: %s-%d",
83  __func__, txId.toStdString(), utxoIndex);
84  }
85 
86  std::string stakingAddressStr = EncodeDestination(
87  addresses[0],
89  );
90 
91  std::string ownerAddressStr = EncodeDestination(
92  addresses[1],
94  );
95 
96  ret = CSDelegation(stakingAddressStr, ownerAddressStr);
97 
98  return true;
99 }
100 
101 int ColdStakingModel::rowCount(const QModelIndex &parent) const
102 {
103  Q_UNUSED(parent);
104  return cachedDelegations.size();
105 }
106 
107 int ColdStakingModel::columnCount(const QModelIndex &parent) const
108 {
109  Q_UNUSED(parent);
110  return COLUMN_COUNT;
111 }
112 
113 
114 QVariant ColdStakingModel::data(const QModelIndex &index, int role) const
115 {
116  if (!index.isValid())
117  return QVariant();
118 
119  int row = index.row();
120  CSDelegation rec = cachedDelegations[row];
121  if (role == Qt::DisplayRole || role == Qt::EditRole) {
122  switch (index.column()) {
123  case OWNER_ADDRESS:
124  return QString::fromStdString(rec.ownerAddress);
125  case OWNER_ADDRESS_LABEL:
126  return addressTableModel->labelForAddress(QString::fromStdString(rec.ownerAddress));
127  case STAKING_ADDRESS:
128  return QString::fromStdString(rec.stakingAddress);
130  return addressTableModel->labelForAddress(QString::fromStdString(rec.stakingAddress));
131  case IS_WHITELISTED:
138  return qint64(rec.cachedTotalAmount);
140  return !rec.isSpendable;
141  }
142  }
143 
144  return QVariant();
145 }
146 
147 bool ColdStakingModel::whitelist(const QModelIndex& modelIndex)
148 {
149  QString address = modelIndex.data(Qt::DisplayRole).toString();
150  if (addressTableModel->isWhitelisted(address.toStdString())) {
151  return error("trying to whitelist already whitelisted address");
152  }
153 
154  if (!model->whitelistAddressFromColdStaking(address)) return false;
155 
156  // address whitelisted - update cached amount and row data
157  const int idx = modelIndex.row();
158  cachedAmount += cachedDelegations[idx].cachedTotalAmount;
160 
161  return true;
162 }
163 
164 bool ColdStakingModel::blacklist(const QModelIndex& modelIndex)
165 {
166  QString address = modelIndex.data(Qt::DisplayRole).toString();
167  if (!addressTableModel->isWhitelisted(address.toStdString())) {
168  return error("trying to blacklist already blacklisted address");
169  }
170 
171  if (!model->blacklistAddressFromColdStaking(address)) return false;
172 
173  // address blacklisted - update cached amount and row data
174  const int idx = modelIndex.row();
175  cachedAmount -= cachedDelegations[idx].cachedTotalAmount;
177 
178  return true;
179 }
180 
182 {
183  beginRemoveRows(QModelIndex(), idx, idx);
184  endRemoveRows();
185  Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, COLUMN_COUNT, QModelIndex()) );
186 }
187 
Qt model of the address book in the core.
std::string purposeForAddress(const std::string &address) const
bool isWhitelisted(const std::string &address) const
Checks if the address is whitelisted.
QString labelForAddress(const QString &address) const
std::string ownerAddress
std::string stakingAddress
QMap< QString, int > delegatedUtxo
Map of txId --> index num for stakeable utxo delegations.
CAmount cachedTotalAmount
An output of a transaction.
Definition: transaction.h:137
CScript scriptPubKey
Definition: transaction.h:140
CAmount nValue
Definition: transaction.h:139
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QList< CSDelegation > cachedDelegations
List with all of the grouped delegations received by this wallet.
bool whitelist(const QModelIndex &modelIndex)
void removeRowAndEmitDataChanged(const int idx)
bool blacklist(const QModelIndex &index)
WalletModel * model
bool parseCSDelegation(const CTxOut &out, CSDelegation &ret, const QString &txId, const int utxoIndex)
ColdStakingModel(WalletModel *model, TransactionTableModel *_tableModel, AddressTableModel *_addressTableModel, QObject *parent=nullptr)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
AddressTableModel * addressTableModel
UI model for the transaction table of a wallet.
Interface to PIVX wallet from Qt view code.
Definition: walletmodel.h:109
void getAvailableP2CSCoins(std::vector< COutput > &vCoins) const
bool blacklistAddressFromColdStaking(const QString &address)
bool whitelistAddressFromColdStaking(const QString &addressStr)
QString formatBalance(CAmount amount, int nDisplayUnit, bool isZpiv)
Definition: guiutil.cpp:119
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType)
bool ExtractDestinations(const CScript &scriptPubKey, txnouttype &typeRet, std::vector< CTxDestination > &addressRet, int &nRequiredRet)
Parse a standard scriptPubKey with one or more destination addresses.
Definition: standard.cpp:195
txnouttype
Definition: standard.h:46
bool error(const char *fmt, const Args &... args)
Definition: system.h:77