Skip to content

Commit

Permalink
Merge #1679: Prepare for non-Base58 addresses [Step 3]
Browse files Browse the repository at this point in the history
e07286d Remove possibly confusing IsValidDestinationString(str) (furszy)
a7bafa1 Implement {Encode,Decode}Destination without CBitcoinAddress (furszy)
7d3ba5d Remove unused GetKeyID and IsScript methods from CBitcoinAddress (furszy)
e7c5d9a Move CBitcoinAddress to base58.cpp (furszy)
548f828 Final migration from CBitcoinAddress to the destionation wrapper (furszy)

Pull request description:

  Finished the complete removal of the base58 address class from the sources, migrated to the destination wrapper.

  Plus includes bitcoin#11117 - last commit - and bitcoin#11259 as an extra.

ACKs for top commit:
  random-zebra:
    utACK e07286d
  Fuzzbawls:
    utACK e07286d

Tree-SHA512: b2bf4c5ed10f863f0de7ab57a87610fddab1bbe21a1f585006e5c370ba3c04635fb1314a9d9a80b2c15a66d5bfe34fd9590dc113f0d91d93d33eb37344c7f8fe
  • Loading branch information
random-zebra committed Jul 5, 2020
2 parents 76ea490 + e07286d commit c157deb
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 200 deletions.
162 changes: 58 additions & 104 deletions src/base58.cpp
Expand Up @@ -6,15 +6,15 @@
#include "base58.h"

#include "hash.h"
#include "script/script.h"
#include "uint256.h"

#include <assert.h>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>

#include <algorithm>
#include <assert.h>
#include <sstream>
#include <stdint.h>
#include <string.h>
#include <string>
#include <vector>

/** All alphanumeric characters except for "0", "I", "O", and "l" */
Expand Down Expand Up @@ -231,94 +231,64 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const

namespace
{
class CBitcoinAddressVisitor : public boost::static_visitor<bool>
class DestinationEncoder : public boost::static_visitor<std::string>
{
private:
CBitcoinAddress* addr;
CChainParams::Base58Type type;
const CChainParams& m_params;
const CChainParams::Base58Type m_addrType;

public:
CBitcoinAddressVisitor(CBitcoinAddress* addrIn,
const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS) :
addr(addrIn),
type(addrType){};

bool operator()(const CKeyID& id) const { return addr->Set(id, type); }
bool operator()(const CScriptID& id) const { return addr->Set(id); }
bool operator()(const CNoDestination& no) const { return false; }
};

} // anon namespace
DestinationEncoder(const CChainParams& params, const CChainParams::Base58Type _addrType = CChainParams::PUBKEY_ADDRESS) : m_params(params), m_addrType(_addrType) {}

bool CBitcoinAddress::Set(const CKeyID& id, const CChainParams::Base58Type addrType)
{
SetData(Params().Base58Prefix(addrType), &id, 20);
return true;
}

bool CBitcoinAddress::Set(const CScriptID& id)
{
SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
return true;
}

bool CBitcoinAddress::Set(const CTxDestination& dest, const CChainParams::Base58Type addrType)
{
return boost::apply_visitor(CBitcoinAddressVisitor(this, addrType), dest);
}

bool CBitcoinAddress::IsValid() const
{
return IsValid(Params());
}

bool CBitcoinAddress::IsValid(const CChainParams& params) const
{
bool fCorrectSize = vchData.size() == 20;
bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS) ||
vchVersion == params.Base58Prefix(CChainParams::STAKING_ADDRESS);
return fCorrectSize && fKnownVersion;
}
std::string operator()(const CKeyID& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(m_addrType);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}

CTxDestination CBitcoinAddress::Get() const
{
if (!IsValid())
return CNoDestination();
uint160 id;
memcpy(&id, &vchData[0], 20);
if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
vchVersion == Params().Base58Prefix(CChainParams::STAKING_ADDRESS))
return CKeyID(id);
else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
return CScriptID(id);
else
return CNoDestination();
}
std::string operator()(const CScriptID& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}

bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
{
if (!IsValid() ||
(vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) &&
vchVersion != Params().Base58Prefix(CChainParams::STAKING_ADDRESS)))
return false;
uint160 id;
memcpy(&id, &vchData[0], 20);
keyID = CKeyID(id);
return true;
}
std::string operator()(const CNoDestination& no) const { return ""; }
};

bool CBitcoinAddress::IsScript() const
CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, bool& isStaking)
{
bool fCorrectSize = vchData.size() == 20;
return fCorrectSize && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
std::vector<unsigned char> data;
uint160 hash;
if (DecodeBase58Check(str, data)) {
// base58-encoded PIVX addresses.
// Public-key-hash-addresses have version 30 (or 139 testnet).
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
return CKeyID(hash);
}
// Public-key-hash-coldstaking-addresses have version 63 (or 73 testnet).
const std::vector<unsigned char>& staking_prefix = params.Base58Prefix(CChainParams::STAKING_ADDRESS);
if (data.size() == hash.size() + staking_prefix.size() && std::equal(staking_prefix.begin(), staking_prefix.end(), data.begin())) {
isStaking = true;
std::copy(data.begin() + staking_prefix.size(), data.end(), hash.begin());
return CKeyID(hash);
}
// Script-hash-addresses have version 13 (or 19 testnet).
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
return CScriptID(hash);
}
}
return CNoDestination();
}

bool CBitcoinAddress::IsStakingAddress() const
{
bool fCorrectSize = vchData.size() == 20;
return fCorrectSize && vchVersion == Params().Base58Prefix(CChainParams::STAKING_ADDRESS);
}
} // anon namespace

CKey DecodeSecret(const std::string& str)
{
Expand Down Expand Up @@ -349,50 +319,34 @@ std::string EncodeSecret(const CKey& key)
return ret;
}

CTxDestination DestinationFor(const CKeyID& keyID, const CChainParams::Base58Type addrType)
{
CBitcoinAddress addr(keyID, addrType);
if (!addr.IsValid()) throw std::runtime_error("Error, trying to decode an invalid keyID");
return addr.Get();
}

std::string EncodeDestination(const CTxDestination& dest, bool isStaking)
{
return EncodeDestination(dest, isStaking ? CChainParams::STAKING_ADDRESS : CChainParams::PUBKEY_ADDRESS);
}

std::string EncodeDestination(const CTxDestination& dest, const CChainParams::Base58Type addrType)
{
CBitcoinAddress addr(dest, addrType);
if (!addr.IsValid()) return "";
return addr.ToString();
return boost::apply_visitor(DestinationEncoder(Params(), addrType), dest);
}

CTxDestination DecodeDestination(const std::string& str)
{
return CBitcoinAddress(str).Get();
bool isStaking;
return DecodeDestination(str, Params(), isStaking);
}

CTxDestination DecodeDestination(const std::string& str, bool& isStaking)
{
CBitcoinAddress addr(str);
isStaking = addr.IsStakingAddress();
return addr.Get();
return DecodeDestination(str, Params(), isStaking);
}

bool IsValidDestinationString(const std::string& str, bool fStaking, const CChainParams& params)
{
return IsValidDestinationString(str, fStaking);
}

bool IsValidDestinationString(const std::string& str)
{
CBitcoinAddress address(str);
return address.IsValid();
bool isStaking = false;
return IsValidDestination(DecodeDestination(str, params, isStaking)) && (isStaking == fStaking);
}

bool IsValidDestinationString(const std::string& str, bool isStaking)
{
CBitcoinAddress address(str);
return address.IsValid() && (address.IsStakingAddress() == isStaking);
return IsValidDestinationString(str, isStaking, Params());
}
38 changes: 0 additions & 38 deletions src/base58.h
Expand Up @@ -18,7 +18,6 @@
#include "chainparams.h"
#include "key.h"
#include "pubkey.h"
#include "script/script.h"
#include "script/standard.h"

#include <string>
Expand Down Expand Up @@ -101,42 +100,6 @@ class CBase58Data
bool operator>(const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};

/** base58-encoded PIVX 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, const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS);
bool Set(const CScriptID& id);
bool Set(const CTxDestination& dest, const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS);
bool IsValid() const;
bool IsValid(const CChainParams& params) const;

CBitcoinAddress() {}
CBitcoinAddress(const CTxDestination& dest, const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS) { Set(dest, addrType); }
CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); }

CTxDestination Get() const;
bool GetKeyID(CKeyID& keyID) const;
bool IsScript() const;
bool IsStakingAddress() const;


// Helpers
static const CBitcoinAddress newCSInstance(const CTxDestination& dest) {
return CBitcoinAddress(dest, CChainParams::STAKING_ADDRESS);
}

static const CBitcoinAddress newInstance(const CTxDestination& dest) {
return CBitcoinAddress(dest, CChainParams::PUBKEY_ADDRESS);
}
};

CKey DecodeSecret(const std::string& str);
std::string EncodeSecret(const CKey& key);

Expand Down Expand Up @@ -177,7 +140,6 @@ typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_
typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> CBitcoinExtPubKey;


CTxDestination DestinationFor(const CKeyID& keyID, const CChainParams::Base58Type addrType);
std::string EncodeDestination(const CTxDestination& dest, bool isStaking);
std::string EncodeDestination(const CTxDestination& dest, const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS);
// DecodeDestinationisStaking flag is set to true when the string arg is from an staking address
Expand Down
11 changes: 4 additions & 7 deletions src/qt/paymentserver.cpp
Expand Up @@ -193,11 +193,9 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])

SendCoinsRecipient r;
if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty()) {
CBitcoinAddress address(r.address.toStdString());

if (address.IsValid(Params(CBaseChainParams::MAIN))) {
if (IsValidDestinationString(r.address.toStdString(), false, Params(CBaseChainParams::MAIN))) {
SelectParams(CBaseChainParams::MAIN);
} else if (address.IsValid(Params(CBaseChainParams::TESTNET))) {
} else if (IsValidDestinationString(r.address.toStdString(), false, Params(CBaseChainParams::TESTNET))) {
SelectParams(CBaseChainParams::TESTNET);
}
}
Expand Down Expand Up @@ -385,8 +383,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(), false, Params())) {
Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
} else
Expand Down Expand Up @@ -505,7 +502,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
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()) {
// Insecure payments to custom pivx addresses are not supported
// (there is no good way to tell the user where they are paying in a way
Expand Down
2 changes: 1 addition & 1 deletion src/qt/pivx/settings/settingsmultisendwidget.cpp
Expand Up @@ -337,7 +337,7 @@ void SettingsMultisendWidget::activate()
strRet = tr("Unable to activate MultiSend, no available recipients");
else if (!(ui->checkBoxStake->isChecked() || ui->checkBoxRewards->isChecked())) {
strRet = tr("Unable to activate MultiSend\nCheck one or both of the check boxes to send on stake and/or masternode rewards");
} else if (IsValidDestinationString(pwalletMain->vMultiSend[0].first)) {
} else if (IsValidDestinationString(pwalletMain->vMultiSend[0].first, false, Params())) {
pwalletMain->fMultiSendStake = ui->checkBoxStake->isChecked();
pwalletMain->fMultiSendMasternodeReward = ui->checkBoxRewards->isChecked();

Expand Down

0 comments on commit c157deb

Please sign in to comment.