diff --git a/src/base58.cpp b/src/base58.cpp index c5913e4493ab..69bf6865997f 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -212,6 +212,29 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const namespace { +/** base58-encoded Bitcoin addresses. + * Public-key-hash-addresses have version 0 (or 111 testnet). + * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. + * Script-hash-addresses have version 5 (or 196 testnet). + * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. + */ +class CBitcoinAddress : public CBase58Data { +public: + bool Set(const CKeyID &id); + bool Set(const CScriptID &id); + bool Set(const CTxDestination &dest); + bool IsValid() const; + bool IsValid(const CChainParams ¶ms) const; + + CBitcoinAddress() {} + CBitcoinAddress(const CTxDestination &dest) { Set(dest); } + CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); } + CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); } + + CTxDestination Get() const; + bool GetKeyID(CKeyID &keyID) const; +}; + class CBitcoinAddressVisitor : public boost::static_visitor { private: @@ -271,23 +294,6 @@ CTxDestination CBitcoinAddress::Get() const return CNoDestination(); } -bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const -{ - if (!IsValid()) { - return false; - } else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) { - memcpy(&hashBytes, vchData.data(), 20); - type = 1; - return true; - } else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) { - memcpy(&hashBytes, vchData.data(), 20); - type = 2; - return true; - } - - return false; -} - bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const { if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) @@ -298,11 +304,6 @@ bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const return true; } -bool CBitcoinAddress::IsScript() const -{ - return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); -} - void CBitcoinSecret::SetKey(const CKey& vchSecret) { assert(vchSecret.IsValid()); @@ -335,3 +336,26 @@ bool CBitcoinSecret::SetString(const std::string& strSecret) { return SetString(strSecret.c_str()); } + +std::string EncodeDestination(const CTxDestination& dest) +{ + CBitcoinAddress addr(dest); + if (!addr.IsValid()) return ""; + return addr.ToString(); +} + +CTxDestination DecodeDestination(const std::string& str) +{ + return CBitcoinAddress(str).Get(); +} + +bool IsValidDestinationString(const std::string& str, const CChainParams& params) +{ + return CBitcoinAddress(str).IsValid(params); +} + +bool IsValidDestinationString(const std::string& str) +{ + return CBitcoinAddress(str).IsValid(); +} + diff --git a/src/base58.h b/src/base58.h index 1fea053a61ea..4b895ca02228 100644 --- a/src/base58.h +++ b/src/base58.h @@ -95,31 +95,6 @@ class CBase58Data bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } }; -/** base58-encoded Dash addresses. - * Public-key-hash-addresses have version 76 (or 140 testnet). - * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. - * Script-hash-addresses have version 16 (or 19 testnet). - * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. - */ -class CBitcoinAddress : public CBase58Data { -public: - bool Set(const CKeyID &id); - bool Set(const CScriptID &id); - bool Set(const CTxDestination &dest); - bool IsValid() const; - bool IsValid(const CChainParams ¶ms) const; - - CBitcoinAddress() {} - CBitcoinAddress(const CTxDestination &dest) { Set(dest); } - CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); } - CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); } - - CTxDestination Get() const; - bool GetKeyID(CKeyID &keyID) const; - bool GetIndexKey(uint160& hashBytes, int& type) const; - bool IsScript() const; -}; - /** * A base58-encoded secret key */ @@ -168,4 +143,9 @@ template class CBitcoinExtK typedef CBitcoinExtKeyBase CBitcoinExtKey; typedef CBitcoinExtKeyBase CBitcoinExtPubKey; +std::string EncodeDestination(const CTxDestination& dest); +CTxDestination DecodeDestination(const std::string& str); +bool IsValidDestinationString(const std::string& str); +bool IsValidDestinationString(const std::string& str, const CChainParams& params); + #endif // BITCOIN_BASE58_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 090aee3600b9..464d147fb08f 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -154,8 +154,9 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR); - for (const CTxDestination& addr : addresses) - a.push_back(CBitcoinAddress(addr).ToString()); + for (const CTxDestination& addr : addresses) { + a.push_back(EncodeDestination(addr)); + } out.pushKV("addresses", a); } @@ -190,9 +191,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, in.push_back(Pair("value", ValueFromAmount(spentInfo.satoshis))); in.push_back(Pair("valueSat", spentInfo.satoshis)); if (spentInfo.addressType == 1) { - in.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString())); + in.push_back(Pair("address", EncodeDestination(CKeyID(spentInfo.addressHash)))); } else if (spentInfo.addressType == 2) { - in.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString())); + in.push_back(Pair("address", EncodeDestination(CScriptID(spentInfo.addressHash)))); } } } diff --git a/src/dash-tx.cpp b/src/dash-tx.cpp index ef9e06f31b4b..4d26e1f6eddb 100644 --- a/src/dash-tx.cpp +++ b/src/dash-tx.cpp @@ -253,11 +253,11 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn // extract and validate ADDRESS std::string strAddr = vStrInputParts[1]; - CBitcoinAddress addr(strAddr); - if (!addr.IsValid()) + CTxDestination destination = DecodeDestination(strAddr); + if (!IsValidDestination(destination)) { throw std::runtime_error("invalid TX output address"); - // build standard output script via GetScriptForDestination() - CScript scriptPubKey = GetScriptForDestination(addr.Get()); + } + CScript scriptPubKey = GetScriptForDestination(destination); // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); @@ -290,10 +290,8 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str } if (bScriptHash) { - // Get the address for the redeem script, then call - // GetScriptForDestination() to construct a P2SH scriptPubKey. - CBitcoinAddress redeemScriptAddr(scriptPubKey); - scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get()); + // Get the ID for the script, and then construct a P2SH destination for it. + scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list @@ -355,9 +353,8 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s throw std::runtime_error(strprintf( "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); } - // GetScriptForDestination() to construct a P2SH scriptPubKey. - CBitcoinAddress addr(scriptPubKey); - scriptPubKey = GetScriptForDestination(addr.Get()); + // Get the ID for the script, and then construct a P2SH destination for it. + scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list @@ -424,8 +421,7 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str throw std::runtime_error(strprintf( "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); } - CBitcoinAddress addr(scriptPubKey); - scriptPubKey = GetScriptForDestination(addr.Get()); + scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); } // construct TxOut, append to transaction output list diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index fb919e3fc613..4b9e65d4d8b9 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -29,16 +29,16 @@ std::string CDeterministicMNState::ToString() const std::string payoutAddress = "unknown"; std::string operatorPayoutAddress = "none"; if (ExtractDestination(scriptPayout, dest)) { - payoutAddress = CBitcoinAddress(dest).ToString(); + payoutAddress = EncodeDestination(dest); } if (ExtractDestination(scriptOperatorPayout, dest)) { - operatorPayoutAddress = CBitcoinAddress(dest).ToString(); + operatorPayoutAddress = EncodeDestination(dest); } return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, " "ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)", nRegisteredHeight, nLastPaidHeight, nPoSePenalty, nPoSeRevivedHeight, nPoSeBanHeight, nRevocationReason, - CBitcoinAddress(keyIDOwner).ToString(), pubKeyOperator.Get().ToString(), CBitcoinAddress(keyIDVoting).ToString(), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress); + EncodeDestination(keyIDOwner), pubKeyOperator.Get().ToString(), EncodeDestination(keyIDVoting), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress); } void CDeterministicMNState::ToJson(UniValue& obj) const @@ -52,18 +52,16 @@ void CDeterministicMNState::ToJson(UniValue& obj) const obj.push_back(Pair("PoSeRevivedHeight", nPoSeRevivedHeight)); obj.push_back(Pair("PoSeBanHeight", nPoSeBanHeight)); obj.push_back(Pair("revocationReason", nRevocationReason)); - obj.push_back(Pair("ownerAddress", CBitcoinAddress(keyIDOwner).ToString())); - obj.push_back(Pair("votingAddress", CBitcoinAddress(keyIDVoting).ToString())); + obj.push_back(Pair("ownerAddress", EncodeDestination(keyIDOwner))); + obj.push_back(Pair("votingAddress", EncodeDestination(keyIDVoting))); CTxDestination dest; if (ExtractDestination(scriptPayout, dest)) { - CBitcoinAddress payoutAddress(dest); - obj.push_back(Pair("payoutAddress", payoutAddress.ToString())); + obj.push_back(Pair("payoutAddress", EncodeDestination(dest))); } obj.push_back(Pair("pubKeyOperator", pubKeyOperator.Get().ToString())); if (ExtractDestination(scriptOperatorPayout, dest)) { - CBitcoinAddress operatorPayoutAddress(dest); - obj.push_back(Pair("operatorPayoutAddress", operatorPayoutAddress.ToString())); + obj.push_back(Pair("operatorPayoutAddress", EncodeDestination(dest))); } } @@ -88,7 +86,7 @@ void CDeterministicMN::ToJson(UniValue& obj) const if (GetUTXOCoin(collateralOutpoint, coin)) { CTxDestination dest; if (ExtractDestination(coin.out.scriptPubKey, dest)) { - obj.push_back(Pair("collateralAddress", CBitcoinAddress(dest).ToString())); + obj.push_back(Pair("collateralAddress", EncodeDestination(dest))); } } diff --git a/src/evo/providertx.cpp b/src/evo/providertx.cpp index 2b33aa9b5a5f..a0a21a61239c 100644 --- a/src/evo/providertx.cpp +++ b/src/evo/providertx.cpp @@ -132,7 +132,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid } CTxDestination collateralTxDest; - CKeyID keyForPayloadSig; + const CKeyID *keyForPayloadSig = nullptr; COutPoint collateralOutpoint; if (!ptx.collateralOutpoint.hash.IsNull()) { @@ -147,7 +147,8 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid // Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH. // Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx - if (!CBitcoinAddress(collateralTxDest).GetKeyID(keyForPayloadSig)) { + keyForPayloadSig = boost::get(&collateralTxDest); + if (!keyForPayloadSig) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-pkh"); } @@ -197,9 +198,9 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid return false; } - if (!keyForPayloadSig.IsNull()) { + if (keyForPayloadSig) { // collateral is not part of this ProRegTx, so we must verify ownership of the collateral - if (!CheckStringSig(ptx, keyForPayloadSig, state)) { + if (!CheckStringSig(ptx, *keyForPayloadSig, state)) { return false; } } else { @@ -390,18 +391,17 @@ std::string CProRegTx::MakeSignString() const // We only include the important stuff in the string form... CTxDestination destPayout; - CBitcoinAddress addrPayout; std::string strPayout; - if (ExtractDestination(scriptPayout, destPayout) && addrPayout.Set(destPayout)) { - strPayout = addrPayout.ToString(); + if (ExtractDestination(scriptPayout, destPayout)) { + strPayout = EncodeDestination(destPayout); } else { strPayout = HexStr(scriptPayout.begin(), scriptPayout.end()); } s += strPayout + "|"; s += strprintf("%d", nOperatorReward) + "|"; - s += CBitcoinAddress(keyIDOwner).ToString() + "|"; - s += CBitcoinAddress(keyIDVoting).ToString() + "|"; + s += EncodeDestination(keyIDOwner) + "|"; + s += EncodeDestination(keyIDVoting) + "|"; // ... and also the full hash of the payload as a protection agains malleability and replays s += ::SerializeHash(*this).ToString(); @@ -414,11 +414,11 @@ std::string CProRegTx::ToString() const CTxDestination dest; std::string payee = "unknown"; if (ExtractDestination(scriptPayout, dest)) { - payee = CBitcoinAddress(dest).ToString(); + payee = EncodeDestination(dest); } return strprintf("CProRegTx(nVersion=%d, collateralOutpoint=%s, addr=%s, nOperatorReward=%f, ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, scriptPayout=%s)", - nVersion, collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, CBitcoinAddress(keyIDOwner).ToString(), pubKeyOperator.ToString(), CBitcoinAddress(keyIDVoting).ToString(), payee); + nVersion, collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, EncodeDestination(keyIDOwner), pubKeyOperator.ToString(), EncodeDestination(keyIDVoting), payee); } std::string CProUpServTx::ToString() const @@ -426,7 +426,7 @@ std::string CProUpServTx::ToString() const CTxDestination dest; std::string payee = "unknown"; if (ExtractDestination(scriptOperatorPayout, dest)) { - payee = CBitcoinAddress(dest).ToString(); + payee = EncodeDestination(dest); } return strprintf("CProUpServTx(nVersion=%d, proTxHash=%s, addr=%s, operatorPayoutAddress=%s)", @@ -438,11 +438,11 @@ std::string CProUpRegTx::ToString() const CTxDestination dest; std::string payee = "unknown"; if (ExtractDestination(scriptPayout, dest)) { - payee = CBitcoinAddress(dest).ToString(); + payee = EncodeDestination(dest); } return strprintf("CProUpRegTx(nVersion=%d, proTxHash=%s, pubKeyOperator=%s, votingAddress=%s, payoutAddress=%s)", - nVersion, proTxHash.ToString(), pubKeyOperator.ToString(), CBitcoinAddress(keyIDVoting).ToString(), payee); + nVersion, proTxHash.ToString(), pubKeyOperator.ToString(), EncodeDestination(keyIDVoting), payee); } std::string CProUpRevTx::ToString() const diff --git a/src/evo/providertx.h b/src/evo/providertx.h index 1e7218d540d0..359d3e6ae826 100644 --- a/src/evo/providertx.h +++ b/src/evo/providertx.h @@ -71,13 +71,12 @@ class CProRegTx obj.push_back(Pair("collateralHash", collateralOutpoint.hash.ToString())); obj.push_back(Pair("collateralIndex", (int)collateralOutpoint.n)); obj.push_back(Pair("service", addr.ToString(false))); - obj.push_back(Pair("ownerAddress", CBitcoinAddress(keyIDOwner).ToString())); - obj.push_back(Pair("votingAddress", CBitcoinAddress(keyIDVoting).ToString())); + obj.push_back(Pair("ownerAddress", EncodeDestination(keyIDOwner))); + obj.push_back(Pair("votingAddress", EncodeDestination(keyIDVoting))); CTxDestination dest; if (ExtractDestination(scriptPayout, dest)) { - CBitcoinAddress bitcoinAddress(dest); - obj.push_back(Pair("payoutAddress", bitcoinAddress.ToString())); + obj.push_back(Pair("payoutAddress", EncodeDestination(dest))); } obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString())); obj.push_back(Pair("operatorReward", (double)nOperatorReward / 100)); @@ -127,8 +126,7 @@ class CProUpServTx obj.push_back(Pair("service", addr.ToString(false))); CTxDestination dest; if (ExtractDestination(scriptOperatorPayout, dest)) { - CBitcoinAddress bitcoinAddress(dest); - obj.push_back(Pair("operatorPayoutAddress", bitcoinAddress.ToString())); + obj.push_back(Pair("operatorPayoutAddress", EncodeDestination(dest))); } obj.push_back(Pair("inputsHash", inputsHash.ToString())); } @@ -176,11 +174,10 @@ class CProUpRegTx obj.setObject(); obj.push_back(Pair("version", nVersion)); obj.push_back(Pair("proTxHash", proTxHash.ToString())); - obj.push_back(Pair("votingAddress", CBitcoinAddress(keyIDVoting).ToString())); + obj.push_back(Pair("votingAddress", EncodeDestination(keyIDVoting))); CTxDestination dest; if (ExtractDestination(scriptPayout, dest)) { - CBitcoinAddress bitcoinAddress(dest); - obj.push_back(Pair("payoutAddress", bitcoinAddress.ToString())); + obj.push_back(Pair("payoutAddress", EncodeDestination(dest))); } obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString())); obj.push_back(Pair("inputsHash", inputsHash.ToString())); diff --git a/src/evo/simplifiedmns.cpp b/src/evo/simplifiedmns.cpp index db272d02e0a0..91373751cb7a 100644 --- a/src/evo/simplifiedmns.cpp +++ b/src/evo/simplifiedmns.cpp @@ -37,7 +37,7 @@ uint256 CSimplifiedMNListEntry::CalcHash() const std::string CSimplifiedMNListEntry::ToString() const { return strprintf("CSimplifiedMNListEntry(proRegTxHash=%s, confirmedHash=%s, service=%s, pubKeyOperator=%s, votingAddress=%s, isValid=%d)", - proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.Get().ToString(), CBitcoinAddress(keyIDVoting).ToString(), isValid); + proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.Get().ToString(), EncodeDestination(keyIDVoting), isValid); } void CSimplifiedMNListEntry::ToJson(UniValue& obj) const @@ -48,7 +48,7 @@ void CSimplifiedMNListEntry::ToJson(UniValue& obj) const obj.push_back(Pair("confirmedHash", confirmedHash.ToString())); obj.push_back(Pair("service", service.ToString(false))); obj.push_back(Pair("pubKeyOperator", pubKeyOperator.Get().ToString())); - obj.push_back(Pair("votingAddress", CBitcoinAddress(keyIDVoting).ToString())); + obj.push_back(Pair("votingAddress", EncodeDestination(keyIDVoting))); obj.push_back(Pair("isValid", isValid)); } diff --git a/src/governance/governance-classes.cpp b/src/governance/governance-classes.cpp index e1fdd951651c..f17ac9fef0ab 100644 --- a/src/governance/governance-classes.cpp +++ b/src/governance/governance-classes.cpp @@ -345,14 +345,13 @@ bool CSuperblockManager::GetSuperblockPayments(int nBlockHeight, std::vector(&dest); + if (scriptID) { std::ostringstream ostr; ostr << "CSuperblock::ParsePaymentSchedule -- Script addresses are not supported yet : " << vecParsed1[i]; LogPrintf("%s\n", ostr.str()); @@ -535,13 +535,13 @@ void CSuperblock::ParsePaymentSchedule(const std::string& strPaymentAddresses, c LogPrint(BCLog::GOBJECT, "CSuperblock::ParsePaymentSchedule -- i = %d, amount string = %s, nAmount = %lld\n", i, vecParsed2[i], nAmount); - CGovernancePayment payment(address, nAmount); + CGovernancePayment payment(dest, nAmount); if (payment.IsValid()) { vecPayments.push_back(payment); } else { vecPayments.clear(); std::ostringstream ostr; - ostr << "CSuperblock::ParsePaymentSchedule -- Invalid payment found: address = " << address.ToString() + ostr << "CSuperblock::ParsePaymentSchedule -- Invalid payment found: address = " << EncodeDestination(dest) << ", amount = " << nAmount; LogPrintf("%s\n", ostr.str()); throw std::runtime_error(ostr.str()); @@ -651,10 +651,9 @@ bool CSuperblock::IsValid(const CTransaction& txNew, int nBlockHeight, CAmount b if (!fPaymentMatch) { // Superblock payment not found! - CTxDestination address1; - ExtractDestination(payment.script, address1); - CBitcoinAddress address2(address1); - LogPrintf("CSuperblock::IsValid -- ERROR: Block invalid: %d payment %d to %s not found\n", i, payment.nAmount, address2.ToString()); + CTxDestination dest; + ExtractDestination(payment.script, dest); + LogPrintf("CSuperblock::IsValid -- ERROR: Block invalid: %d payment %d to %s not found\n", i, payment.nAmount, EncodeDestination(dest)); return false; } @@ -718,16 +717,15 @@ std::string CSuperblockManager::GetRequiredPaymentsString(int nBlockHeight) if (pSuperblock->GetPayment(i, payment)) { // PRINT NICE LOG OUTPUT FOR SUPERBLOCK PAYMENT - CTxDestination address1; - ExtractDestination(payment.script, address1); - CBitcoinAddress address2(address1); + CTxDestination dest; + ExtractDestination(payment.script, dest); // RETURN NICE OUTPUT FOR CONSOLE if (ret != "Unknown") { - ret += ", " + address2.ToString(); + ret += ", " + EncodeDestination(dest); } else { - ret = address2.ToString(); + ret = EncodeDestination(dest); } } } diff --git a/src/governance/governance-classes.h b/src/governance/governance-classes.h index 780b9dda94b9..6606a2e42162 100644 --- a/src/governance/governance-classes.h +++ b/src/governance/governance-classes.h @@ -88,22 +88,22 @@ class CGovernancePayment { } - CGovernancePayment(CBitcoinAddress addrIn, CAmount nAmountIn) : + CGovernancePayment(CTxDestination destIn, CAmount nAmountIn) : fValid(false), script(), nAmount(0) { try { - CTxDestination dest = addrIn.Get(); + CTxDestination dest = destIn; script = GetScriptForDestination(dest); nAmount = nAmountIn; fValid = true; } catch (std::exception& e) { - LogPrintf("CGovernancePayment Payment not valid: addrIn = %s, nAmountIn = %d, what = %s\n", - addrIn.ToString(), nAmountIn, e.what()); + LogPrintf("CGovernancePayment Payment not valid: destIn = %s, nAmountIn = %d, what = %s\n", + EncodeDestination(destIn), nAmountIn, e.what()); } catch (...) { - LogPrintf("CGovernancePayment Payment not valid: addrIn = %s, nAmountIn = %d\n", - addrIn.ToString(), nAmountIn); + LogPrintf("CGovernancePayment Payment not valid: destIn = %s, nAmountIn = %d\n", + EncodeDestination(destIn), nAmountIn); } } diff --git a/src/governance/governance-validators.cpp b/src/governance/governance-validators.cpp index 64907024b537..cd42ae895c49 100644 --- a/src/governance/governance-validators.cpp +++ b/src/governance/governance-validators.cpp @@ -152,13 +152,14 @@ bool CProposalValidator::ValidatePaymentAddress() return false; } - CBitcoinAddress address(strPaymentAddress); - if (!address.IsValid()) { + CTxDestination dest = DecodeDestination(strPaymentAddress); + if (!IsValidDestination(dest)) { strErrorMessages += "payment_address is invalid;"; return false; } - if (address.IsScript()) { + const CScriptID *scriptID = boost::get(&dest); + if (scriptID) { strErrorMessages += "script addresses are not supported;"; return false; } diff --git a/src/masternode/masternode-payments.cpp b/src/masternode/masternode-payments.cpp index 7549e33766c3..589866728d0d 100644 --- a/src/masternode/masternode-payments.cpp +++ b/src/masternode/masternode-payments.cpp @@ -248,7 +248,7 @@ std::string GetRequiredPaymentsString(int nBlockHeight, const CDeterministicMNCP CTxDestination dest; if (!ExtractDestination(payee->pdmnState->scriptPayout, dest)) assert(false); - strPayee = CBitcoinAddress(dest).ToString(); + strPayee = EncodeDestination(dest); } if (CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) { strPayee += ", " + CSuperblockManager::GetRequiredPaymentsString(nBlockHeight); @@ -306,11 +306,10 @@ bool CMasternodePayments::GetMasternodeTxOuts(int nBlockHeight, CAmount blockRew } for (const auto& txout : voutMasternodePaymentsRet) { - CTxDestination address1; - ExtractDestination(txout.scriptPubKey, address1); - CBitcoinAddress address2(address1); + CTxDestination dest; + ExtractDestination(txout.scriptPubKey, dest); - LogPrintf("CMasternodePayments::%s -- Masternode payment %lld to %s\n", __func__, txout.nValue, address2.ToString()); + LogPrintf("CMasternodePayments::%s -- Masternode payment %lld to %s\n", __func__, txout.nValue, EncodeDestination(dest)); } return true; @@ -389,7 +388,7 @@ bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlo CTxDestination dest; if (!ExtractDestination(txout.scriptPubKey, dest)) assert(false); - LogPrintf("CMasternodePayments::%s -- ERROR failed to find expected payee %s in block at height %s\n", __func__, CBitcoinAddress(dest).ToString(), nBlockHeight); + LogPrintf("CMasternodePayments::%s -- ERROR failed to find expected payee %s in block at height %s\n", __func__, EncodeDestination(dest), nBlockHeight); return false; } } diff --git a/src/privatesend/privatesend-client.cpp b/src/privatesend/privatesend-client.cpp index d396ddefbe7a..4fdcf72078b8 100644 --- a/src/privatesend/privatesend-client.cpp +++ b/src/privatesend/privatesend-client.cpp @@ -1530,7 +1530,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, CAmount nValueLeft = tallyItem.nAmount; nValueLeft -= CPrivateSend::GetCollateralAmount(); // leave some room for fees - LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- 0 - %s nValueLeft: %f\n", CBitcoinAddress(tallyItem.txdest).ToString(), (float)nValueLeft / COIN); + LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- 0 - %s nValueLeft: %f\n", EncodeDestination(tallyItem.txdest), (float)nValueLeft / COIN); // ****** Add an output for mixing collaterals ************ / diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 56d6df93557a..d18a3d57e7f9 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -83,14 +83,14 @@ class AddressTablePriv LOCK(wallet->cs_wallet); for (const std::pair& item : wallet->mapAddressBook) { - const CBitcoinAddress& address = item.first; - bool fMine = IsMine(*wallet, address.Get()); + const CTxDestination& address = item.first; + bool fMine = IsMine(*wallet, address); AddressTableEntry::Type addressType = translateTransactionType( QString::fromStdString(item.second.purpose), fMine); const std::string& strName = item.second.name; cachedAddressTable.append(AddressTableEntry(addressType, QString::fromStdString(strName), - QString::fromStdString(address.ToString()))); + QString::fromStdString(EncodeDestination(address)))); } } // qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order @@ -247,7 +247,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value, if(role == Qt::EditRole) { LOCK(wallet->cs_wallet); /* For SetAddressBook / DelAddressBook */ - CTxDestination curAddress = CBitcoinAddress(rec->address.toStdString()).Get(); + CTxDestination curAddress = DecodeDestination(rec->address.toStdString()); if(index.column() == Label) { // Do nothing, if old label == new label @@ -258,7 +258,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value, } wallet->SetAddressBook(curAddress, value.toString().toStdString(), strPurpose); } else if(index.column() == Address) { - CTxDestination newAddress = CBitcoinAddress(value.toString().toStdString()).Get(); + CTxDestination newAddress = DecodeDestination(value.toString().toStdString()); // Refuse to set invalid address, set error status and return false if(boost::get(&newAddress)) { @@ -359,7 +359,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con // Check for duplicate addresses { LOCK(wallet->cs_wallet); - if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get())) + if(wallet->mapAddressBook.count(DecodeDestination(strAddress))) { editStatus = DUPLICATE_ADDRESS; return QString(); @@ -385,7 +385,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con return QString(); } } - strAddress = CBitcoinAddress(newKey.GetID()).ToString(); + strAddress = EncodeDestination(newKey.GetID()); } else { @@ -395,7 +395,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con // Add entry { LOCK(wallet->cs_wallet); - wallet->SetAddressBook(CBitcoinAddress(strAddress).Get(), strLabel, + wallet->SetAddressBook(DecodeDestination(strAddress), strLabel, (type == Send ? "send" : "receive")); } return QString::fromStdString(strAddress); @@ -413,7 +413,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent } { LOCK(wallet->cs_wallet); - wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get()); + wallet->DelAddressBook(DecodeDestination(rec->address.toStdString())); } return true; } @@ -422,14 +422,10 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent */ QString AddressTableModel::labelForAddress(const QString &address) const { - CBitcoinAddress address_parsed(address.toStdString()); - return labelForAddress(address_parsed); + CTxDestination dest = DecodeDestination(address.toStdString()); + return labelForDestination(dest); } -QString AddressTableModel::labelForAddress(const CBitcoinAddress &address) const -{ - return labelForDestination(address.Get()); -} QString AddressTableModel::labelForDestination(const CTxDestination &dest) const { diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index f55921bc6dd0..a7f027b194f3 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -68,7 +68,6 @@ class AddressTableModel : public QAbstractTableModel /* Look up label for address in address book, if not found return empty string. */ QString labelForAddress(const QString &address) const; - QString labelForAddress(const CBitcoinAddress &address) const; QString labelForDestination(const CTxDestination &dest) const; /* Look up row index of an address in the model. diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp index e95a4276cbf8..ff507dc7a268 100644 --- a/src/qt/bitcoinaddressvalidator.cpp +++ b/src/qt/bitcoinaddressvalidator.cpp @@ -90,9 +90,9 @@ QValidator::State BitcoinAddressCheckValidator::validate(QString &input, int &po { Q_UNUSED(pos); // Validate the passed Dash address - CBitcoinAddress addr(input.toStdString()); - if (addr.IsValid()) + if (IsValidDestinationString(input.toStdString())) { return QValidator::Acceptable; + } return QValidator::Invalid; } diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index d76dd059830b..052cab3b6e11 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -708,7 +708,7 @@ void CoinControlDialog::updateView() QString sAddress = ""; if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress)) { - sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString()); + sAddress = QString::fromStdString(EncodeDestination(outputAddress)); // if listMode or change => show dash address. In tree mode, address is not shown again for direct wallet address outputs if (!treeMode || (!(sAddress == sWalletAddress))) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index cbaa2faa5c71..df40e365c79b 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -170,8 +170,9 @@ static std::string DummyAddress(const CChainParams ¶ms) sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata)); for(int i=0; i<256; ++i) { // Try every trailing byte std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size()); - if (!CBitcoinAddress(s).IsValid()) + if (!IsValidDestinationString(s)) { return s; + } sourcedata[sourcedata.size()-1] += 1; } return ""; @@ -312,7 +313,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info) bool isDust(const QString& address, const CAmount& amount) { - CTxDestination dest = CBitcoinAddress(address.toStdString()).Get(); + CTxDestination dest = DecodeDestination(address.toStdString()); CScript script = GetScriptForDestination(dest); CTxOut txOut(amount, script); return IsDust(txOut, ::dustRelayFee); diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index f6163a0c6119..74555af9bc7a 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -219,7 +219,7 @@ void MasternodeList::updateDIP3List() CTxDestination payeeDest; QString payeeStr = tr("UNKNOWN"); if (ExtractDestination(dmn->pdmnState->scriptPayout, payeeDest)) { - payeeStr = QString::fromStdString(CBitcoinAddress(payeeDest).ToString()); + payeeStr = QString::fromStdString(EncodeDestination(payeeDest)); } QTableWidgetItem* payeeItem = new QTableWidgetItem(payeeStr); @@ -230,7 +230,7 @@ void MasternodeList::updateDIP3List() if (dmn->pdmnState->scriptOperatorPayout != CScript()) { CTxDestination operatorDest; if (ExtractDestination(dmn->pdmnState->scriptOperatorPayout, operatorDest)) { - operatorRewardStr += tr("to %1").arg(QString::fromStdString(CBitcoinAddress(operatorDest).ToString())); + operatorRewardStr += tr("to %1").arg(QString::fromStdString(EncodeDestination(operatorDest))); } else { operatorRewardStr += tr("to UNKNOWN"); } @@ -243,14 +243,14 @@ void MasternodeList::updateDIP3List() QString collateralStr = tr("UNKNOWN"); auto collateralDestIt = mapCollateralDests.find(dmn->proTxHash); if (collateralDestIt != mapCollateralDests.end()) { - collateralStr = QString::fromStdString(CBitcoinAddress(collateralDestIt->second).ToString()); + collateralStr = QString::fromStdString(EncodeDestination(collateralDestIt->second)); } QTableWidgetItem* collateralItem = new QTableWidgetItem(collateralStr); - QString ownerStr = QString::fromStdString(CBitcoinAddress(dmn->pdmnState->keyIDOwner).ToString()); + QString ownerStr = QString::fromStdString(EncodeDestination(dmn->pdmnState->keyIDOwner)); QTableWidgetItem* ownerItem = new QTableWidgetItem(ownerStr); - QString votingStr = QString::fromStdString(CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString()); + QString votingStr = QString::fromStdString(EncodeDestination(dmn->pdmnState->keyIDVoting)); QTableWidgetItem* votingItem = new QTableWidgetItem(votingStr); QTableWidgetItem* proTxHashItem = new QTableWidgetItem(QString::fromStdString(dmn->proTxHash.ToString())); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 5b257440fcec..9c8d9a3e66d4 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -219,17 +219,15 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) SendCoinsRecipient r; if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty()) { - CBitcoinAddress address(r.address.toStdString()); auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN); - if (address.IsValid(*tempChainParams)) - { + if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) { SelectParams(CBaseChainParams::MAIN); - } - else { + } else { tempChainParams = CreateChainParams(CBaseChainParams::TESTNET); - if (address.IsValid(*tempChainParams)) + if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) { SelectParams(CBaseChainParams::TESTNET); + } } } } @@ -442,8 +440,7 @@ void PaymentServer::handleURIOrFile(const QString& s) SendCoinsRecipient recipient; if (GUIUtil::parseBitcoinURI(s, &recipient)) { - CBitcoinAddress address(recipient.address.toStdString()); - if (!address.IsValid()) { + if (!IsValidDestinationString(recipient.address.toStdString())) { Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address), CClientUIInterface::MSG_ERROR); } @@ -561,7 +558,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen CTxDestination dest; if (ExtractDestination(sendingTo.first, dest)) { // Append destination address - addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString())); + addresses.append(QString::fromStdString(EncodeDestination(dest))); } else if (!recipient.authenticatedMerchant.isEmpty()) { // Unauthenticated payment requests to custom dash addresses are not supported diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 2de2612f5471..786c6b182178 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -870,19 +870,18 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) CoinControlDialog::coinControl->destChange = CNoDestination(); ui->labelCoinControlChangeLabel->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); - CBitcoinAddress addr = CBitcoinAddress(text.toStdString()); + const CTxDestination dest = DecodeDestination(text.toStdString()); if (text.isEmpty()) // Nothing entered { ui->labelCoinControlChangeLabel->setText(""); } - else if (!addr.IsValid()) // Invalid address + else if (!IsValidDestination(dest)) // Invalid address { ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Dash address")); } else // Valid address { - const CTxDestination dest = addr.Get(); if (!model->IsSpendable(dest)) { ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 130dc3270017..b5dd325619dd 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -51,7 +51,7 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformS ui->copySignatureButton_SM->setIcon(QIcon(":/icons/editcopy")); ui->addressBookButton_VM->setIcon(QIcon(":/icons/address-book")); - + GUIUtil::setupAddressWidget(ui->addressIn_SM, this); GUIUtil::setupAddressWidget(ui->addressIn_VM, this); @@ -128,16 +128,14 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() /* Clear old signature to ensure users don't get confused on error with an old signature displayed */ ui->signatureOut_SM->clear(); - CBitcoinAddress addr(ui->addressIn_SM->text().toStdString()); - if (!addr.IsValid()) - { + CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString()); + if (!IsValidDestination(destination)) { ui->statusLabel_SM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - CKeyID keyID; - if (!addr.GetKeyID(keyID)) - { + const CKeyID* keyID = boost::get(&destination); + if (!keyID) { ui->addressIn_SM->setValid(false); ui->statusLabel_SM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); @@ -153,7 +151,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() } CKey key; - if (!model->getPrivKey(keyID, key)) + if (!model->getPrivKey(*keyID, key)) { ui->statusLabel_SM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); ui->statusLabel_SM->setText(tr("Private key for the entered address is not available.")); @@ -208,16 +206,13 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked() void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() { - CBitcoinAddress addr(ui->addressIn_VM->text().toStdString()); - if (!addr.IsValid()) - { + CTxDestination destination = DecodeDestination(ui->addressIn_VM->text().toStdString()); + if (!IsValidDestination(destination)) { ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - CKeyID keyID; - if (!addr.GetKeyID(keyID)) - { + if (!boost::get(&destination)) { ui->addressIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); @@ -248,8 +243,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() return; } - if (!(CBitcoinAddress(pubkey.GetID()) == addr)) - { + if (!(CTxDestination(pubkey.GetID()) == destination)) { ui->statusLabel_VM->setStyleSheet(GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR)); ui->statusLabel_VM->setText(QString("") + tr("Message verification failed.") + QString("")); return; diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 7f2a916cbced..aec42f0999fe 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -37,11 +37,11 @@ void ConfirmSend() } //! Send coins to address and return txid. -uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount) +uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount) { QVBoxLayout* entries = sendCoinsDialog.findChild("entries"); SendCoinsEntry* entry = qobject_cast(entries->itemAt(0)->widget()); - entry->findChild("payTo")->setText(QString::fromStdString(address.ToString())); + entry->findChild("payTo")->setText(QString::fromStdString(EncodeDestination(address))); entry->findChild("payAmount")->setValue(amount); uint256 txid; boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) { @@ -107,8 +107,8 @@ void TestSendCoins() // Send two transactions, and verify they are added to transaction list. TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); QCOMPARE(transactionTableModel->rowCount({}), 101); - uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN); - uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN); + uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 5 * COIN); + uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 10 * COIN); QCOMPARE(transactionTableModel->rowCount({}), 103); QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 6c10ffd22dcc..fdb3ef7736c6 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -107,8 +107,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (nNet > 0) { // Credit - if (rec->address.IsValid()) - { + if (IsValidDestinationString(rec->strAddress)) { CTxDestination address = rec->txDest; if (wallet->mapAddressBook.count(address)) { @@ -134,7 +133,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // Online transaction std::string strAddress = wtx.mapValue["to"]; strHTML += "" + tr("To") + ": "; - CTxDestination dest = CBitcoinAddress(strAddress).Get(); + CTxDestination dest = DecodeDestination(strAddress); if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " "; strHTML += GUIUtil::HtmlEscape(strAddress) + "
"; @@ -205,7 +204,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "" + tr("To") + ": "; if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " "; - strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); + strHTML += GUIUtil::HtmlEscape(EncodeDestination(address)); if(toSelf == ISMINE_SPENDABLE) strHTML += " (own address)"; else if(toSelf & ISMINE_WATCH_ONLY) @@ -320,7 +319,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco { if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " "; - strHTML += QString::fromStdString(CBitcoinAddress(address).ToString()); + strHTML += QString::fromStdString(EncodeDestination(address)); } strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue); strHTML = strHTML + " IsMine=" + (wallet->IsMine(txout) & ISMINE_SPENDABLE ? tr("true") : tr("false")); diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 716b9a1ef346..bf54f0744839 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -58,13 +58,15 @@ QList TransactionRecord::decomposeTransaction(const CWallet * { // Received by Dash Address sub.type = TransactionRecord::RecvWithAddress; - sub.strAddress = CBitcoinAddress(address).ToString(); + sub.strAddress = EncodeDestination(address); + sub.txDest = address; } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.strAddress = mapValue["from"]; + sub.txDest = DecodeDestination(sub.strAddress); } if (wtx.IsCoinBase()) { @@ -72,8 +74,6 @@ QList TransactionRecord::decomposeTransaction(const CWallet * sub.type = TransactionRecord::Generated; } - sub.address.SetString(sub.strAddress); - sub.txDest = sub.address.Get(); parts.append(sub); } } @@ -130,12 +130,14 @@ QList TransactionRecord::decomposeTransaction(const CWallet * if (ExtractDestination(wtx.tx->vout[0].scriptPubKey, address)) { // Sent to Dash Address - sub.strAddress = CBitcoinAddress(address).ToString(); + sub.strAddress = EncodeDestination(address); + sub.txDest = address; } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.strAddress = mapValue["to"]; + sub.txDest = DecodeDestination(sub.strAddress); } } else @@ -164,8 +166,6 @@ QList TransactionRecord::decomposeTransaction(const CWallet * sub.debit = -(nDebit - nChange); sub.credit = nCredit - nChange; - sub.address.SetString(sub.strAddress); - sub.txDest = sub.address.Get(); parts.append(sub); parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument } @@ -209,13 +209,15 @@ QList TransactionRecord::decomposeTransaction(const CWallet * { // Sent to Dash Address sub.type = TransactionRecord::SendToAddress; - sub.strAddress = CBitcoinAddress(address).ToString(); + sub.strAddress = EncodeDestination(address); + sub.txDest = address; } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.strAddress = mapValue["to"]; + sub.txDest = DecodeDestination(sub.strAddress); } if(mapValue["DS"] == "1") @@ -232,9 +234,6 @@ QList TransactionRecord::decomposeTransaction(const CWallet * } sub.debit = -nValue; - sub.address.SetString(sub.strAddress); - sub.txDest = sub.address.Get(); - parts.append(sub); } } diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 2b6c64c7e93a..dc9d8468b7bf 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -105,16 +105,14 @@ class TransactionRecord TransactionRecord(): hash(), time(0), type(Other), strAddress(""), debit(0), credit(0), idx(0) { - address = CBitcoinAddress(strAddress); - txDest = address.Get(); + txDest = DecodeDestination(strAddress); } TransactionRecord(uint256 _hash, qint64 _time): hash(_hash), time(_time), type(Other), strAddress(""), debit(0), credit(0), idx(0) { - address = CBitcoinAddress(strAddress); - txDest = address.Get(); + txDest = DecodeDestination(strAddress); } TransactionRecord(uint256 _hash, qint64 _time, @@ -123,8 +121,7 @@ class TransactionRecord hash(_hash), time(_time), type(_type), strAddress(_strAddress), debit(_debit), credit(_credit), idx(0) { - address = CBitcoinAddress(strAddress); - txDest = address.Get(); + txDest = DecodeDestination(strAddress); } /** Decompose CWallet transaction to model transaction records. @@ -138,7 +135,6 @@ class TransactionRecord qint64 time; Type type; std::string strAddress; - CBitcoinAddress address; CTxDestination txDest; CAmount debit; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index c3179d483d27..9cdabba8bd86 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -833,7 +833,7 @@ static void NotifyTransactionChanged(TransactionTableModel *ttm, CWallet *wallet static void NotifyAddressBookChanged(TransactionTableModel *ttm, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, const std::string &purpose, ChangeType status) { QMetaObject::invokeMethod(ttm, "updateAddressBook", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())), + Q_ARG(QString, QString::fromStdString(EncodeDestination(address))), Q_ARG(QString, QString::fromStdString(label)), Q_ARG(bool, isMine), Q_ARG(QString, QString::fromStdString(purpose)), diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 9a3cb47a4434..683051558745 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -223,8 +223,7 @@ void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly) bool WalletModel::validateAddress(const QString &address) { - CBitcoinAddress addressParsed(address.toStdString()); - return addressParsed.IsValid(); + return IsValidDestinationString(address.toStdString()); } WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl) @@ -287,7 +286,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact setAddress.insert(rcp.address); ++nAddresses; - CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); + CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString())); CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount}; vecSend.push_back(recipient); @@ -398,7 +397,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran if (!rcp.paymentRequest.IsInitialized()) { std::string strAddress = rcp.address.toStdString(); - CTxDestination dest = CBitcoinAddress(strAddress).Get(); + CTxDestination dest = DecodeDestination(strAddress); std::string strLabel = rcp.label.toStdString(); { LOCK(wallet->cs_wallet); @@ -518,7 +517,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, const std::string &purpose, ChangeType status) { - QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString()); + QString strAddress = QString::fromStdString(EncodeDestination(address)); QString strLabel = QString::fromStdString(label); QString strPurpose = QString::fromStdString(purpose); @@ -688,7 +687,7 @@ bool WalletModel::isSpent(const COutPoint& outpoint) const void WalletModel::listCoins(std::map >& mapCoins) const { for (auto& group : wallet->ListCoins()) { - auto& resultGroup = mapCoins[QString::fromStdString(CBitcoinAddress(group.first).ToString())]; + auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))]; for (auto& coin : group.second) { resultGroup.emplace_back(std::move(coin)); } @@ -732,7 +731,7 @@ void WalletModel::loadReceiveRequests(std::vector& vReceiveRequests bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest) { - CTxDestination dest = CBitcoinAddress(sAddress).Get(); + CTxDestination dest = DecodeDestination(sAddress); std::stringstream ss; ss << nId; diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index d11c17ea0d3e..8d7c8ff87d86 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -75,7 +75,7 @@ void WalletModelTransaction::reassignAmounts() else // normal recipient (no payment request) { for (const auto& txout : walletTransaction->tx->vout) { - CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); + CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString())); if (txout.scriptPubKey == scriptPubKey) { rcp.amount = txout.nValue; break; diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index cd88f47df1b5..27968de4111e 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -608,7 +608,7 @@ UniValue gobject_vote_alias(const JSONRPCRequest& request) CKey votingKey; if (!pwallet->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Private key for voting address %s not known by wallet", CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString())); + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Private key for voting address %s not known by wallet", EncodeDestination(dmn->pdmnState->keyIDVoting))); } std::map votingKeys; diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 29ab1dac7c54..639a70c99d7e 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -163,10 +163,7 @@ UniValue GetNextMasternodeForPayment(int heightShift) CScript payeeScript = payee->pdmnState->scriptPayout; CTxDestination payeeDest; - CBitcoinAddress payeeAddr; - if (ExtractDestination(payeeScript, payeeDest)) { - payeeAddr = CBitcoinAddress(payeeDest); - } + ExtractDestination(payeeScript, payeeDest); UniValue obj(UniValue::VOBJ); @@ -174,7 +171,7 @@ UniValue GetNextMasternodeForPayment(int heightShift) obj.push_back(Pair("IP:port", payee->pdmnState->addr.ToString())); obj.push_back(Pair("proTxHash", payee->proTxHash.ToString())); obj.push_back(Pair("outpoint", payee->collateralOutpoint.ToStringShort())); - obj.push_back(Pair("payee", payeeAddr.IsValid() ? payeeAddr.ToString() : "UNKNOWN")); + obj.push_back(Pair("payee", IsValidDestination(payeeDest) ? EncodeDestination(payeeDest) : "UNKNOWN")); return obj; } @@ -429,7 +426,7 @@ UniValue masternodelist(const JSONRPCRequest& request) if (GetUTXOCoin(dmn->collateralOutpoint, coin)) { CTxDestination collateralDest; if (ExtractDestination(coin.out.scriptPubKey, collateralDest)) { - collateralAddressStr = CBitcoinAddress(collateralDest).ToString(); + collateralAddressStr = EncodeDestination(collateralDest); } } @@ -437,7 +434,7 @@ UniValue masternodelist(const JSONRPCRequest& request) CTxDestination payeeDest; std::string payeeStr = "UNKNOWN"; if (ExtractDestination(payeeScript, payeeDest)) { - payeeStr = CBitcoinAddress(payeeDest).ToString(); + payeeStr = EncodeDestination(payeeDest); } if (strMode == "addr") { @@ -475,8 +472,8 @@ UniValue masternodelist(const JSONRPCRequest& request) dmnToStatus(dmn) << " " << dmnToLastPaidTime(dmn) << " " << dmn->pdmnState->nLastPaidHeight << " " << - CBitcoinAddress(dmn->pdmnState->keyIDOwner).ToString() << " " << - CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString() << " " << + EncodeDestination(dmn->pdmnState->keyIDOwner) << " " << + EncodeDestination(dmn->pdmnState->keyIDVoting) << " " << collateralAddressStr << " " << dmn->pdmnState->pubKeyOperator.Get().ToString(); std::string strInfo = streamInfo.str(); @@ -489,8 +486,8 @@ UniValue masternodelist(const JSONRPCRequest& request) objMN.push_back(Pair("status", dmnToStatus(dmn))); objMN.push_back(Pair("lastpaidtime", dmnToLastPaidTime(dmn))); objMN.push_back(Pair("lastpaidblock", dmn->pdmnState->nLastPaidHeight)); - objMN.push_back(Pair("owneraddress", CBitcoinAddress(dmn->pdmnState->keyIDOwner).ToString())); - objMN.push_back(Pair("votingaddress", CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString())); + objMN.push_back(Pair("owneraddress", EncodeDestination(dmn->pdmnState->keyIDOwner))); + objMN.push_back(Pair("votingaddress", EncodeDestination(dmn->pdmnState->keyIDVoting))); objMN.push_back(Pair("collateraladdress", collateralAddressStr)); objMN.push_back(Pair("pubkeyoperator", dmn->pdmnState->pubKeyOperator.Get().ToString())); obj.push_back(Pair(strOutpoint, objMN)); @@ -506,7 +503,7 @@ UniValue masternodelist(const JSONRPCRequest& request) obj.push_back(Pair(strOutpoint, payeeStr)); } else if (strMode == "owneraddress") { if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; - obj.push_back(Pair(strOutpoint, CBitcoinAddress(dmn->pdmnState->keyIDOwner).ToString())); + obj.push_back(Pair(strOutpoint, EncodeDestination(dmn->pdmnState->keyIDOwner))); } else if (strMode == "pubkeyoperator") { if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; obj.push_back(Pair(strOutpoint, dmn->pdmnState->pubKeyOperator.Get().ToString())); @@ -517,7 +514,7 @@ UniValue masternodelist(const JSONRPCRequest& request) obj.push_back(Pair(strOutpoint, strStatus)); } else if (strMode == "votingaddress") { if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; - obj.push_back(Pair(strOutpoint, CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString())); + obj.push_back(Pair(strOutpoint, EncodeDestination(dmn->pdmnState->keyIDVoting))); } }); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index f18891b67205..8e96a54ed401 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -187,12 +187,13 @@ UniValue generatetoaddress(const JSONRPCRequest& request) nMaxTries = request.params[2].get_int(); } - CBitcoinAddress address(request.params[1].get_str()); - if (!address.IsValid()) + CTxDestination destination = DecodeDestination(request.params[1].get_str()); + if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); + } std::shared_ptr coinbaseScript = std::make_shared(); - coinbaseScript->reserveScript = GetScriptForDestination(address.Get()); + coinbaseScript->reserveScript = GetScriptForDestination(destination); return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false); } @@ -682,12 +683,11 @@ UniValue getblocktemplate(const JSONRPCRequest& request) UniValue masternodeObj(UniValue::VARR); for (const auto& txout : pblocktemplate->voutMasternodePayments) { - CTxDestination address1; - ExtractDestination(txout.scriptPubKey, address1); - CBitcoinAddress address2(address1); + CTxDestination dest; + ExtractDestination(txout.scriptPubKey, dest); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("payee", address2.ToString().c_str())); + obj.push_back(Pair("payee", EncodeDestination(dest).c_str())); obj.push_back(Pair("script", HexStr(txout.scriptPubKey))); obj.push_back(Pair("amount", txout.nValue)); masternodeObj.push_back(obj); @@ -701,10 +701,9 @@ UniValue getblocktemplate(const JSONRPCRequest& request) if(pblocktemplate->voutSuperblockPayments.size()) { for (const auto& txout : pblocktemplate->voutSuperblockPayments) { UniValue entry(UniValue::VOBJ); - CTxDestination address1; - ExtractDestination(txout.scriptPubKey, address1); - CBitcoinAddress address2(address1); - entry.push_back(Pair("payee", address2.ToString().c_str())); + CTxDestination dest; + ExtractDestination(txout.scriptPubKey, dest); + entry.push_back(Pair("payee", EncodeDestination(dest).c_str())); entry.push_back(Pair("script", HexStr(txout.scriptPubKey))); entry.push_back(Pair("amount", txout.nValue)); superblockObjArray.push_back(entry); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 5e1dce882b3b..407aa5096bfc 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -238,8 +238,9 @@ class DescribeAddressVisitor : public boost::static_visitor obj.push_back(Pair("script", GetTxnOutputType(whichType))); obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); UniValue a(UniValue::VARR); - for (const CTxDestination& addr : addresses) - a.push_back(CBitcoinAddress(addr).ToString()); + for (const CTxDestination& addr : addresses) { + a.push_back(EncodeDestination(addr)); + } obj.push_back(Pair("addresses", a)); if (whichType == TX_MULTISIG) obj.push_back(Pair("sigsrequired", nRequired)); @@ -369,15 +370,14 @@ UniValue validateaddress(const JSONRPCRequest& request) LOCK(cs_main); #endif - CBitcoinAddress address(request.params[0].get_str()); - bool isValid = address.IsValid(); + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + bool isValid = IsValidDestination(dest); UniValue ret(UniValue::VOBJ); ret.push_back(Pair("isvalid", isValid)); if (isValid) { - CTxDestination dest = address.Get(); - std::string currentAddress = address.ToString(); + std::string currentAddress = EncodeDestination(dest); ret.push_back(Pair("address", currentAddress)); CScript scriptPubKey = GetScriptForDestination(dest); @@ -392,10 +392,10 @@ UniValue validateaddress(const JSONRPCRequest& request) if (pwallet && pwallet->mapAddressBook.count(dest)) { ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name)); } - CKeyID keyID; if (pwallet) { const auto& meta = pwallet->mapKeyMetadata; - auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end(); + const CKeyID *keyID = boost::get(&dest); + auto it = keyID ? meta.find(*keyID) : meta.end(); if (it == meta.end()) { it = meta.find(CScriptID(scriptPubKey)); } @@ -404,8 +404,8 @@ UniValue validateaddress(const JSONRPCRequest& request) } CHDChain hdChainCurrent; - if (!keyID.IsNull() && pwallet->mapHdPubKeys.count(keyID) && pwallet->GetHDChain(hdChainCurrent)) { - ret.push_back(Pair("hdkeypath", pwallet->mapHdPubKeys[keyID].GetKeyPath())); + if (keyID && pwallet->mapHdPubKeys.count(*keyID) && pwallet->GetHDChain(hdChainCurrent)) { + ret.push_back(Pair("hdkeypath", pwallet->mapHdPubKeys[*keyID].GetKeyPath())); ret.push_back(Pair("hdchainid", hdChainCurrent.GetID().GetHex())); } } @@ -441,16 +441,15 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa const std::string& ks = keys[i].get_str(); #ifdef ENABLE_WALLET // Case 1: Dash address and we have full public key: - CBitcoinAddress address(ks); - if (pwallet && address.IsValid()) { - CKeyID keyID; - if (!address.GetKeyID(keyID)) - throw std::runtime_error( - strprintf("%s does not refer to a key",ks)); + CTxDestination dest = DecodeDestination(ks); + if (pwallet && IsValidDestination(dest)) { + const CKeyID *keyID = boost::get(&dest); + if (!keyID) { + throw std::runtime_error(strprintf("%s does not refer to a key", ks)); + } CPubKey vchPubKey; - if (!pwallet->GetPubKey(keyID, vchPubKey)) { - throw std::runtime_error( - strprintf("no full public key for address %s",ks)); + if (!pwallet->GetPubKey(*keyID, vchPubKey)) { + throw std::runtime_error(strprintf("no full public key for address %s", ks)); } if (!vchPubKey.IsFullyValid()) throw std::runtime_error(" Invalid public key: "+ks); @@ -521,10 +520,9 @@ UniValue createmultisig(const JSONRPCRequest& request) // Construct using pay-to-script-hash: CScript inner = _createmultisig_redeemScript(pwallet, request.params); CScriptID innerID(inner); - CBitcoinAddress address(innerID); UniValue result(UniValue::VOBJ); - result.push_back(Pair("address", address.ToString())); + result.push_back(Pair("address", EncodeDestination(innerID))); result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); return result; @@ -559,13 +557,15 @@ UniValue verifymessage(const JSONRPCRequest& request) std::string strSign = request.params[1].get_str(); std::string strMessage = request.params[2].get_str(); - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) + CTxDestination destination = DecodeDestination(strAddress); + if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + } - CKeyID keyID; - if (!addr.GetKeyID(keyID)) + const CKeyID *keyID = boost::get(&destination); + if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + } bool fInvalid = false; std::vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); @@ -581,7 +581,7 @@ UniValue verifymessage(const JSONRPCRequest& request) if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) return false; - return (pubkey.GetID() == keyID); + return (pubkey.GetID() == *keyID); } UniValue signmessagewithprivkey(const JSONRPCRequest& request) @@ -656,22 +656,35 @@ UniValue setmocktime(const JSONRPCRequest& request) bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address) { if (type == 2) { - address = CBitcoinAddress(CScriptID(hash)).ToString(); + address = EncodeDestination(CScriptID(hash)); } else if (type == 1) { - address = CBitcoinAddress(CKeyID(hash)).ToString(); + address = EncodeDestination(CKeyID(hash)); } else { return false; } return true; } +bool getIndexKey(const std::string& str, uint160& hashBytes, int& type) +{ + CTxDestination dest = DecodeDestination(str); + if (!IsValidDestination(dest)) { + type = 0; + return false; + } + const CKeyID *keyID = boost::get(&dest); + const CScriptID *scriptID = boost::get(&dest); + type = keyID ? 1 : 2; + hashBytes = keyID ? *keyID : *scriptID; + return true; +} + bool getAddressesFromParams(const UniValue& params, std::vector > &addresses) { if (params[0].isStr()) { - CBitcoinAddress address(params[0].get_str()); uint160 hashBytes; int type = 0; - if (!address.GetIndexKey(hashBytes, type)) { + if (!getIndexKey(params[0].get_str(), hashBytes, type)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); } addresses.push_back(std::make_pair(hashBytes, type)); @@ -686,10 +699,9 @@ bool getAddressesFromParams(const UniValue& params, std::vector::iterator it = values.begin(); it != values.end(); ++it) { - CBitcoinAddress address(it->get_str()); uint160 hashBytes; int type = 0; - if (!address.GetIndexKey(hashBytes, type)) { + if (!getIndexKey(it->get_str(), hashBytes, type)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); } addresses.push_back(std::make_pair(hashBytes, type)); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 10bf9c3bdb46..8300c1be88be 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -426,7 +426,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request) rawTx.vin.push_back(in); } - std::set setAddress; + std::set destinations; std::vector addrList = sendTo.getKeys(); for (const std::string& name_ : addrList) { @@ -436,15 +436,16 @@ UniValue createrawtransaction(const JSONRPCRequest& request) CTxOut out(0, CScript() << OP_RETURN << data); rawTx.vout.push_back(out); } else { - CBitcoinAddress address(name_); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ")+name_); + CTxDestination destination = DecodeDestination(name_); + if (!IsValidDestination(destination)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + name_); + } - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); - setAddress.insert(address); + if (!destinations.insert(destination).second) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_); + } - CScript scriptPubKey = GetScriptForDestination(address.Get()); + CScript scriptPubKey = GetScriptForDestination(destination); CAmount nAmount = AmountFromValue(sendTo[name_]); CTxOut out(nAmount, scriptPubKey); @@ -568,7 +569,7 @@ UniValue decodescript(const JSONRPCRequest& request) if (type.isStr() && type.get_str() != "scripthash") { // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH, // don't return the address for a P2SH of the P2SH. - r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString())); + r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script)))); } return r; diff --git a/src/rpc/rpcevo.cpp b/src/rpc/rpcevo.cpp index 4eb69a963502..4b46df8585c8 100644 --- a/src/rpc/rpcevo.cpp +++ b/src/rpc/rpcevo.cpp @@ -119,16 +119,16 @@ std::string GetHelpString(int nParamNum, std::string strParamName) // Allows to specify Dash address or priv key. In case of Dash address, the priv key is taken from the wallet static CKey ParsePrivKey(CWallet* pwallet, const std::string &strKeyOrAddress, bool allowAddresses = true) { - CBitcoinAddress address; - if (allowAddresses && address.SetString(strKeyOrAddress) && address.IsValid()) { + CTxDestination dest = DecodeDestination(strKeyOrAddress); + if (allowAddresses && IsValidDestination(dest)) { #ifdef ENABLE_WALLET if (!pwallet) { throw std::runtime_error("addresses not supported when wallet is disabled"); } EnsureWalletIsUnlocked(pwallet); - CKeyID keyId; + const CKeyID *keyID = boost::get(&dest); CKey key; - if (!address.GetKeyID(keyId) || !pwallet->GetKey(keyId, key)) + if (!keyID || !pwallet->GetKey(*keyID, key)) throw std::runtime_error(strprintf("non-wallet or invalid address %s", strKeyOrAddress)); return key; #else//ENABLE_WALLET @@ -145,12 +145,12 @@ static CKey ParsePrivKey(CWallet* pwallet, const std::string &strKeyOrAddress, b static CKeyID ParsePubKeyIDFromAddress(const std::string& strAddress, const std::string& paramName) { - CBitcoinAddress address(strAddress); - CKeyID keyID; - if (!address.IsValid() || !address.GetKeyID(keyID)) { + CTxDestination dest = DecodeDestination(strAddress); + const CKeyID *keyID = boost::get(&dest); + if (!keyID) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be a valid P2PKH address, not %s", paramName, strAddress)); } - return keyID; + return *keyID; } static CBLSPublicKey ParseBLSPubKey(const std::string& hexKey, const std::string& paramName) @@ -439,11 +439,11 @@ UniValue protx_register(const JSONRPCRequest& request) ptx.nVersion = CProRegTx::CURRENT_VERSION; if (isFundRegister) { - CBitcoinAddress collateralAddress(request.params[paramIdx].get_str()); - if (!collateralAddress.IsValid()) { + CTxDestination collateralDest = DecodeDestination(request.params[paramIdx].get_str()); + if (!IsValidDestination(collateralDest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid collaterall address: %s", request.params[paramIdx].get_str())); } - CScript collateralScript = GetScriptForDestination(collateralAddress.Get()); + CScript collateralScript = GetScriptForDestination(collateralDest); CTxOut collateralTxOut(collateralAmount, collateralScript); tx.vout.emplace_back(collateralTxOut); @@ -486,29 +486,29 @@ UniValue protx_register(const JSONRPCRequest& request) } ptx.nOperatorReward = operatorReward; - CBitcoinAddress payoutAddress(request.params[paramIdx + 5].get_str()); - if (!payoutAddress.IsValid()) { + CTxDestination payoutDest = DecodeDestination(request.params[paramIdx + 5].get_str()); + if (!IsValidDestination(payoutDest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid payout address: %s", request.params[paramIdx + 5].get_str())); } ptx.keyIDOwner = keyOwner.GetPubKey().GetID(); ptx.pubKeyOperator = pubKeyOperator; ptx.keyIDVoting = keyIDVoting; - ptx.scriptPayout = GetScriptForDestination(payoutAddress.Get()); + ptx.scriptPayout = GetScriptForDestination(payoutDest); if (!isFundRegister) { // make sure fee calculation works ptx.vchSig.resize(65); } - CBitcoinAddress fundAddress = payoutAddress; + CTxDestination fundDest = payoutDest; if (!request.params[paramIdx + 6].isNull()) { - fundAddress = CBitcoinAddress(request.params[paramIdx + 6].get_str()); - if (!fundAddress.IsValid()) + fundDest = DecodeDestination(request.params[paramIdx + 6].get_str()); + if (!IsValidDestination(fundDest)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[paramIdx + 6].get_str()); } - FundSpecialTx(pwallet, tx, ptx, fundAddress.Get()); + FundSpecialTx(pwallet, tx, ptx, fundDest); UpdateSpecialTxInputsHash(tx, ptx); if (isFundRegister) { @@ -532,8 +532,9 @@ UniValue protx_register(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral not found: %s", ptx.collateralOutpoint.ToStringShort())); } CTxDestination txDest; - CKeyID keyID; - if (!ExtractDestination(coin.out.scriptPubKey, txDest) || !CBitcoinAddress(txDest).GetKeyID(keyID)) { + ExtractDestination(coin.out.scriptPubKey, txDest); + const CKeyID *keyID = boost::get(&txDest); + if (!keyID) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral type not supported: %s", ptx.collateralOutpoint.ToStringShort())); } @@ -544,14 +545,14 @@ UniValue protx_register(const JSONRPCRequest& request) UniValue ret(UniValue::VOBJ); ret.push_back(Pair("tx", EncodeHexTx(tx))); - ret.push_back(Pair("collateralAddress", CBitcoinAddress(txDest).ToString())); + ret.push_back(Pair("collateralAddress", EncodeDestination(txDest))); ret.push_back(Pair("signMessage", ptx.MakeSignString())); return ret; } else { // lets prove we own the collateral CKey key; - if (!pwallet->GetKey(keyID, key)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral key not in wallet: %s", CBitcoinAddress(keyID).ToString())); + if (!pwallet->GetKey(*keyID, key)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("collateral key not in wallet: %s", EncodeDestination(txDest))); } SignSpecialTxPayloadByString(tx, ptx, key); SetTxPayload(tx, ptx); @@ -657,11 +658,11 @@ UniValue protx_update_service(const JSONRPCRequest& request) if (request.params[4].get_str().empty()) { ptx.scriptOperatorPayout = dmn->pdmnState->scriptOperatorPayout; } else { - CBitcoinAddress payoutAddress(request.params[4].get_str()); - if (!payoutAddress.IsValid()) { + CTxDestination payoutDest = DecodeDestination(request.params[4].get_str()); + if (!IsValidDestination(payoutDest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid operator payout address: %s", request.params[4].get_str())); } - ptx.scriptOperatorPayout = GetScriptForDestination(payoutAddress.Get()); + ptx.scriptOperatorPayout = GetScriptForDestination(payoutDest); } } else { ptx.scriptOperatorPayout = dmn->pdmnState->scriptOperatorPayout; @@ -671,10 +672,9 @@ UniValue protx_update_service(const JSONRPCRequest& request) // param feeSourceAddress if (!request.params[5].isNull()) { - CBitcoinAddress feeSourceAddress = CBitcoinAddress(request.params[5].get_str()); - if (!feeSourceAddress.IsValid()) + feeSource = DecodeDestination(request.params[5].get_str()); + if (!IsValidDestination(feeSource)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[5].get_str()); - feeSource = feeSourceAddress.Get(); } else { if (ptx.scriptOperatorPayout != CScript()) { // use operator reward address as default source for fees @@ -750,17 +750,16 @@ UniValue protx_update_registrar(const JSONRPCRequest& request) CTxDestination payoutDest; ExtractDestination(ptx.scriptPayout, payoutDest); if (request.params[4].get_str() != "") { - CBitcoinAddress payoutAddress(request.params[4].get_str()); - if (!payoutAddress.IsValid()) { + payoutDest = DecodeDestination(request.params[4].get_str()); + if (!IsValidDestination(payoutDest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid payout address: %s", request.params[4].get_str())); } - payoutDest = payoutAddress.Get(); ptx.scriptPayout = GetScriptForDestination(payoutDest); } CKey keyOwner; if (!pwallet->GetKey(dmn->pdmnState->keyIDOwner, keyOwner)) { - throw std::runtime_error(strprintf("Private key for owner address %s not found in your wallet", CBitcoinAddress(dmn->pdmnState->keyIDOwner).ToString())); + throw std::runtime_error(strprintf("Private key for owner address %s not found in your wallet", EncodeDestination(dmn->pdmnState->keyIDOwner))); } CMutableTransaction tx; @@ -772,10 +771,9 @@ UniValue protx_update_registrar(const JSONRPCRequest& request) CTxDestination feeSourceDest = payoutDest; if (!request.params[5].isNull()) { - CBitcoinAddress feeSourceAddress = CBitcoinAddress(request.params[5].get_str()); - if (!feeSourceAddress.IsValid()) + feeSourceDest = DecodeDestination(request.params[5].get_str()); + if (!IsValidDestination(feeSourceDest)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[5].get_str()); - feeSourceDest = feeSourceAddress.Get(); } FundSpecialTx(pwallet, tx, ptx, feeSourceDest); @@ -848,10 +846,10 @@ UniValue protx_revoke(const JSONRPCRequest& request) tx.nType = TRANSACTION_PROVIDER_UPDATE_REVOKE; if (!request.params[4].isNull()) { - CBitcoinAddress feeSourceAddress = CBitcoinAddress(request.params[4].get_str()); - if (!feeSourceAddress.IsValid()) + CTxDestination feeSourceDest = DecodeDestination(request.params[4].get_str()); + if (!IsValidDestination(feeSourceDest)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[4].get_str()); - FundSpecialTx(pwallet, tx, ptx, feeSourceAddress.Get()); + FundSpecialTx(pwallet, tx, ptx, feeSourceDest); } else if (dmn->pdmnState->scriptOperatorPayout != CScript()) { // Using funds from previousely specified operator payout address CTxDestination txDest; diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 068089284e1d..7294177e3331 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -276,3 +276,8 @@ CScript GetScriptForMultisig(int nRequired, const std::vector& keys) script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; return script; } + + +bool IsValidDestination(const CTxDestination& dest) { + return dest.which() != 0; +} diff --git a/src/script/standard.h b/src/script/standard.h index 452844c3ae33..b683e79efcbe 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -75,10 +75,13 @@ class CNoDestination { * * CNoDestination: no destination set * * CKeyID: TX_PUBKEYHASH destination * * CScriptID: TX_SCRIPTHASH destination - * A CTxDestination is the internal data type encoded in a CBitcoinAddress + * A CTxDestination is the internal data type encoded in a bitcoin address */ typedef boost::variant CTxDestination; +/** Check whether a CTxDestination is a CNoDestination. */ +bool IsValidDestination(const CTxDestination& dest); + /** Get the name of a txnouttype as a C string, or nullptr if unknown. */ const char* GetTxnOutputType(txnouttype t); diff --git a/src/spork.cpp b/src/spork.cpp index 22840ce247e1..06d0500335fa 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -280,13 +280,13 @@ bool CSporkManager::GetSporkByHash(const uint256& hash, CSporkMessage &sporkRet) bool CSporkManager::SetSporkAddress(const std::string& strAddress) { LOCK(cs); - CBitcoinAddress address(strAddress); - CKeyID keyid; - if (!address.IsValid() || !address.GetKeyID(keyid)) { + CTxDestination dest = DecodeDestination(strAddress); + const CKeyID *keyID = boost::get(&dest); + if (!keyID) { LogPrintf("CSporkManager::SetSporkAddress -- Failed to parse spork address\n"); return false; } - setSporkPubKeyIDs.insert(keyid); + setSporkPubKeyIDs.insert(*keyID); return true; } diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 7cbc7899a0eb..7fc3dd8ce187 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) { UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); CBitcoinSecret secret; - CBitcoinAddress addr; + CTxDestination destination; SelectParams(CBaseChainParams::MAIN); for (unsigned int idx = 0; idx < tests.size(); idx++) { @@ -145,7 +145,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); // Must be valid private key - // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not! BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); CKey privkey = secret.GetKey(); @@ -153,18 +152,17 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest); // Private key must be invalid public key - addr.SetString(exp_base58string); - BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest); + destination = DecodeDestination(exp_base58string); + BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest); } else { std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey" // Must be valid public key - BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest); - BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest); - BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest); - CTxDestination dest = addr.Get(); - BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest); + destination = DecodeDestination(exp_base58string); + BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest); + BOOST_CHECK_MESSAGE((boost::get(&destination) != nullptr) == (exp_addrType == "script"), "isScript mismatch" + strTest); + BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), destination), "addrType mismatch" + strTest); // Public key must be invalid private key secret.SetString(exp_base58string); @@ -226,17 +224,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) BOOST_ERROR("Bad addrtype: " << strTest); continue; } - CBitcoinAddress addrOut; - BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest); - BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest); + std::string address = EncodeDestination(dest); + BOOST_CHECK_MESSAGE(address == exp_base58string, "mismatch: " + strTest); } } - // Visiting a CNoDestination must fail - CBitcoinAddress dummyAddr; - CTxDestination nodest = CNoDestination(); - BOOST_CHECK(!dummyAddr.Set(nodest)); - SelectParams(CBaseChainParams::MAIN); } @@ -245,7 +237,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) { UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases CBitcoinSecret secret; - CBitcoinAddress addr; + CTxDestination destination; for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; @@ -258,8 +250,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) std::string exp_base58string = test[0].get_str(); // must be invalid as public and as private key - addr.SetString(exp_base58string); - BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest); + destination = DecodeDestination(exp_base58string); + BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest); secret.SetString(exp_base58string); BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest); } diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index cd9c13003874..36869121ccde 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -246,8 +246,8 @@ BOOST_FIXTURE_TEST_CASE(dip3_activation, TestChainDIP3BeforeActivationSetup) auto utxos = BuildSimpleUtxoMap(coinbaseTxns); CKey ownerKey; CBLSSecretKey operatorKey; - CBitcoinAddress payoutAddress("yRq1Ky1AfFmf597rnotj7QRxsDUKePVWNF"); - auto tx = CreateProRegTx(utxos, 1, GetScriptForDestination(payoutAddress.Get()), coinbaseKey, ownerKey, operatorKey); + CTxDestination payoutDest = DecodeDestination("yRq1Ky1AfFmf597rnotj7QRxsDUKePVWNF"); + auto tx = CreateProRegTx(utxos, 1, GetScriptForDestination(payoutDest), coinbaseKey, ownerKey, operatorKey); std::vector txns = {tx}; int nHeight = chainActive.Height(); @@ -277,9 +277,7 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup) CKey sporkKey; sporkKey.MakeNewKey(false); CBitcoinSecret sporkSecret(sporkKey); - CBitcoinAddress sporkAddress; - sporkAddress.Set(sporkKey.GetPubKey().GetID()); - sporkManager.SetSporkAddress(sporkAddress.ToString()); + sporkManager.SetSporkAddress(EncodeDestination(sporkKey.GetPubKey().GetID())); sporkManager.SetPrivKey(sporkSecret.ToString()); auto utxos = BuildSimpleUtxoMap(coinbaseTxns); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 813411d09a0c..afbecc12014e 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -16,17 +16,16 @@ #include -static const std::string strSecret1 ("7qh6LYnLN2w2ntz2wwUhRUEgkQ2j8XB16FGw77ZRDZmC29bn7cD"); -static const std::string strSecret2 ("7rve4MxeWFQHGbSYH6J2yaaZd3MBUqoDEwN6ZAZ6ZHmhTT4r3hW"); -static const std::string strSecret1C ("XBuxZHH6TqXUuaSjbVTFR1DQSYecxCB9QA1Koyx5tTc3ddhqEnhm"); -static const std::string strSecret2C ("XHMkZqWcY6Zkoq1j42NBijD8z5N5FtNy2Wx7WyAfXX2HZgxry8cr"); -static const CBitcoinAddress addr1 ("Xywgfc872nn5CKtpATCoAjZCc4v96pJczy"); -static const CBitcoinAddress addr2 ("XpmouUj9KKJ99ZuU331ZS1KqsboeFnLGgK"); -static const CBitcoinAddress addr1C("XxV9h4Xmv6Pup8tVAQmH97K6grzvDwMG9F"); -static const CBitcoinAddress addr2C("Xn7ZrYdExuk79Dm7CJCw7sfUWi2qWJSbRy"); +static const std::string strSecret1 = "7qh6LYnLN2w2ntz2wwUhRUEgkQ2j8XB16FGw77ZRDZmC29bn7cD"; +static const std::string strSecret2 = "7rve4MxeWFQHGbSYH6J2yaaZd3MBUqoDEwN6ZAZ6ZHmhTT4r3hW"; +static const std::string strSecret1C = "XBuxZHH6TqXUuaSjbVTFR1DQSYecxCB9QA1Koyx5tTc3ddhqEnhm"; +static const std::string strSecret2C = "XHMkZqWcY6Zkoq1j42NBijD8z5N5FtNy2Wx7WyAfXX2HZgxry8cr"; +static const std::string addr1 = "Xywgfc872nn5CKtpATCoAjZCc4v96pJczy"; +static const std::string addr2 = "XpmouUj9KKJ99ZuU331ZS1KqsboeFnLGgK"; +static const std::string addr1C = "XxV9h4Xmv6Pup8tVAQmH97K6grzvDwMG9F"; +static const std::string addr2C = "Xn7ZrYdExuk79Dm7CJCw7sfUWi2qWJSbRy"; - -static const std::string strAddressBad("Xta1praZQjyELweyMByXyiREw1ZRsjXzVP"); +static const std::string strAddressBad = "Xta1praZQjyELweyMByXyiREw1ZRsjXzVP"; BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup) @@ -74,10 +73,10 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(!key2C.VerifyPubKey(pubkey2)); BOOST_CHECK(key2C.VerifyPubKey(pubkey2C)); - BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID())); - BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID())); - BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID())); - BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID())); + BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID())); + BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID())); + BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID())); + BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID())); for (int n=0; n<16; n++) { diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 6edd0c94bab6..dd54494d9a01 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -182,7 +182,7 @@ UniValue abortrescan(const JSONRPCRequest& request) return true; } -void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel); +void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel); void ImportScript(CWallet * const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) { if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) { @@ -199,7 +199,7 @@ void ImportScript(CWallet * const pwallet, const CScript& script, const std::str if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); } - ImportAddress(pwallet, CBitcoinAddress(CScriptID(script)), strLabel); + ImportAddress(pwallet, CScriptID(script), strLabel); } else { CTxDestination destination; if (ExtractDestination(script, destination)) { @@ -208,13 +208,13 @@ void ImportScript(CWallet * const pwallet, const CScript& script, const std::str } } -void ImportAddress(CWallet * const pwallet, const CBitcoinAddress& address, const std::string& strLabel) +void ImportAddress(CWallet * const pwallet, const CTxDestination& dest, const std::string& strLabel) { - CScript script = GetScriptForDestination(address.Get()); + CScript script = GetScriptForDestination(dest); ImportScript(pwallet, script, strLabel, false); // add to address book or update label - if (address.IsValid()) - pwallet->SetAddressBook(address.Get(), strLabel, "receive"); + if (IsValidDestination(dest)) + pwallet->SetAddressBook(dest, strLabel, "receive"); } UniValue importaddress(const JSONRPCRequest& request) @@ -266,11 +266,12 @@ UniValue importaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - CBitcoinAddress address(request.params[0].get_str()); - if (address.IsValid()) { - if (fP2SH) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (IsValidDestination(dest)) { + if (fP2SH) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead"); - ImportAddress(pwallet, address, strLabel); + } + ImportAddress(pwallet, dest, strLabel); } else if (IsHex(request.params[0].get_str())) { std::vector data(ParseHex(request.params[0].get_str())); ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH); @@ -433,7 +434,7 @@ UniValue importpubkey(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - ImportAddress(pwallet, CBitcoinAddress(pubKey.GetID()), strLabel); + ImportAddress(pwallet, pubKey.GetID(), strLabel); ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false); if (fRescan) @@ -507,7 +508,7 @@ UniValue importwallet(const JSONRPCRequest& request) assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); if (pwallet->HaveKey(keyid)) { - LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); + LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); continue; } int64_t nTime = DecodeDumpTime(vstr[1]); @@ -525,7 +526,7 @@ UniValue importwallet(const JSONRPCRequest& request) fLabel = true; } } - LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); + LogPrintf("Importing %s...\n", EncodeDestination(keyid)); if (!pwallet->AddKeyPubKey(key, pubkey)) { fGood = false; continue; @@ -617,10 +618,10 @@ UniValue importelectrumwallet(const JSONRPCRequest& request) assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); if (pwallet->HaveKey(keyid)) { - LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); + LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); continue; } - LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); + LogPrintf("Importing %s...\n", EncodeDestination(keyid)); if (!pwallet->AddKeyPubKey(key, pubkey)) { fGood = false; continue; @@ -649,10 +650,10 @@ UniValue importelectrumwallet(const JSONRPCRequest& request) assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); if (pwallet->HaveKey(keyid)) { - LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); + LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); continue; } - LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); + LogPrintf("Importing %s...\n", EncodeDestination(keyid)); if (!pwallet->AddKeyPubKey(key, pubkey)) { fGood = false; continue; @@ -709,14 +710,16 @@ UniValue dumpprivkey(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); std::string strAddress = request.params[0].get_str(); - CBitcoinAddress address; - if (!address.SetString(strAddress)) + CTxDestination dest = DecodeDestination(strAddress); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address"); - CKeyID keyID; - if (!address.GetKeyID(keyID)) + } + const CKeyID *keyID = boost::get(&dest); + if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + } CKey vchSecret; - if (!pwallet->GetKey(keyID, vchSecret)) { + if (!pwallet->GetKey(*keyID, vchSecret)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); } return CBitcoinSecret(vchSecret).ToString(); @@ -883,7 +886,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { const CKeyID &keyid = it->second; std::string strTime = EncodeDumpTime(it->first); - std::string strAddr = CBitcoinAddress(keyid).ToString(); + std::string strAddr = EncodeDestination(keyid); CKey key; if (pwallet->GetKey(keyid, key)) { file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime); @@ -937,14 +940,14 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 // Parse the output. CScript script; - CBitcoinAddress address; + CTxDestination dest; if (!isScript) { - address = CBitcoinAddress(output); - if (!address.IsValid()) { + dest = DecodeDestination(output); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); } - script = GetScriptForDestination(address.Get()); + script = GetScriptForDestination(dest); } else { if (!IsHex(output)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey"); @@ -1002,8 +1005,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); } - CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript)); - CScript redeemDestination = GetScriptForDestination(redeemAddress.Get()); + CTxDestination redeem_dest = CScriptID(redeemScript); + CScript redeemDestination = GetScriptForDestination(redeem_dest); if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); @@ -1016,8 +1019,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 } // add to address book or update label - if (address.IsValid()) { - pwallet->SetAddressBook(address.Get(), label, "receive"); + if (IsValidDestination(dest)) { + pwallet->SetAddressBook(dest, label, "receive"); } // Import private keys. @@ -1076,27 +1079,25 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key"); } - CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID()); + CTxDestination pubkey_dest = pubKey.GetID(); // Consistency check. - if (!isScript && !(pubKeyAddress.Get() == address.Get())) { + if (!isScript && !(pubkey_dest == dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } // Consistency check. if (isScript) { - CBitcoinAddress scriptAddress; CTxDestination destination; if (ExtractDestination(script, destination)) { - scriptAddress = CBitcoinAddress(destination); - if (!(scriptAddress.Get() == pubKeyAddress.Get())) { + if (!(destination == pubkey_dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } } } - CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get()); + CScript pubKeyScript = GetScriptForDestination(pubkey_dest); if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); @@ -1109,8 +1110,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 } // add to address book or update label - if (pubKeyAddress.IsValid()) { - pwallet->SetAddressBook(pubKeyAddress.Get(), label, "receive"); + if (IsValidDestination(pubkey_dest)) { + pwallet->SetAddressBook(pubkey_dest, label, "receive"); } // TODO Is this necessary? @@ -1149,21 +1150,19 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 CPubKey pubKey = key.GetPubKey(); assert(key.VerifyPubKey(pubKey)); - CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID()); + CTxDestination pubkey_dest = pubKey.GetID(); // Consistency check. - if (!isScript && !(pubKeyAddress.Get() == address.Get())) { + if (!isScript && !(pubkey_dest == dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } // Consistency check. if (isScript) { - CBitcoinAddress scriptAddress; CTxDestination destination; if (ExtractDestination(script, destination)) { - scriptAddress = CBitcoinAddress(destination); - if (!(scriptAddress.Get() == pubKeyAddress.Get())) { + if (!(destination == pubkey_dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } } @@ -1202,8 +1201,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 if (scriptPubKey.getType() == UniValue::VOBJ) { // add to address book or update label - if (address.IsValid()) { - pwallet->SetAddressBook(address.Get(), label, "receive"); + if (IsValidDestination(dest)) { + pwallet->SetAddressBook(dest, label, "receive"); } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 76a1cb519244..5c4a2d926575 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -169,18 +169,18 @@ UniValue getnewaddress(const JSONRPCRequest& request) pwallet->SetAddressBook(keyID, strAccount, "receive"); - return CBitcoinAddress(keyID).ToString(); + return EncodeDestination(keyID); } -CBitcoinAddress GetAccountAddress(CWallet * const pwallet, std::string strAccount, bool bForceNew=false) +CTxDestination GetAccountAddress(CWallet * const pwallet, std::string strAccount, bool bForceNew=false) { CPubKey pubKey; if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) { throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); } - return CBitcoinAddress(pubKey.GetID()); + return pubKey.GetID(); } UniValue getaccountaddress(const JSONRPCRequest& request) @@ -212,7 +212,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request) UniValue ret(UniValue::VSTR); - ret = GetAccountAddress(pwallet, strAccount).ToString(); + ret = EncodeDestination(GetAccountAddress(pwallet, strAccount)); return ret; } @@ -251,7 +251,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) CKeyID keyID = vchPubKey.GetID(); - return CBitcoinAddress(keyID).ToString(); + return EncodeDestination(keyID); } @@ -276,24 +276,25 @@ UniValue setaccount(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - CBitcoinAddress address(request.params[0].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address"); + } std::string strAccount; if (!request.params[1].isNull()) strAccount = AccountFromValue(request.params[1]); // Only add the account if the address is yours. - if (IsMine(*pwallet, address.Get())) { + if (IsMine(*pwallet, dest)) { // Detect when changing the account of an address that is the 'unused current key' of another account: - if (pwallet->mapAddressBook.count(address.Get())) { - std::string strOldAccount = pwallet->mapAddressBook[address.Get()].name; - if (address == GetAccountAddress(pwallet, strOldAccount)) { + if (pwallet->mapAddressBook.count(dest)) { + std::string strOldAccount = pwallet->mapAddressBook[dest].name; + if (dest == GetAccountAddress(pwallet, strOldAccount)) { GetAccountAddress(pwallet, strOldAccount, true); } } - pwallet->SetAddressBook(address.Get(), strAccount, "receive"); + pwallet->SetAddressBook(dest, strAccount, "receive"); } else throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); @@ -324,12 +325,13 @@ UniValue getaccount(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - CBitcoinAddress address(request.params[0].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address"); + } std::string strAccount; - std::map::iterator mi = pwallet->mapAddressBook.find(address.Get()); + std::map::iterator mi = pwallet->mapAddressBook.find(dest); if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) { strAccount = (*mi).second.name; } @@ -366,11 +368,12 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) // Find all addresses that have the given account UniValue ret(UniValue::VARR); - for (const std::pair& item : pwallet->mapAddressBook) { - const CBitcoinAddress& address = item.first; + for (const std::pair& item : pwallet->mapAddressBook) { + const CTxDestination& dest = item.first; const std::string& strName = item.second.name; - if (strName == strAccount) - ret.push_back(address.ToString()); + if (strName == strAccount) { + ret.push_back(EncodeDestination(dest)); + } } return ret; } @@ -455,9 +458,10 @@ UniValue sendtoaddress(const JSONRPCRequest& request) ObserveSafeMode(); LOCK2(cs_main, pwallet->cs_wallet); - CBitcoinAddress address(request.params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address"); + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } // Amount CAmount nAmount = AmountFromValue(request.params[1]); @@ -494,7 +498,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, coin_control); + SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control); return wtx.GetHash().GetHex(); } @@ -544,16 +548,16 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) UniValue jsonGroupings(UniValue::VARR); std::map balances = pwallet->GetAddressBalances(); - for (std::set grouping : pwallet->GetAddressGroupings()) { + for (const std::set& grouping : pwallet->GetAddressGroupings()) { UniValue jsonGrouping(UniValue::VARR); - for (CTxDestination address : grouping) + for (const CTxDestination& address : grouping) { UniValue addressInfo(UniValue::VARR); - addressInfo.push_back(CBitcoinAddress(address).ToString()); + addressInfo.push_back(EncodeDestination(address)); addressInfo.push_back(ValueFromAmount(balances[address])); { - if (pwallet->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwallet->mapAddressBook.end()) { - addressInfo.push_back(pwallet->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name); + if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) { + addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name); } } jsonGrouping.push_back(addressInfo); @@ -600,7 +604,7 @@ UniValue listaddressbalances(const JSONRPCRequest& request) std::map balances = pwallet->GetAddressBalances(); for (auto& balance : balances) if (balance.second >= nMinAmount) - jsonBalances.push_back(Pair(CBitcoinAddress(balance.first).ToString(), ValueFromAmount(balance.second))); + jsonBalances.push_back(Pair(EncodeDestination(balance.first), ValueFromAmount(balance.second))); return jsonBalances; } @@ -640,16 +644,18 @@ UniValue signmessage(const JSONRPCRequest& request) std::string strAddress = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) + CTxDestination dest = DecodeDestination(strAddress); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + } - CKeyID keyID; - if (!addr.GetKeyID(keyID)) + const CKeyID *keyID = boost::get(&dest); + if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + } CKey key; - if (!pwallet->GetKey(keyID, key)) { + if (!pwallet->GetKey(*keyID, key)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); } @@ -696,10 +702,11 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); // Dash address - CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address"); - CScript scriptPubKey = GetScriptForDestination(address.Get()); + } + CScript scriptPubKey = GetScriptForDestination(dest); if (!IsMine(*pwallet, scriptPubKey)) { return ValueFromAmount(0); } @@ -967,9 +974,10 @@ UniValue sendfrom(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); std::string strAccount = AccountFromValue(request.params[0]); - CBitcoinAddress address(request.params[1].get_str()); - if (!address.IsValid()) + CTxDestination dest = DecodeDestination(request.params[1].get_str()); + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address"); + } CAmount nAmount = AmountFromValue(request.params[2]); if (nAmount <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); @@ -993,7 +1001,7 @@ UniValue sendfrom(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); CCoinControl no_coin_control; // This is a deprecated API - SendMoney(pwallet, address.Get(), nAmount, false, wtx, no_coin_control); + SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control); return wtx.GetHash().GetHex(); } @@ -1089,22 +1097,23 @@ UniValue sendmany(const JSONRPCRequest& request) } } - std::set setAddress; + std::set destinations; std::vector vecSend; CAmount totalAmount = 0; std::vector keys = sendTo.getKeys(); - for (const std::string& name_ : keys) - { - CBitcoinAddress address(name_); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ")+name_); + for (const std::string& name_ : keys) { + CTxDestination dest = DecodeDestination(name_); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + name_); + } - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); - setAddress.insert(address); + if (destinations.count(dest)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_); + } + destinations.insert(dest); - CScript scriptPubKey = GetScriptForDestination(address.Get()); + CScript scriptPubKey = GetScriptForDestination(dest); CAmount nAmount = AmountFromValue(sendTo[name_]); if (nAmount <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); @@ -1197,7 +1206,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) pwallet->AddCScript(inner); pwallet->SetAddressBook(innerID, strAccount, "send"); - return CBitcoinAddress(innerID).ToString(); + return EncodeDestination(innerID); } @@ -1236,7 +1245,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA filter = filter | ISMINE_WATCH_ONLY; // Tally - std::map mapTally; + std::map mapTally; for (const std::pair& pairWtx : pwallet->mapWallet) { const CWalletTx& wtx = pairWtx.second; @@ -1269,14 +1278,14 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA // Reply UniValue ret(UniValue::VARR); std::map mapAccountTally; - for (const std::pair& item : pwallet->mapAddressBook) { - const CBitcoinAddress& address = item.first; + for (const std::pair& item : pwallet->mapAddressBook) { + const CTxDestination& dest = item.first; const std::string& strAccount = item.second.name; - std::map::iterator it = mapTally.find(address); + std::map::iterator it = mapTally.find(dest); if (it == mapTally.end() && !fIncludeEmpty) continue; - isminefilter mine = IsMine(*pwallet, address.Get()); + isminefilter mine = IsMine(*pwallet, dest); if(!(mine & filter)) continue; @@ -1302,7 +1311,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA UniValue obj(UniValue::VOBJ); if(fIsWatchonly) obj.push_back(Pair("involvesWatchonly", true)); - obj.push_back(Pair("address", address.ToString())); + obj.push_back(Pair("address", EncodeDestination(dest))); obj.push_back(Pair("account", strAccount)); obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); @@ -1431,9 +1440,9 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request) static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) { - CBitcoinAddress addr; - if (addr.Set(dest)) - entry.push_back(Pair("address", addr.ToString())); + if (IsValidDestination(dest)) { + entry.push_back(Pair("address", EncodeDestination(dest))); + } } /** @@ -2842,18 +2851,19 @@ UniValue listunspent(const JSONRPCRequest& request) nMaxDepth = request.params[1].get_int(); } - std::set setAddress; + std::set destinations; if (!request.params[2].isNull()) { RPCTypeCheckArgument(request.params[2], UniValue::VARR); UniValue inputs = request.params[2].get_array(); for (unsigned int idx = 0; idx < inputs.size(); idx++) { const UniValue& input = inputs[idx]; - CBitcoinAddress address(input.get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ")+input.get_str()); - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+input.get_str()); - setAddress.insert(address); + CTxDestination dest = DecodeDestination(input.get_str()); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + input.get_str()); + } + if (!destinations.insert(dest).second) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str()); + } } } @@ -2895,7 +2905,7 @@ UniValue listunspent(const JSONRPCRequest& request) const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey; bool fValidAddress = ExtractDestination(scriptPubKey, address); - if (setAddress.size() && (!fValidAddress || !setAddress.count(address))) + if (destinations.size() && (!fValidAddress || !destinations.count(address))) continue; UniValue entry(UniValue::VOBJ); @@ -2903,7 +2913,7 @@ UniValue listunspent(const JSONRPCRequest& request) entry.push_back(Pair("vout", out.i)); if (fValidAddress) { - entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); + entry.push_back(Pair("address", EncodeDestination(address))); if (pwallet->mapAddressBook.count(address)) { entry.push_back(Pair("account", pwallet->mapAddressBook[address].name)); @@ -3024,12 +3034,13 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) true, true); if (options.exists("changeAddress")) { - CBitcoinAddress address(options["changeAddress"].get_str()); + CTxDestination dest = DecodeDestination(options["changeAddress"].get_str()); - if (!address.IsValid()) + if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid dash address"); + } - coinControl.destChange = address.Get(); + coinControl.destChange = dest; } if (options.exists("changePosition")) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a91459a44b05..4c7f2fc180ce 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -430,7 +430,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript) * these. Do not add them to the wallet and warn. */ if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { - std::string strAddr = CBitcoinAddress(CScriptID(redeemScript)).ToString(); + std::string strAddr = EncodeDestination(CScriptID(redeemScript)); LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr); return true; @@ -3330,7 +3330,7 @@ bool CWallet::SelectCoinsGroupedByAddresses(std::vector& vecTa if (LogAcceptCategory(BCLog::SELECTCOINS)) { std::string strMessage = "SelectCoinsGroupedByAddresses - vecTallyRet:\n"; for (const auto& item : vecTallyRet) - strMessage += strprintf(" %s %f\n", CBitcoinAddress(item.txdest).ToString().c_str(), float(item.nAmount)/COIN); + strMessage += strprintf(" %s %f\n", EncodeDestination(item.txdest).c_str(), float(item.nAmount)/COIN); LogPrint(BCLog::SELECTCOINS, "%s", strMessage); } @@ -3433,17 +3433,16 @@ bool CWallet::GetOutpointAndKeysFromOutput(const COutput& out, COutPoint& outpoi outpointRet = COutPoint(out.tx->GetHash(), out.i); pubScript = out.tx->tx->vout[out.i].scriptPubKey; // the inputs PubKey - CTxDestination address1; - ExtractDestination(pubScript, address1); - CBitcoinAddress address2(address1); + CTxDestination dest; + ExtractDestination(pubScript, dest); - CKeyID keyID; - if (!address2.GetKeyID(keyID)) { + const CKeyID *keyID = boost::get(&dest); + if (!keyID) { LogPrintf("CWallet::GetOutpointAndKeysFromOutput -- Address does not refer to a key\n"); return false; } - if (!GetKey(keyID, keyRet)) { + if (!GetKey(*keyID, keyRet)) { LogPrintf ("CWallet::GetOutpointAndKeysFromOutput -- Private key for address is not known\n"); return false; } @@ -4180,9 +4179,9 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s } NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO, strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) ); - if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose)) + if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(EncodeDestination(address), strPurpose)) return false; - return CWalletDB(*dbw).WriteName(CBitcoinAddress(address).ToString(), strName); + return CWalletDB(*dbw).WriteName(EncodeDestination(address), strName); } bool CWallet::DelAddressBook(const CTxDestination& address) @@ -4191,7 +4190,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address) LOCK(cs_wallet); // mapAddressBook // Delete destdata tuples associated with address - std::string strAddress = CBitcoinAddress(address).ToString(); + std::string strAddress = EncodeDestination(address); for (const std::pair &item : mapAddressBook[address].destdata) { CWalletDB(*dbw).EraseDestData(strAddress, item.first); @@ -4201,8 +4200,8 @@ bool CWallet::DelAddressBook(const CTxDestination& address) NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED); - CWalletDB(*dbw).ErasePurpose(CBitcoinAddress(address).ToString()); - return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString()); + CWalletDB(*dbw).ErasePurpose(EncodeDestination(address)); + return CWalletDB(*dbw).EraseName(EncodeDestination(address)); } const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const @@ -4876,14 +4875,14 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co return false; mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); - return CWalletDB(*dbw).WriteDestData(CBitcoinAddress(dest).ToString(), key, value); + return CWalletDB(*dbw).WriteDestData(EncodeDestination(dest), key, value); } bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key) { if (!mapAddressBook[dest].destdata.erase(key)) return false; - return CWalletDB(*dbw).EraseDestData(CBitcoinAddress(dest).ToString(), key); + return CWalletDB(*dbw).EraseDestData(EncodeDestination(dest), key); } bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f37ebe902f69..d98b51343df1 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -260,13 +260,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { std::string strAddress; ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name; + ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name; } else if (strType == "purpose") { std::string strAddress; ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose; + ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose; } else if (strType == "tx") { @@ -492,7 +492,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssKey >> strAddress; ssKey >> strKey; ssValue >> strValue; - if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue)) + if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue)) { strErr = "Error reading wallet database: LoadDestData failed"; return false;