Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 58 additions & 104 deletions src/base58.cpp
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading