Skip to content

Commit

Permalink
Merge bitcoin#11372: Address encoding cleanup
Browse files Browse the repository at this point in the history
92f1f8b Split off key_io_tests from base58_tests (Pieter Wuille)
119b0f8 Split key_io (address/key encodings) off from base58 (Pieter Wuille)
ebfe217 Stop using CBase58Data for ext keys (Pieter Wuille)
32e69fa Replace CBitcoinSecret with {Encode,Decode}Secret (Pieter Wuille)

Pull request description:

  This PR contains some of the changes left as TODO in bitcoin#11167 (and built on top of that PR). They are not intended for backporting.

  This removes the `CBase58`, `CBitcoinSecret`, `CBitcoinExtKey`, and `CBitcoinExtPubKey` classes, in favor of simple `Encode`/`Decode` functions. Furthermore, all Bitcoin-specific logic (addresses, WIF, BIP32) is moved to `key_io.{h,cpp}`, leaving `base58.{h,cpp}` as a pure utility that implements the base58 encoding/decoding logic.

Tree-SHA512: a5962c0ed27ad53cbe00f22af432cf11aa530e3efc9798e25c004bc9ed1b5673db5df3956e398ee2c085e3a136ac8da69fe7a7d97a05fb2eb3be0b60d0479655
  • Loading branch information
laanwj authored and UdjinM6 committed Dec 25, 2020
1 parent 34723e3 commit 5e311b6
Show file tree
Hide file tree
Showing 53 changed files with 456 additions and 526 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ BITCOIN_CORE_H = \
interfaces/node.h \
interfaces/wallet.h \
key.h \
key_io.h \
keepass.h \
keystore.h \
dbwrapper.h \
Expand Down Expand Up @@ -534,6 +535,7 @@ libdash_common_a_SOURCES = \
core_write.cpp \
hdchain.cpp \
key.cpp \
key_io.cpp \
keystore.cpp \
netaddress.cpp \
netbase.cpp \
Expand Down
11 changes: 6 additions & 5 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ TEST_BINARY=test/test_dash$(EXEEXT)

JSON_TEST_FILES = \
test/data/blockfilters.json \
test/data/script_tests.json \
test/data/base58_keys_valid.json \
test/data/base58_encode_decode.json \
test/data/base58_keys_invalid.json \
test/data/bip39_vectors.json \
test/data/key_io_valid.json \
test/data/key_io_invalid.json \
test/data/proposals_valid.json \
test/data/proposals_invalid.json \
test/data/script_tests.json \
test/data/sighash.json \
test/data/tx_invalid.json \
test/data/tx_valid.json \
test/data/sighash.json
test/data/tx_valid.json

RAW_TEST_FILES =

Expand Down Expand Up @@ -58,6 +58,7 @@ BITCOIN_TESTS =\
test/getarg_tests.cpp \
test/governance_validators_tests.cpp \
test/hash_tests.cpp \
test/key_io_tests.cpp \
test/key_tests.cpp \
test/limitedmap_tests.cpp \
test/dbwrapper_tests.cpp \
Expand Down
171 changes: 0 additions & 171 deletions src/base58.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@
#include <base58.h>

#include <hash.h>
#include <script/script.h>
#include <uint256.h>

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

#include <algorithm>
#include <assert.h>
#include <stdint.h>

Expand Down Expand Up @@ -166,169 +161,3 @@ bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRe
return DecodeBase58Check(str.c_str(), vchRet);
}

CBase58Data::CBase58Data()
{
vchVersion.clear();
vchData.clear();
}

void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
{
vchVersion = vchVersionIn;
vchData.resize(nSize);
if (!vchData.empty())
memcpy(vchData.data(), pdata, nSize);
}

void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
{
SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
}

bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
{
std::vector<unsigned char> vchTemp;
bool rc58 = DecodeBase58Check(psz, vchTemp);
if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
vchData.clear();
vchVersion.clear();
return false;
}
vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
vchData.resize(vchTemp.size() - nVersionBytes);
if (!vchData.empty())
memcpy(vchData.data(), vchTemp.data() + nVersionBytes, vchData.size());
memory_cleanse(vchTemp.data(), vchTemp.size());
return true;
}

bool CBase58Data::SetString(const std::string& str)
{
return SetString(str.c_str());
}

std::string CBase58Data::ToString() const
{
std::vector<unsigned char> vch = vchVersion;
vch.insert(vch.end(), vchData.begin(), vchData.end());
return EncodeBase58Check(vch);
}

int CBase58Data::CompareTo(const CBase58Data& b58) const
{
if (vchVersion < b58.vchVersion)
return -1;
if (vchVersion > b58.vchVersion)
return 1;
if (vchData < b58.vchData)
return -1;
if (vchData > b58.vchData)
return 1;
return 0;
}

namespace
{
class DestinationEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;

public:
DestinationEncoder(const CChainParams& params) : m_params(params) {}

std::string operator()(const CKeyID& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}

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);
}

