Skip to content

Commit

Permalink
[qt] Move some WalletModel functions into CWallet
Browse files Browse the repository at this point in the history
>>> inspired by bitcoin/bitcoin@d944bd7

Motivation for moving these is to make supporting IPC simpler (see
bitcoin PR 10102), so these lookups can be one-shot IPC requests,
instead of back-and-forth interactions over the IPC channel.

Also these functions are potentially useful outside of the bitcoin GUI
(e.g. for RPCs).
  • Loading branch information
random-zebra committed Jun 2, 2021
1 parent 494ba64 commit 54fa122
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 43 deletions.
62 changes: 19 additions & 43 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,44 +1063,25 @@ void WalletModel::listAvailableNotes(std::map<ListCoinsKey, std::vector<ListCoin
// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
void WalletModel::listCoins(std::map<ListCoinsKey, std::vector<ListCoinsValue>>& mapCoins) const
{
CWallet::AvailableCoinsFilter filter;
filter.fIncludeLocked = true;
std::vector<COutput> vCoins;
wallet->AvailableCoins(&vCoins, nullptr, filter);

for (const COutput& out : vCoins) {
if (!out.fSpendable) continue;

const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
const bool isP2CS = scriptPubKey.IsPayToColdStaking();

CTxDestination outputAddress;
CTxDestination outputAddressStaker;
if (isP2CS) {
txnouttype type; std::vector<CTxDestination> addresses; int nRequired;
if(!ExtractDestinations(scriptPubKey, type, addresses, nRequired)
|| addresses.size() != 2) throw std::runtime_error("Cannot extract P2CS addresses from a stored transaction");
outputAddressStaker = addresses[0];
outputAddress = addresses[1];
} else {
if (!ExtractDestination(scriptPubKey, outputAddress))
continue;
for (const auto& it: wallet->ListCoins()) {
const std::pair<CTxDestination, Optional<CTxDestination>>& addresses = it.first;
const std::vector<COutput>& coins = it.second;

const QString& address = QString::fromStdString(EncodeDestination(addresses.first));
const Optional<QString>& stakerAddr = addresses.second == nullopt ? nullopt : Optional<QString>(
QString::fromStdString(EncodeDestination(*addresses.second, CChainParams::STAKING_ADDRESS)));
// P2CS cannot be "change"
const bool isChange = stakerAddr == nullopt ? wallet->IsChange(addresses.first) : false;

const ListCoinsKey key{address, isChange, stakerAddr};

for (const COutput& out: coins) {
mapCoins[key].emplace_back(out.tx->GetHash(),
out.i,
out.tx->tx->vout[out.i].nValue,
out.tx->GetTxTime(),
out.nDepth);
}

QString address = QString::fromStdString(EncodeDestination(outputAddress));
Optional<QString> stakerAddr = IsValidDestination(outputAddressStaker) ?
Optional<QString>(QString::fromStdString(EncodeDestination(outputAddressStaker, CChainParams::STAKING_ADDRESS))) :
nullopt;

ListCoinsKey key{address, wallet->IsChange(outputAddress), stakerAddr};
ListCoinsValue value{
out.tx->GetHash(),
out.i,
out.tx->tx->vout[out.i].nValue,
out.tx->GetTxTime(),
out.nDepth
};
mapCoins[key].emplace_back(value);
}
}

Expand Down Expand Up @@ -1130,12 +1111,7 @@ std::set<COutPoint> WalletModel::listLockedCoins()

void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
{
LOCK(wallet->cs_wallet);
for (auto it = wallet->NewAddressBookIterator(); it.IsValid(); it.Next()) {
for (const std::pair<std::string, std::string> &item2 : it.GetValue().destdata)
if (item2.first.size() > 2 && item2.first.substr(0, 2) == "rr") // receive request
vReceiveRequests.push_back(item2.second);
}
vReceiveRequests = wallet->GetDestValues("rr"); // receive request
}

bool WalletModel::saveReceiveRequest(const std::string& sAddress, const int64_t nId, const std::string& sRequest)
Expand Down
5 changes: 5 additions & 0 deletions src/qt/walletmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ class WalletModel : public QObject

class ListCoinsValue {
public:
ListCoinsValue() = delete;
ListCoinsValue(const uint256& _txhash, int _outIndex, CAmount _nValue, int64_t _nTime, int _nDepth) :
txhash(_txhash), outIndex(_outIndex), nValue(_nValue), nTime(_nTime), nDepth(_nDepth)
{}

uint256 txhash;
int outIndex;
CAmount nValue;
Expand Down
44 changes: 44 additions & 0 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2969,6 +2969,36 @@ bool CWallet::SelectCoinsToSpend(const std::vector<COutput>& vAvailableCoins, co
return res;
}

std::map<std::pair<CTxDestination, Optional<CTxDestination>>, std::vector<COutput>> CWallet::ListCoins() const
{
std::map<std::pair<CTxDestination, Optional<CTxDestination>>, std::vector<COutput>> result;

CWallet::AvailableCoinsFilter filter;
filter.fIncludeLocked = true;
filter.fOnlySpendable = true;
std::vector<COutput> availableCoins;
AvailableCoins(&availableCoins, nullptr, filter);

for (const COutput& coin : availableCoins) {
const CScript& scriptPubKey = coin.tx->tx->vout[coin.i].scriptPubKey;
txnouttype type; std::vector<CTxDestination> addresses; int nRequired;
if (ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
if (addresses.size() == 1) {
// P2PK, P2PKH scripts
const auto& addrpair = std::make_pair(addresses[0], nullopt);
result[addrpair].emplace_back(std::move(coin));
} else if (type == TX_COLDSTAKE) {
// P2CS scripts
assert(addresses.size() == 2);
const auto& addrpair = std::make_pair(addresses[1], Optional<CTxDestination>(addresses[0]));
result[addrpair].emplace_back(std::move(coin));
}
}
}

return result;
}

bool CWallet::CreateBudgetFeeTX(CTransactionRef& tx, const uint256& hash, CReserveKey& keyChange, bool fFinalization)
{
CScript scriptChange;
Expand Down Expand Up @@ -4047,6 +4077,20 @@ bool CWallet::LoadDestData(const CTxDestination& dest, const std::string& key, c
return true;
}

std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
{
LOCK(cs_wallet);
std::vector<std::string> values;
for (const auto& address : mapAddressBook) {
for (const auto& data : address.second.destdata) {
if (!data.first.compare(0, prefix.size(), prefix)) {
values.emplace_back(data.second);
}
}
}
return values;
}

void CWallet::AutoCombineDust(CConnman* connman)
{
{
Expand Down
9 changes: 9 additions & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,13 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface

std::map<CTxDestination, std::vector<COutput> > AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue, bool fIncludeColdStaking);

/**
* Return list of available coins and locked coins grouped by non-change output address.
* PIVX: group coins by pair <CTxDestination, Optional<CTxDestination>>. The optional destination
* is reserved for the staker address in case of P2CS.
*/
std::map<std::pair<CTxDestination, Optional<CTxDestination>>, std::vector<COutput>> ListCoins() const;

/// Get 10000 PIV output and keys which can be used for the Masternode
bool GetMasternodeVinAndKeys(CTxIn& txinRet, CPubKey& pubKeyRet,
CKey& keyRet, std::string strTxHash, std::string strOutputIndex, std::string& strError);
Expand Down Expand Up @@ -940,6 +947,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
bool EraseDestData(const CTxDestination& dest, const std::string& key);
//! Adds a destination data tuple to the store, without saving it to disk
bool LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value);
//! Get all destination values matching a prefix.
std::vector<std::string> GetDestValues(const std::string& prefix) const;

//! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CScript& dest) override;
Expand Down

0 comments on commit 54fa122

Please sign in to comment.