diff --git a/src/Makefile.am b/src/Makefile.am index c873941d9586..64897dec01cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -187,7 +187,6 @@ BITCOIN_CORE_H = \ evo/evonotificationinterface.h \ evo/providertx.h \ evo/specialtx.h \ - pairresult.h \ addressbook.h \ wallet/db.h \ flatfile.h \ diff --git a/src/destination_io.cpp b/src/destination_io.cpp index f4816f52c59f..5917263f481f 100644 --- a/src/destination_io.cpp +++ b/src/destination_io.cpp @@ -66,3 +66,26 @@ namespace Standard { } // End Standard namespace +Destination& Destination::operator=(const Destination& from) +{ + this->dest = from.dest; + this->isP2CS = from.isP2CS; + return *this; +} + +// Returns the key ID if Destination is a transparent "regular" destination +const CKeyID* Destination::getKeyID() +{ + const CTxDestination* regDest = Standard::GetTransparentDestination(dest); + return (regDest) ? boost::get(regDest) : nullptr; +} + +std::string Destination::ToString() const +{ + if (!Standard::IsValidDestination(dest)) { + // Invalid address + return ""; + } + return Standard::EncodeDestination(dest, isP2CS ? CChainParams::STAKING_ADDRESS : CChainParams::PUBKEY_ADDRESS); +} + diff --git a/src/destination_io.h b/src/destination_io.h index 938e693b57e6..91730bae0298 100644 --- a/src/destination_io.h +++ b/src/destination_io.h @@ -26,4 +26,23 @@ namespace Standard { } // End Standard namespace +/** + * Wrapper class for every supported address + */ +class Destination { +public: + explicit Destination() {} + explicit Destination(const CTxDestination& _dest, bool _isP2CS) : dest(_dest), isP2CS(_isP2CS) {} + explicit Destination(const libzcash::SaplingPaymentAddress& _dest) : dest(_dest) {} + + CWDestination dest{CNoDestination()}; + bool isP2CS{false}; + + Destination& operator=(const Destination& from); + // Returns the key ID if Destination is a transparent "regular" destination + const CKeyID* getKeyID(); + // Returns the encoded string address + std::string ToString() const; +}; + #endif //DESTINATION_IO_H diff --git a/src/key_io.h b/src/key_io.h index 5ded92522a7c..b6cfb58621cc 100644 --- a/src/key_io.h +++ b/src/key_io.h @@ -38,32 +38,4 @@ namespace KeyIO { } -/** - * Wrapper class for every supported address - */ -struct Destination { -public: - explicit Destination() {} - explicit Destination(const CTxDestination& _dest, bool _isP2CS) : dest(_dest), isP2CS(_isP2CS) {} - - CTxDestination dest{CNoDestination()}; - bool isP2CS{false}; - - Destination& operator=(const Destination& from) - { - this->dest = from.dest; - this->isP2CS = from.isP2CS; - return *this; - } - - std::string ToString() - { - if (!IsValidDestination(dest)) { - // Invalid address - return ""; - } - return EncodeDestination(dest, isP2CS ? CChainParams::STAKING_ADDRESS : CChainParams::PUBKEY_ADDRESS); - } -}; - #endif //PIVX_KEY_IO_H diff --git a/src/operationresult.h b/src/operationresult.h index 549e5e2b5b89..087ed5e0a0e4 100644 --- a/src/operationresult.h +++ b/src/operationresult.h @@ -27,4 +27,18 @@ inline OperationResult errorOut(const std::string& errorStr) return OperationResult(false, errorStr); } + +template +class CallResult : public OperationResult +{ +private: + Optional m_obj_res{nullopt}; +public: + CallResult() : OperationResult(false) {} + CallResult(T _obj) : OperationResult(true), m_obj_res(_obj) { } + CallResult(const std::string& error) : OperationResult(false, error) { } + const Optional& getObjResult() const { return m_obj_res; } +}; + + #endif //OPERATIONRESULT_H diff --git a/src/pairresult.h b/src/pairresult.h deleted file mode 100644 index 9cb6b3fe2d6f..000000000000 --- a/src/pairresult.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2019 The PIVX developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef PIVX_PAIRRESULT_H -#define PIVX_PAIRRESULT_H - - -class PairResult { - -public: - PairResult(bool res):result(res){} - PairResult(bool res, std::string* statusStr):result(res), status(statusStr){} - - bool result; - std::string* status = nullptr; -}; - - -#endif //PIVX_PAIRRESULT_H diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 01472ba72e14..8bc3830807e8 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -631,18 +631,9 @@ QString AddressTableModel::getAddressToShow(bool isShielded) const } // For some reason we don't have any address in our address book, let's create one - PairResult res(false); - QString addressStr; - if (!isShielded) { - Destination newAddress; - res = walletModel->getNewAddress(newAddress, "Default"); - if (res.result) { - addressStr = QString::fromStdString(newAddress.ToString()); - } - } else { - res = walletModel->getNewShieldedAddress(addressStr, "default shielded"); - } - return addressStr; + CallResult res = !isShielded ? walletModel->getNewAddress("Default") : + walletModel->getNewShieldedAddress("default shielded"); + return (res) ? QString::fromStdString(res.getObjResult()->ToString()) : "";; } void AddressTableModel::emitDataChanged(int idx) diff --git a/src/qt/pivx/masternodewizarddialog.cpp b/src/qt/pivx/masternodewizarddialog.cpp index 8d5cb6297efd..25c4850b6c04 100644 --- a/src/qt/pivx/masternodewizarddialog.cpp +++ b/src/qt/pivx/masternodewizarddialog.cpp @@ -9,7 +9,6 @@ #include "clientmodel.h" #include "key_io.h" #include "optionsmodel.h" -#include "pairresult.h" #include "qt/pivx/mnmodel.h" #include "qt/pivx/guitransactionsutils.h" #include "qt/pivx/qtutils.h" @@ -221,18 +220,16 @@ bool MasterNodeWizardDialog::createMN() // If not found create a new collateral tx if (!walletModel->getMNCollateralCandidate(collateralOut)) { // New receive address - Destination dest; - PairResult r = walletModel->getNewAddress(dest, alias); - - if (!r.result) { + auto r = walletModel->getNewAddress(alias); + if (!r) { // generate address fail - inform(tr(r.status->c_str())); + inform(tr(r.getError().c_str())); return false; } // const QString& addr, const QString& label, const CAmount& amount, const QString& message SendCoinsRecipient sendCoinsRecipient( - QString::fromStdString(dest.ToString()), + QString::fromStdString(r.getObjResult()->ToString()), QString::fromStdString(alias), clientModel->getMNCollateralRequiredAmount(), ""); diff --git a/src/qt/pivx/receivewidget.cpp b/src/qt/pivx/receivewidget.cpp index c17dbe9725b1..220c0eb2497c 100644 --- a/src/qt/pivx/receivewidget.cpp +++ b/src/qt/pivx/receivewidget.cpp @@ -12,7 +12,6 @@ #include "qt/pivx/addressholder.h" #include "walletmodel.h" #include "guiutil.h" -#include "pairresult.h" #include #include @@ -251,23 +250,16 @@ void ReceiveWidget::onNewAddressClicked() return; } - QString strAddress; - PairResult r(false); - if (!shieldedMode) { - Destination address; - r = walletModel->getNewAddress(address, ""); - strAddress = QString::fromStdString(address.ToString()); - } else { - r = walletModel->getNewShieldedAddress(strAddress, ""); - } + CallResult r = !shieldedMode ? walletModel->getNewAddress("") : + walletModel->getNewShieldedAddress(""); // Check validity - if (!r.result) { - inform(r.status->c_str()); + if (!r) { + inform(r.getError().c_str()); return; } - refreshView(strAddress); + refreshView(QString::fromStdString(r.getObjResult()->ToString())); inform(tr("New address created")); } catch (const std::runtime_error& error) { // Error generating address diff --git a/src/qt/pivx/requestdialog.cpp b/src/qt/pivx/requestdialog.cpp index cb0e685f2b1b..31196111824d 100644 --- a/src/qt/pivx/requestdialog.cpp +++ b/src/qt/pivx/requestdialog.cpp @@ -9,7 +9,6 @@ #include "qt/pivx/qtutils.h" #include "guiutil.h" #include "amount.h" -#include "pairresult.h" #include "optionsmodel.h" RequestDialog::RequestDialog(QWidget *parent) : @@ -114,23 +113,22 @@ void RequestDialog::accept() std::string label = info->label.isEmpty() ? "" : info->label.toStdString(); QString title; - Destination address; - PairResult r(false); + CallResult r; if (this->isPaymentRequest) { - r = walletModel->getNewAddress(address, label); + r = walletModel->getNewAddress(label); title = tr("Request for ") + BitcoinUnits::format(displayUnit, value, false, BitcoinUnits::separatorAlways) + " " + QString(CURRENCY_UNIT.c_str()); } else { - r = walletModel->getNewStakingAddress(address, label); + r = walletModel->getNewStakingAddress(label); title = tr("Cold Staking Address Generated"); } - if (!r.result) { + if (!r) { // TODO: notify user about this error close(); return; } - info->address = QString::fromStdString(address.ToString()); + info->address = QString::fromStdString(r.getObjResult()->ToString()); ui->labelTitle->setText(title); updateQr(info->address); diff --git a/src/qt/pivx/send.cpp b/src/qt/pivx/send.cpp index f9e4c401a802..9826a4a6e198 100644 --- a/src/qt/pivx/send.cpp +++ b/src/qt/pivx/send.cpp @@ -743,14 +743,12 @@ void SendWidget::onShieldCoinsClicked() // Process spending ProcessSend(recipients, true, [this](QList& recipients) { - QString strAddress; - auto res = walletModel->getNewShieldedAddress(strAddress, ""); - // Check for generation errors - if (!res.result) { + auto res = walletModel->getNewShieldedAddress(""); + if (!res) { inform(tr("Error generating address to shield PIVs")); return false; } - recipients.back().address = strAddress; + recipients.back().address = QString::fromStdString(res.getObjResult()->ToString()); resetCoinControl(); return true; }); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index cee21970c4cb..6a7cacc16f70 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -27,6 +27,7 @@ #include #include #include +#include WalletModel::WalletModel(CWallet* wallet, OptionsModel* optionsModel, QObject* parent) : QObject(parent), wallet(wallet), walletWrapper(*wallet), @@ -475,14 +476,15 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact Destination ownerAdd; if (rcp.ownerAddress.isEmpty()) { // Create new internal owner address - if (!getNewAddress(ownerAdd).result) - return CannotCreateInternalAddress; + auto res = getNewAddress(); + if (!res) return CannotCreateInternalAddress; + ownerAdd = *res.getObjResult(); } else { ownerAdd = Destination(DecodeDestination(rcp.ownerAddress.toStdString()), false); } const CKeyID* stakerId = boost::get(&out); - const CKeyID* ownerId = boost::get(&ownerAdd.dest); + const CKeyID* ownerId = ownerAdd.getKeyID(); if (!stakerId || !ownerId) { return InvalidAddress; } @@ -926,27 +928,23 @@ int64_t WalletModel::getKeyCreationTime(const libzcash::SaplingPaymentAddress& a return 0; } -PairResult WalletModel::getNewAddress(Destination& ret, std::string label) const +CallResult WalletModel::getNewAddress(const std::string& label) const { - CTxDestination dest; - PairResult res = wallet->getNewAddress(dest, label); - if (res.result) ret = Destination(dest, false); - return res; + auto res = wallet->getNewAddress(label); + return res ? CallResult(Destination(*res.getObjResult(), false)) : + CallResult(res.getError()); } -PairResult WalletModel::getNewStakingAddress(Destination& ret,std::string label) const +CallResult WalletModel::getNewStakingAddress(const std::string& label) const { - CTxDestination dest; - PairResult res = wallet->getNewStakingAddress(dest, label); - if (res.result) ret = Destination(dest, true); - return res; + auto res = wallet->getNewStakingAddress(label); + return res ? CallResult(Destination(*res.getObjResult(), true)) : + CallResult(res.getError()); } -PairResult WalletModel::getNewShieldedAddress(QString& shieldedAddrRet, std::string strLabel) +CallResult WalletModel::getNewShieldedAddress(std::string strLabel) { - shieldedAddrRet = QString::fromStdString( - KeyIO::EncodePaymentAddress(wallet->GenerateNewSaplingZKey(strLabel))); - return PairResult(true); + return CallResult(Destination(wallet->GenerateNewSaplingZKey(std::move(strLabel)))); } bool WalletModel::whitelistAddressFromColdStaking(const QString &addressStr) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 0ad630a6ec72..1b14ca6ae69a 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -14,10 +14,8 @@ #include "interfaces/wallet.h" #include "key.h" -#include "key_io.h" #include "operationresult.h" #include "support/allocators/zeroafterfree.h" -#include "pairresult.h" #include #include @@ -273,14 +271,14 @@ class WalletModel : public QObject int64_t getKeyCreationTime(const CTxDestination& address); int64_t getKeyCreationTime(const std::string& address); int64_t getKeyCreationTime(const libzcash::SaplingPaymentAddress& address); - PairResult getNewAddress(Destination& ret, std::string label = "") const; + CallResult getNewAddress(const std::string& label = "") const; /** * Return a new address used to receive for delegated cold stake purpose. */ - PairResult getNewStakingAddress(Destination& ret, std::string label = "") const; + CallResult getNewStakingAddress(const std::string& label = "") const; //! Return a new shielded address. - PairResult getNewShieldedAddress(QString& shieldedAddrRet, std::string strLabel = ""); + CallResult getNewShieldedAddress(std::string strLabel = ""); //! Return new wallet rescan reserver WalletRescanReserver getRescanReserver() const { return WalletRescanReserver(wallet); } diff --git a/src/test/librust/sapling_rpc_wallet_tests.cpp b/src/test/librust/sapling_rpc_wallet_tests.cpp index 05cb6178a4b9..8615582036a4 100644 --- a/src/test/librust/sapling_rpc_wallet_tests.cpp +++ b/src/test/librust/sapling_rpc_wallet_tests.cpp @@ -421,8 +421,9 @@ BOOST_AUTO_TEST_CASE(rpc_shieldsendmany_taddr_to_sapling) UniValue retValue; // add keys manually - CTxDestination taddr; - m_wallet.getNewAddress(taddr, ""); + auto res = m_wallet.getNewAddress(""); + BOOST_CHECK(res); + CTxDestination taddr = *res.getObjResult(); std::string taddr1 = EncodeDestination(taddr); auto zaddr1 = m_wallet.GenerateNewSaplingZKey(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ae7101e19733..32cb187dba03 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -117,11 +117,10 @@ static CTxDestination GetNewAddressFromLabel(CWallet* const pwallet, const std:: if (!params.isNull() && params.size() > 0) label = LabelFromValue(params[0]); - CTxDestination address; - PairResult r = pwallet->getNewAddress(address, label, purpose, addrType); - if(!r.result) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, *r.status); - return address; + auto r = pwallet->getNewAddress(label, purpose, addrType); + if(!r) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, r.getError()); + return *r.getObjResult(); } /** Convert CAddressBookData to JSON record. */ @@ -2437,7 +2436,7 @@ UniValue sendmany(const JSONRPCRequest& request) bool fShieldSend = false; for (const std::string& key : sendTo.getKeys()) { bool isStaking = false, isShielded = false; - const CWDestination& dest = Standard::DecodeDestination(key, isStaking, isShielded); + Standard::DecodeDestination(key, isStaking, isShielded); if (isShielded) { fShieldSend = true; break; diff --git a/src/wallet/test/wallet_sapling_transactions_validations_tests.cpp b/src/wallet/test/wallet_sapling_transactions_validations_tests.cpp index f7fd88daeea4..a4d5a4b2cf95 100644 --- a/src/wallet/test/wallet_sapling_transactions_validations_tests.cpp +++ b/src/wallet/test/wallet_sapling_transactions_validations_tests.cpp @@ -77,9 +77,10 @@ static SaplingOperation createOperationAndBuildTx(std::unique_ptr& pwal // Test double spend notes in the mempool and in blocks. BOOST_AUTO_TEST_CASE(test_in_block_and_mempool_notes_double_spend) { - CTxDestination coinbaseDest; - auto ret = pwalletMain->getNewAddress(coinbaseDest, "coinbase"); - BOOST_ASSERT_MSG(ret.result, "cannot create address"); + auto ret = pwalletMain->getNewAddress("coinbase"); + BOOST_CHECK(ret); + CTxDestination coinbaseDest = *ret.getObjResult(); + BOOST_ASSERT_MSG(ret, "cannot create address"); BOOST_ASSERT_MSG(IsValidDestination(coinbaseDest), "invalid destination"); BOOST_ASSERT_MSG(IsMine(*pwalletMain, coinbaseDest), "destination not from wallet"); @@ -126,15 +127,17 @@ BOOST_AUTO_TEST_CASE(test_in_block_and_mempool_notes_double_spend) // first generate a valid tx spending only one note // Create the operation and build the transaction - CTxDestination tDest2; - pwalletMain->getNewAddress(tDest2, "receiveValid"); + auto res = pwalletMain->getNewAddress("receiveValid"); + BOOST_CHECK(res); + CTxDestination tDest2 = *res.getObjResult(); std::vector recipients2; recipients2.emplace_back(tDest2, CAmount(90 * COIN), false); SaplingOperation operation2 = createOperationAndBuildTx(pwalletMain, recipients2, tipHeight + 1, false); // Create a second transaction that spends the same note with a different output now - CTxDestination tDest3; - pwalletMain->getNewAddress(tDest3, "receiveInvalid"); + res = pwalletMain->getNewAddress("receiveInvalid"); + BOOST_CHECK(res); + CTxDestination tDest3 = *res.getObjResult();; std::vector recipients3; recipients3.emplace_back(tDest3, CAmount(5 * COIN), false); SaplingOperation operation3 = createOperationAndBuildTx(pwalletMain, recipients3, tipHeight + 1, false); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 7fa369848239..645a7f1341e0 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -577,8 +577,9 @@ BOOST_AUTO_TEST_CASE(cached_balances_tests) wallet.SetLastBlockProcessed(chainActive.Tip()); // Receive balance from an external source - CTxDestination receivingAddr; - BOOST_ASSERT(wallet.getNewAddress(receivingAddr, "receiving_address").result); + auto res = wallet.getNewAddress("receiving_address"); + BOOST_ASSERT(res); + CTxDestination receivingAddr = *res.getObjResult(); CTxOut creditOut(nCredit/2, GetScriptForDestination(receivingAddr)); CWalletTx& wtxCredit = ReceiveBalanceWith({creditOut, creditOut},wallet); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index ea7df0aa74b8..55b47e48f320 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -12,7 +12,6 @@ #include "evo/deterministicmns.h" #include "guiinterfaceutil.h" #include "masternode.h" -#include "masternode-payments.h" #include "policy/policy.h" #include "sapling/key_io_sapling.h" #include "script/sign.h" @@ -176,15 +175,17 @@ std::vector CWallet::getWalletTxs() return result; } -PairResult CWallet::getNewAddress(CTxDestination& ret, std::string label){ - return getNewAddress(ret, label, AddressBook::AddressBookPurpose::RECEIVE); +CallResult CWallet::getNewAddress(const std::string& label) +{ + return getNewAddress(label, AddressBook::AddressBookPurpose::RECEIVE); } -PairResult CWallet::getNewStakingAddress(CTxDestination& ret, std::string label){ - return getNewAddress(ret, label, AddressBook::AddressBookPurpose::COLD_STAKING, CChainParams::Base58Type::STAKING_ADDRESS); +CallResult CWallet::getNewStakingAddress(const std::string& label) +{ + return getNewAddress(label, AddressBook::AddressBookPurpose::COLD_STAKING, CChainParams::Base58Type::STAKING_ADDRESS); } -PairResult CWallet::getNewAddress(CTxDestination& ret, const std::string addressLabel, const std::string purpose, +CallResult CWallet::getNewAddress(const std::string& addressLabel, const std::string purpose, const CChainParams::Base58Type addrType) { LOCK(cs_wallet); @@ -198,7 +199,7 @@ PairResult CWallet::getNewAddress(CTxDestination& ret, const std::string address // Get a key if (!GetKeyFromPool(newKey, type)) { // inform the user to top-up the keypool or unlock the wallet - return PairResult(false, new std::string( + return CallResult(std::string( _("Keypool ran out, please call keypoolrefill first, or unlock the wallet."))); } CKeyID keyID = newKey.GetID(); @@ -206,8 +207,7 @@ PairResult CWallet::getNewAddress(CTxDestination& ret, const std::string address if (!SetAddressBook(keyID, addressLabel, purpose)) throw std::runtime_error("CWallet::getNewAddress() : SetAddressBook failed"); - ret = CTxDestination(keyID); - return PairResult(true); + return CallResult(CTxDestination(keyID)); } int64_t CWallet::GetKeyCreationTime(const CWDestination& dest) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 9ebc998ed09c..250e5851b7a1 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -18,7 +18,7 @@ #include "key.h" #include "key_io.h" #include "keystore.h" -#include "pairresult.h" +#include "operationresult.h" #include "policy/feerate.h" #include "primitives/block.h" #include "primitives/transaction.h" @@ -886,10 +886,10 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void LockIfMyCollateral(const CTransactionRef& ptx); // keystore implementation - PairResult getNewAddress(CTxDestination& ret, const std::string addressLabel, const std::string purpose, - const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS); - PairResult getNewAddress(CTxDestination& ret, std::string label); - PairResult getNewStakingAddress(CTxDestination& ret, std::string label); + CallResult getNewAddress(const std::string& addressLabel, const std::string purpose, + const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS); + CallResult getNewAddress(const std::string& label); + CallResult getNewStakingAddress(const std::string& label); int64_t GetKeyCreationTime(const CWDestination& dest); int64_t GetKeyCreationTime(CPubKey pubkey); int64_t GetKeyCreationTime(const CTxDestination& address);