std::string operator()(const CNoDestination& no) const { return ""; }
};

CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
{
std::vector<unsigned char> data;
uint160 hash;
if (DecodeBase58Check(str, data)) {
// 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.
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);
}
// Script-hash-addresses have version 5 (or 196 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();
}
} // namespace

void CBitcoinSecret::SetKey(const CKey& vchSecret)
{
assert(vchSecret.IsValid());
SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
if (vchSecret.IsCompressed())
vchData.push_back(1);
}

CKey CBitcoinSecret::GetKey()
{
CKey ret;
assert(vchData.size() >= 32);
ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);
return ret;
}

bool CBitcoinSecret::IsValid() const
{
bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
return fExpectedFormat && fCorrectVersion;
}

bool CBitcoinSecret::SetString(const char* pszSecret)
{
return CBase58Data::SetString(pszSecret) && IsValid();
}

bool CBitcoinSecret::SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}

std::string EncodeDestination(const CTxDestination& dest)
{
return boost::apply_visitor(DestinationEncoder(Params()), dest);
}

CTxDestination DecodeDestination(const std::string& str)
{
return DecodeDestination(str, Params());
}

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

bool IsValidDestinationString(const std::string& str)
{
return IsValidDestinationString(str, Params());
}

93 changes: 2 additions & 91 deletions src/base58.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@
#ifndef BITCOIN_BASE58_H
#define BITCOIN_BASE58_H

#include <chainparams.h>
#include <key.h>
#include <pubkey.h>
#include <script/standard.h>
#include <support/allocators/zeroafterfree.h>

#include <string>
#include <vector>

Expand Down Expand Up @@ -56,95 +50,12 @@ std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn);
* Decode a base58-encoded string (psz) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet);
bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet);

/**
* Decode a base58-encoded string (str) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);

/**
* Base class for all base58-encoded data
*/
class CBase58Data
{
protected:
//! the version byte(s)
std::vector<unsigned char> vchVersion;

//! the actually encoded data
typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar;
vector_uchar vchData;

CBase58Data();
void SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize);
void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend);

public:
bool SetString(const char* psz, unsigned int nVersionBytes = 1);
bool SetString(const std::string& str);
std::string ToString() const;
int CompareTo(const CBase58Data& b58) const;

bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; }
bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; }
bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; }
bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; }
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};

/**
* A base58-encoded secret key
*/
class CBitcoinSecret : public CBase58Data
{
public:
void SetKey(const CKey& vchSecret);
CKey GetKey();
bool IsValid() const;
bool SetString(const char* pszSecret);
bool SetString(const std::string& strSecret);

CBitcoinSecret(const CKey& vchSecret) { SetKey(vchSecret); }
CBitcoinSecret() {}
};

template<typename K, int Size, CChainParams::Base58Type Type> class CBitcoinExtKeyBase : public CBase58Data
{
public:
void SetKey(const K &key) {
unsigned char vch[Size];
key.Encode(vch);
SetData(Params().Base58Prefix(Type), vch, vch+Size);
}

K GetKey() {
K ret;
if (vchData.size() == Size) {
// If base58 encoded data does not hold an ext key, return a !IsValid() key
ret.Decode(vchData.data());
}
return ret;
}

CBitcoinExtKeyBase(const K &key) {
SetKey(key);
}

CBitcoinExtKeyBase(const std::string& strBase58c) {
SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size());
}

CBitcoinExtKeyBase() {}
};

typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_KEY> CBitcoinExtKey;
typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> 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);
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);

#endif // BITCOIN_BASE58_H
4 changes: 3 additions & 1 deletion src/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

#include <core_io.h>

#include <base58.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <key_io.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/standard.h>
Expand Down
10 changes: 4 additions & 6 deletions src/dash-tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
#include <config/dash-config.h>
#endif

#include <base58.h>
#include <clientversion.h>
#include <coins.h>
#include <consensus/consensus.h>
#include <core_io.h>
#include <key_io.h>
#include <keystore.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
Expand Down Expand Up @@ -516,12 +516,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
throw std::runtime_error("privatekey not a std::string");
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
if (!fGood)
CKey key = DecodeSecret(keysObj[kidx].getValStr());
if (!key.IsValid()) {
throw std::runtime_error("privatekey not valid");

CKey key = vchSecret.GetKey();
}
tempKeystore.AddKey(key);
}

Expand Down
2 changes: 1 addition & 1 deletion src/evo/providertx.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <consensus/validation.h>
#include <primitives/transaction.h>

#include <base58.h>
#include <key_io.h>
#include <netaddress.h>
#include <pubkey.h>
#include <univalue.h>
Expand Down
2 changes: 1 addition & 1 deletion src/governance/governance-validators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <governance/governance-object.h>
#include <governance/governance-validators.h>

#include <base58.h>
#include <key_io.h>
#include <timedata.h>
#include <tinyformat.h>
#include <utilstrencodings.h>
Expand Down
Loading

0 comments on commit 5e311b6

Please sign in to comment.