diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,6 +112,7 @@ core_io.h \ core_memusage.h \ cuckoocache.h \ + dstencode.h \ globals.h \ httprpc.h \ httpserver.h \ @@ -325,8 +326,11 @@ cashaddr.cpp \ cashaddrenc.cpp \ chainparams.cpp \ + config.cpp \ coins.cpp \ compressor.cpp \ + dstencode.cpp \ + globals.cpp \ core_read.cpp \ core_write.cpp \ key.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -88,6 +88,7 @@ test/crypto_tests.cpp \ test/cuckoocache_tests.cpp \ test/DoS_tests.cpp \ + test/dstencode_tests.cpp \ test/excessiveblock_tests.cpp \ test/getarg_tests.cpp \ test/hash_tests.cpp \ diff --git a/src/base58.h b/src/base58.h --- a/src/base58.h +++ b/src/base58.h @@ -155,10 +155,7 @@ 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 ¶ms); +std::string EncodeLegacyAddr(const CTxDestination &dest, const CChainParams &); +CTxDestination DecodeLegacyAddr(const std::string &str, const CChainParams &); #endif // BITCOIN_BASE58_H diff --git a/src/base58.cpp b/src/base58.cpp --- a/src/base58.cpp +++ b/src/base58.cpp @@ -257,6 +257,7 @@ } return CNoDestination(); } +} // namespace } // namespace @@ -291,19 +292,12 @@ 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 ¶ms) { - return IsValidDestination(DecodeDestination(str, params)); +std::string EncodeLegacyAddr(const CTxDestination &dest, + const CChainParams ¶ms) { + return boost::apply_visitor(DestinationEncoder(params), dest); } -bool IsValidDestinationString(const std::string &str) { - return IsValidDestination(DecodeDestination(str, Params())); +CTxDestination DecodeLegacyAddr(const std::string &str, + const CChainParams ¶ms) { + return DecodeDestination(str, params); } diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -7,10 +7,12 @@ #endif #include "base58.h" +#include "chainparams.h" #include "clientversion.h" #include "coins.h" #include "consensus/consensus.h" #include "core_io.h" +#include "dstencode.h" #include "keystore.h" #include "policy/policy.h" #include "primitives/transaction.h" diff --git a/src/config.h b/src/config.h --- a/src/config.h +++ b/src/config.h @@ -19,15 +19,23 @@ SetBlockPriorityPercentage(int64_t blockPriorityPercentage) = 0; virtual uint8_t GetBlockPriorityPercentage() const = 0; virtual const CChainParams &GetChainParams() const = 0; + virtual void SetCashAddrEncoding(bool) = 0; + virtual bool UseCashAddrEncoding() const = 0; }; class GlobalConfig final : public Config { public: + GlobalConfig(); bool SetMaxBlockSize(uint64_t maxBlockSize); uint64_t GetMaxBlockSize() const; bool SetBlockPriorityPercentage(int64_t blockPriorityPercentage); uint8_t GetBlockPriorityPercentage() const; const CChainParams &GetChainParams() const; + void SetCashAddrEncoding(bool) override; + bool UseCashAddrEncoding() const override; + +private: + bool useCashAddr; }; // Temporary woraround. diff --git a/src/config.cpp b/src/config.cpp --- a/src/config.cpp +++ b/src/config.cpp @@ -7,6 +7,8 @@ #include "consensus/consensus.h" #include "globals.h" +GlobalConfig::GlobalConfig() : useCashAddr(false) {} + bool GlobalConfig::SetMaxBlockSize(uint64_t maxBlockSize) { // Do not allow maxBlockSize to be set below historic 1MB limit // It cannot be equal either because of the "must be big" UAHF rule. @@ -44,3 +46,10 @@ const Config &GetConfig() { return gConfig; } + +void GlobalConfig::SetCashAddrEncoding(bool c) { + useCashAddr = c; +} +bool GlobalConfig::UseCashAddrEncoding() const { + return useCashAddr; +} diff --git a/src/core_write.cpp b/src/core_write.cpp --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -4,7 +4,7 @@ #include "core_io.h" -#include "base58.h" +#include "dstencode.h" #include "primitives/transaction.h" #include "script/script.h" #include "script/standard.h" diff --git a/src/dstencode.h b/src/dstencode.h new file mode 100644 --- /dev/null +++ b/src/dstencode.h @@ -0,0 +1,26 @@ +#ifndef BITCOIN_DSTENCODE_H +#define BITCOIN_DSTENCODE_H + +// key.h and pubkey.h are not used here, but gcc doesn't want to instantiate +// CTxDestination if types are unknown +#include "key.h" +#include "pubkey.h" +#include "script/standard.h" +#include + +class Config; +class CChainParams; + +std::string EncodeDestination(const CTxDestination &, const CChainParams &, + const Config &); +CTxDestination DecodeDestination(const std::string &addr, const CChainParams &); +bool IsValidDestinationString(const std::string &addr, + const CChainParams ¶ms); + +// Temporary workaround. Don't rely on global state, pass all parameters in new +// code. +std::string EncodeDestination(const CTxDestination &); +CTxDestination DecodeDestination(const std::string &addr); +bool IsValidDestinationString(const std::string &addr); + +#endif // BITCOIN_DSTENCODE_H diff --git a/src/dstencode.cpp b/src/dstencode.cpp new file mode 100644 --- /dev/null +++ b/src/dstencode.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2017 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "dstencode.h" +#include "base58.h" +#include "cashaddrenc.h" +#include "chainparams.h" +#include "config.h" +#include "script/standard.h" + +std::string EncodeDestination(const CTxDestination &dst, + const CChainParams ¶ms, const Config &cfg) { + return cfg.UseCashAddrEncoding() ? EncodeCashAddr(dst, params) + : EncodeLegacyAddr(dst, params); +} + +CTxDestination DecodeDestination(const std::string &addr, + const CChainParams ¶ms) { + CTxDestination dst = DecodeCashAddr(addr, params); + if (IsValidDestination(dst)) { + return dst; + } + return DecodeLegacyAddr(addr, params); +} + +bool IsValidDestinationString(const std::string &addr, + const CChainParams ¶ms) { + return IsValidDestination(DecodeDestination(addr, params)); +} + +std::string EncodeDestination(const CTxDestination &dst) { + return EncodeDestination(dst, Params(), GetConfig()); +} + +CTxDestination DecodeDestination(const std::string &addr) { + return DecodeDestination(addr, Params()); +} + +bool IsValidDestinationString(const std::string &addr) { + return IsValidDestinationString(addr, Params()); +} diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -1574,6 +1574,7 @@ } } } + return true; } diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -7,7 +7,7 @@ #include "guiutil.h" #include "walletmodel.h" -#include "base58.h" +#include "dstencode.h" #include "wallet/wallet.h" #include diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp --- a/src/qt/bitcoinaddressvalidator.cpp +++ b/src/qt/bitcoinaddressvalidator.cpp @@ -4,7 +4,7 @@ #include "bitcoinaddressvalidator.h" -#include "base58.h" +#include "dstencode.h" /* Base58 characters are: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -13,6 +13,7 @@ #include "txmempool.h" #include "walletmodel.h" +#include "dstencode.h" #include "init.h" #include "policy/policy.h" #include "validation.h" // For mempool diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -9,6 +9,7 @@ #include "qvalidatedlineedit.h" #include "walletmodel.h" +#include "dstencode.h" #include "init.h" #include "policy/policy.h" #include "primitives/transaction.h" diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -8,8 +8,8 @@ #include "guiutil.h" #include "optionsmodel.h" -#include "base58.h" #include "chainparams.h" +#include "dstencode.h" #include "policy/policy.h" #include "ui_interface.h" #include "util.h" diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -15,8 +15,8 @@ #include "sendcoinsentry.h" #include "walletmodel.h" -#include "base58.h" #include "chainparams.h" +#include "dstencode.h" #include "txmempool.h" #include "ui_interface.h" #include "validation.h" // mempool and minRelayTxFee diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -10,7 +10,7 @@ #include "platformstyle.h" #include "walletmodel.h" -#include "base58.h" +#include "dstencode.h" #include "init.h" #include "validation.h" // For strMessageMagic #include "wallet/wallet.h" diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -9,8 +9,8 @@ #include "paymentserver.h" #include "transactionrecord.h" -#include "base58.h" #include "consensus/consensus.h" +#include "dstencode.h" #include "script/script.h" #include "timedata.h" #include "util.h" diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -4,8 +4,8 @@ #include "transactionrecord.h" -#include "base58.h" #include "consensus/consensus.h" +#include "dstencode.h" #include "timedata.h" #include "validation.h" #include "wallet/finaltx.h" diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -12,7 +12,7 @@ #include "recentrequeststablemodel.h" #include "transactiontablemodel.h" -#include "base58.h" +#include "dstencode.h" #include "keystore.h" #include "net.h" // for g_connman #include "sync.h" diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -4,7 +4,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "amount.h" -#include "base58.h" #include "chain.h" #include "chainparams.h" #include "config.h" @@ -12,6 +11,7 @@ #include "consensus/params.h" #include "consensus/validation.h" #include "core_io.h" +#include "dstencode.h" #include "init.h" #include "miner.h" #include "net.h" diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -4,10 +4,10 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "rpc/misc.h" - #include "base58.h" #include "clientversion.h" #include "config.h" +#include "dstencode.h" #include "init.h" #include "net.h" #include "netbase.h" diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -9,6 +9,7 @@ #include "config.h" #include "consensus/validation.h" #include "core_io.h" +#include "dstencode.h" #include "init.h" #include "keystore.h" #include "merkleblock.h" diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -163,7 +163,7 @@ "key mismatch:" + strTest); // Private key must be invalid public key - destination = DecodeDestination(exp_base58string); + destination = DecodeLegacyAddr(exp_base58string, Params()); BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest); } else { @@ -171,7 +171,7 @@ std::string exp_addrType = find_value(metadata, "addrType").get_str(); // Must be valid public key - destination = DecodeDestination(exp_base58string); + destination = DecodeLegacyAddr(exp_base58string, Params()); BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest); BOOST_CHECK_MESSAGE((boost::get(&destination) != @@ -236,7 +236,7 @@ BOOST_ERROR("Bad addrtype: " << strTest); continue; } - std::string address = EncodeDestination(dest); + std::string address = EncodeLegacyAddr(dest, Params()); BOOST_CHECK_MESSAGE(address == exp_base58string, "mismatch: " + strTest); } @@ -267,7 +267,7 @@ std::string exp_base58string = test[0].get_str(); // must be invalid as public and as private key - destination = DecodeDestination(exp_base58string); + destination = DecodeLegacyAddr(exp_base58string, Params()); BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest); secret.SetString(exp_base58string); diff --git a/src/test/dstencode_tests.cpp b/src/test/dstencode_tests.cpp new file mode 100644 --- /dev/null +++ b/src/test/dstencode_tests.cpp @@ -0,0 +1,78 @@ +// Copyright (c) 2017 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chainparams.h" +#include "config.h" +#include "dstencode.h" +#include "test/test_bitcoin.h" + +#include + +namespace { + +class DummyCfg : public Config { +public: + DummyCfg() : useCashAddr(false) {} + virtual bool SetMaxBlockSize(uint64_t maxBlockSize) { return false; } + virtual uint64_t GetMaxBlockSize() const { return 0; } + virtual bool SetBlockPriorityPercentage(int64_t blockPriorityPercentage) { + return false; + } + virtual uint8_t GetBlockPriorityPercentage() const { return 0; } + virtual const CChainParams &GetChainParams() const { + return Params(CBaseChainParams::MAIN); + } + virtual void SetCashAddrEncoding(bool b) { useCashAddr = b; } + virtual bool UseCashAddrEncoding() const { return useCashAddr; } + +private: + bool useCashAddr; +}; + +} // anon ns + +BOOST_FIXTURE_TEST_SUITE(dstencode_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(test_addresses) { + std::vector hash = {118, 160, 64, 83, 189, 160, 168, + 139, 218, 81, 119, 184, 106, 21, + 195, 178, 159, 85, 152, 115}; + + const CTxDestination dstKey = CKeyID(uint160(hash)); + const CTxDestination dstScript = CScriptID(uint160(hash)); + + std::string cashaddr_pubkey = + "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"; + std::string cashaddr_script = + "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"; + std::string base58_pubkey = "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu"; + std::string base58_script = "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC"; + + const CChainParams ¶ms = Params(CBaseChainParams::MAIN); + DummyCfg cfg; + + // Check encoding + cfg.SetCashAddrEncoding(true); + BOOST_CHECK_EQUAL(cashaddr_pubkey, EncodeDestination(dstKey, params, cfg)); + BOOST_CHECK_EQUAL(cashaddr_script, + EncodeDestination(dstScript, params, cfg)); + cfg.SetCashAddrEncoding(false); + BOOST_CHECK_EQUAL(base58_pubkey, EncodeDestination(dstKey, params, cfg)); + BOOST_CHECK_EQUAL(base58_script, EncodeDestination(dstScript, params, cfg)); + + // Check decoding + BOOST_CHECK(dstKey == DecodeDestination(cashaddr_pubkey, params)); + BOOST_CHECK(dstScript == DecodeDestination(cashaddr_script, params)); + BOOST_CHECK(dstKey == DecodeDestination(base58_pubkey, params)); + BOOST_CHECK(dstScript == DecodeDestination(base58_script, params)); + + // Validation + BOOST_CHECK(IsValidDestinationString(cashaddr_pubkey, params)); + BOOST_CHECK(IsValidDestinationString(cashaddr_script, params)); + BOOST_CHECK(IsValidDestinationString(base58_pubkey, params)); + BOOST_CHECK(IsValidDestinationString(base58_script, params)); + BOOST_CHECK(!IsValidDestinationString("notvalid", params)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -5,6 +5,7 @@ #include "key.h" #include "base58.h" +#include "dstencode.h" #include "script/script.h" #include "test/test_bitcoin.h" #include "uint256.h" diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -5,6 +5,7 @@ #include "base58.h" #include "chain.h" #include "core_io.h" +#include "dstencode.h" #include "init.h" #include "merkleblock.h" #include "rpc/server.h" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4,12 +4,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "amount.h" -#include "base58.h" #include "chain.h" #include "chainparams.h" // for GetConsensus. #include "config.h" #include "consensus/validation.h" #include "core_io.h" +#include "dstencode.h" #include "init.h" #include "net.h" #include "rpc/misc.h" diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5,12 +5,12 @@ #include "wallet/wallet.h" -#include "base58.h" #include "chain.h" #include "checkpoints.h" #include "config.h" #include "consensus/consensus.h" #include "consensus/validation.h" +#include "dstencode.h" #include "key.h" #include "keystore.h" #include "net.h" diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -5,8 +5,8 @@ #include "wallet/walletdb.h" -#include "base58.h" #include "consensus/validation.h" +#include "dstencode.h" #include "protocol.h" #include "serialize.h" #include "sync.h"