From 07ff0d19a03870234bbbddce393ad5e3ec2d3581 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Thu, 9 Jul 2020 16:53:54 -0600 Subject: [PATCH] Make evident the relationship between chainparams and key IO. --- src/bitcoin-tx.cpp | 8 +- src/chainparams.cpp | 154 +++++++++------- src/chainparams.h | 46 ++--- src/consensus/params.cpp | 10 +- src/consensus/params.h | 33 ++++ src/core_write.cpp | 3 +- src/gtest/test_foundersreward.cpp | 13 +- src/gtest/test_keys.cpp | 13 +- src/init.cpp | 12 +- src/key_io.cpp | 166 +++++++++--------- src/key_io.h | 42 +++-- src/miner.cpp | 6 +- src/rpc/blockchain.cpp | 7 +- src/rpc/mining.cpp | 2 +- src/rpc/misc.cpp | 31 ++-- src/rpc/rawtransaction.cpp | 17 +- src/test/base58_tests.cpp | 21 ++- src/test/bip32_tests.cpp | 9 +- src/test/bloom_tests.cpp | 3 +- src/test/key_tests.cpp | 40 +++-- src/utiltest.cpp | 3 +- .../asyncrpcoperation_mergetoaddress.cpp | 8 +- .../asyncrpcoperation_saplingmigration.cpp | 3 +- src/wallet/asyncrpcoperation_sendmany.cpp | 22 ++- .../asyncrpcoperation_shieldcoinbase.cpp | 7 +- src/wallet/paymentdisclosure.cpp | 6 +- src/wallet/rpcdisclosure.cpp | 4 +- src/wallet/rpcdump.cpp | 63 ++++--- src/wallet/rpcwallet.cpp | 133 ++++++++------ src/wallet/test/rpc_wallet_tests.cpp | 89 ++++++---- src/wallet/wallet.cpp | 47 +++-- src/wallet/walletdb.cpp | 8 +- 32 files changed, 607 insertions(+), 422 deletions(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 1bb304596..473ad3f1c 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -240,9 +240,11 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn if (!ParseMoney(strValue, value)) throw std::runtime_error("invalid TX output value"); + KeyIO keyIO(Params()); + // extract and validate ADDRESS std::string strAddr = strInput.substr(pos + 1, std::string::npos); - CTxDestination destination = DecodeDestination(strAddr); + CTxDestination destination = keyIO.DecodeDestination(strAddr); if (!IsValidDestination(destination)) { throw std::runtime_error("invalid TX output address"); } @@ -399,10 +401,12 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput) UniValue keysObj = registers["privatekeys"]; fGivenKeys = true; + KeyIO keyIO(Params()); + for (size_t kidx = 0; kidx < keysObj.size(); kidx++) { if (!keysObj[kidx].isStr()) throw std::runtime_error("privatekey not a std::string"); - CKey key = DecodeSecret(keysObj[kidx].getValStr()); + CKey key = keyIO.DecodeSecret(keysObj[kidx].getValStr()); if (!key.IsValid()) { throw std::runtime_error("privatekey not valid"); } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 49752b0b5..51279ef0c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -127,6 +127,48 @@ public: consensus.nFundingPeriodLength = consensus.nPostBlossomSubsidyHalvingInterval / 48; + // guarantees the first 2 characters, when base58 encoded, are "t1" + keyInfo.base58Prefixes[PUBKEY_ADDRESS] = {0x1C,0xB8}; + // guarantees the first 2 characters, when base58 encoded, are "t3" + keyInfo.base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBD}; + // the first character, when base58 encoded, is "5" or "K" or "L" (as in Bitcoin) + keyInfo.base58Prefixes[SECRET_KEY] = {0x80}; + // do not rely on these BIP32 prefixes; they are not specified and may change + keyInfo.base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x88,0xB2,0x1E}; + keyInfo.base58Prefixes[EXT_SECRET_KEY] = {0x04,0x88,0xAD,0xE4}; + // guarantees the first 2 characters, when base58 encoded, are "zc" + keyInfo.base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0x9A}; + // guarantees the first 4 characters, when base58 encoded, are "ZiVK" + keyInfo.base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAB,0xD3}; + // guarantees the first 2 characters, when base58 encoded, are "SK" + keyInfo.base58Prefixes[ZCSPENDING_KEY] = {0xAB,0x36}; + + keyInfo.bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs"; + keyInfo.bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews"; + keyInfo.bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks"; + keyInfo.bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-main"; + keyInfo.bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviews"; + + // TODO: This `if` can be removed once canopy activation height is set. + if (consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { + std::vector addresses(48, ""); + consensus.AddZIP207FundingStream( + keyInfo, + Consensus::FS_ZIP214_ECC, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + consensus.AddZIP207FundingStream( + keyInfo, + Consensus::FS_ZIP214_ZF, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + consensus.AddZIP207FundingStream( + keyInfo, + Consensus::FS_ZIP214_MG, + consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, + addresses); + } + // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("000000000000000000000000000000000000000000000000017e73a331fae01c"); @@ -157,28 +199,6 @@ public: vSeeds.push_back(CDNSSeedData("zfnd.org", "mainnet.seeder.zfnd.org")); // Zcash Foundation vSeeds.push_back(CDNSSeedData("yolo.money", "mainnet.is.yolo.money")); // gtank - // guarantees the first 2 characters, when base58 encoded, are "t1" - base58Prefixes[PUBKEY_ADDRESS] = {0x1C,0xB8}; - // guarantees the first 2 characters, when base58 encoded, are "t3" - base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBD}; - // the first character, when base58 encoded, is "5" or "K" or "L" (as in Bitcoin) - base58Prefixes[SECRET_KEY] = {0x80}; - // do not rely on these BIP32 prefixes; they are not specified and may change - base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x88,0xB2,0x1E}; - base58Prefixes[EXT_SECRET_KEY] = {0x04,0x88,0xAD,0xE4}; - // guarantees the first 2 characters, when base58 encoded, are "zc" - base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0x9A}; - // guarantees the first 4 characters, when base58 encoded, are "ZiVK" - base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAB,0xD3}; - // guarantees the first 2 characters, when base58 encoded, are "SK" - base58Prefixes[ZCSPENDING_KEY] = {0xAB,0x36}; - - bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs"; - bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews"; - bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks"; - bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-main"; - bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviews"; - vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); fMiningRequiresPeers = true; @@ -336,20 +356,46 @@ public: consensus.nFundingPeriodLength = consensus.nPostBlossomSubsidyHalvingInterval / 48; + // guarantees the first 2 characters, when base58 encoded, are "tm" + keyInfo.base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; + // guarantees the first 2 characters, when base58 encoded, are "t2" + keyInfo.base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; + // the first character, when base58 encoded, is "9" or "c" (as in Bitcoin) + keyInfo.base58Prefixes[SECRET_KEY] = {0xEF}; + // do not rely on these BIP32 prefixes; they are not specified and may change + keyInfo.base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; + keyInfo.base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; + // guarantees the first 2 characters, when base58 encoded, are "zt" + keyInfo.base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6}; + // guarantees the first 4 characters, when base58 encoded, are "ZiVt" + keyInfo.base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; + // guarantees the first 2 characters, when base58 encoded, are "ST" + keyInfo.base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; + + keyInfo.bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling"; + keyInfo.bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling"; + keyInfo.bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling"; + keyInfo.bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-test"; + keyInfo.bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviewtestsapling"; + // TODO: This `if` can be removed once canopy activation height is set. if (consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { + std::vector addresses(48, ""); consensus.AddZIP207FundingStream( + keyInfo, Consensus::FS_ZIP214_ECC, consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, - {/*TODO*/}); + addresses); consensus.AddZIP207FundingStream( + keyInfo, Consensus::FS_ZIP214_ZF, consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, - {/*TODO*/}); + addresses); consensus.AddZIP207FundingStream( + keyInfo, Consensus::FS_ZIP214_MG, consensus.vUpgrades[Consensus::UPGRADE_CANOPY].nActivationHeight, 2726400, - {/*TODO*/}); + addresses); } // On testnet we activate this rule 6 blocks after Blossom activation. From block 299188 and @@ -395,28 +441,6 @@ public: vSeeds.push_back(CDNSSeedData("zfnd.org", "testnet.seeder.zfnd.org")); // Zcash Foundation vSeeds.push_back(CDNSSeedData("yolo.money", "testnet.is.yolo.money")); // gtank - // guarantees the first 2 characters, when base58 encoded, are "tm" - base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; - // guarantees the first 2 characters, when base58 encoded, are "t2" - base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; - // the first character, when base58 encoded, is "9" or "c" (as in Bitcoin) - base58Prefixes[SECRET_KEY] = {0xEF}; - // do not rely on these BIP32 prefixes; they are not specified and may change - base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; - base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; - // guarantees the first 2 characters, when base58 encoded, are "zt" - base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6}; - // guarantees the first 4 characters, when base58 encoded, are "ZiVt" - base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; - // guarantees the first 2 characters, when base58 encoded, are "ST" - base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; - - bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling"; - bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling"; - bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling"; - bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-test"; - bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviewtestsapling"; - vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); fMiningRequiresPeers = true; @@ -517,6 +541,23 @@ public: consensus.nFundingPeriodLength = consensus.nPostBlossomSubsidyHalvingInterval / 48; // Defined funding streams can be enabled with node config flags. + // These prefixes are the same as the testnet prefixes + keyInfo.base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; + keyInfo.base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; + keyInfo.base58Prefixes[SECRET_KEY] = {0xEF}; + // do not rely on these BIP32 prefixes; they are not specified and may change + keyInfo.base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; + keyInfo.base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; + keyInfo.base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6}; + keyInfo.base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; + keyInfo.base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; + + keyInfo.bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling"; + keyInfo.bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling"; + keyInfo.bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivkregtestsapling"; + keyInfo.bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-regtest"; + keyInfo.bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviewregtestsapling"; + // The best chain should have at least this much work. consensus.nMinimumChainWork = uint256S("0x00"); @@ -552,22 +593,6 @@ public: 0, 0 }; - // These prefixes are the same as the testnet prefixes - base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; - base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; - base58Prefixes[SECRET_KEY] = {0xEF}; - // do not rely on these BIP32 prefixes; they are not specified and may change - base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; - base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; - base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6}; - base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; - base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; - - bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling"; - bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling"; - bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivkregtestsapling"; - bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-regtest"; - bech32HRPs[SAPLING_EXTENDED_FVK] = "zxviewregtestsapling"; // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" }; @@ -659,7 +684,8 @@ std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const { CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const { assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight)); - CTxDestination address = DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str()); + KeyIO keyIO(*this); + CTxDestination address = keyIO.DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str()); assert(IsValidDestination(address)); assert(IsScriptDestination(address)); CScriptID scriptID = boost::get(address); // address is a boost variant diff --git a/src/chainparams.h b/src/chainparams.h index 11dbacd96..136b40a67 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -32,6 +32,15 @@ struct CCheckpointData { double fTransactionsPerDay; }; +class CBaseKeyInfo : public Consensus::KeyInfo { +public: + const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } + const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; } + + std::vector base58Prefixes[Consensus::KeyInfo::MAX_BASE58_TYPES]; + std::string bech32HRPs[Consensus::KeyInfo::MAX_BECH32_TYPES]; +}; + /** * CChainParams defines various tweakable parameters of a given instance of the * Bitcoin system. There are three: the main network on which people trade goods @@ -39,33 +48,9 @@ struct CCheckpointData { * a regression test mode which is intended for private networks only. It has * minimal difficulty to ensure that blocks can be found instantly. */ -class CChainParams +class CChainParams: public Consensus::KeyInfo { public: - enum Base58Type { - PUBKEY_ADDRESS, - SCRIPT_ADDRESS, - SECRET_KEY, - EXT_PUBLIC_KEY, - EXT_SECRET_KEY, - - ZCPAYMENT_ADDRRESS, - ZCSPENDING_KEY, - ZCVIEWING_KEY, - - MAX_BASE58_TYPES - }; - - enum Bech32Type { - SAPLING_PAYMENT_ADDRESS, - SAPLING_FULL_VIEWING_KEY, - SAPLING_INCOMING_VIEWING_KEY, - SAPLING_EXTENDED_SPEND_KEY, - SAPLING_EXTENDED_FVK, - - MAX_BECH32_TYPES - }; - const Consensus::Params& GetConsensus() const { return consensus; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector& AlertKey() const { return vAlertPubKey; } @@ -93,8 +78,12 @@ public: /** Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } const std::vector& DNSSeeds() const { return vSeeds; } - const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } - const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; } + const std::vector& Base58Prefix(Base58Type type) const { + return keyInfo.Base58Prefix(type); + } + const std::string& Bech32HRP(Bech32Type type) const { + return keyInfo.Bech32HRP(type); + } const std::vector& FixedSeeds() const { return vFixedSeeds; } const CCheckpointData& Checkpoints() const { return checkpointData; } /** Return the founder's reward address and script for a given block height */ @@ -113,8 +102,7 @@ protected: int nDefaultPort = 0; uint64_t nPruneAfterHeight = 0; std::vector vSeeds; - std::vector base58Prefixes[MAX_BASE58_TYPES]; - std::string bech32HRPs[MAX_BECH32_TYPES]; + CBaseKeyInfo keyInfo; std::string strNetworkID; std::string strCurrencyUnits; uint32_t bip44CoinType; diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 1ddf0dc88..3623e0e48 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -142,18 +142,21 @@ namespace Consensus { FundingStream FundingStream::ParseFundingStream( const Consensus::Params& params, + const Consensus::KeyInfo& keyInfo, const int startHeight, const int endHeight, const std::vector& strAddresses) { + KeyIO keyIO(keyInfo); + // Parse the address strings into concrete types. std::vector addresses; for (auto addr : strAddresses) { - auto taddr = DecodeDestination(addr); + auto taddr = keyIO.DecodeDestination(addr); if (IsValidDestination(taddr)) { addresses.push_back(GetScriptForDestination(taddr)); } else { - auto zaddr = DecodePaymentAddress(addr); + auto zaddr = keyIO.DecodePaymentAddress(addr); // If the string is not a valid transparent or Sapling address, we will // throw here. @@ -166,12 +169,13 @@ namespace Consensus { }; void Params::AddZIP207FundingStream( + const Consensus::KeyInfo& keyInfo, FundingStreamIndex idx, int startHeight, int endHeight, const std::vector& strAddresses) { - vFundingStreams[idx] = FundingStream::ParseFundingStream(*this, startHeight, endHeight, strAddresses); + vFundingStreams[idx] = FundingStream::ParseFundingStream(*this, keyInfo, startHeight, endHeight, strAddresses); }; FundingStreamAddress FundingStream::RecipientAddress(const Consensus::Params& params, int nHeight) const diff --git a/src/consensus/params.h b/src/consensus/params.h index 959c7f190..2c36d879d 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -101,6 +101,37 @@ enum FundingStreamError { INSUFFICIENT_ADDRESSES, }; +class KeyInfo +{ +public: + enum Base58Type { + PUBKEY_ADDRESS, + SCRIPT_ADDRESS, + SECRET_KEY, + EXT_PUBLIC_KEY, + EXT_SECRET_KEY, + + ZCPAYMENT_ADDRRESS, + ZCSPENDING_KEY, + ZCVIEWING_KEY, + + MAX_BASE58_TYPES + }; + + enum Bech32Type { + SAPLING_PAYMENT_ADDRESS, + SAPLING_FULL_VIEWING_KEY, + SAPLING_INCOMING_VIEWING_KEY, + SAPLING_EXTENDED_SPEND_KEY, + SAPLING_EXTENDED_FVK, + + MAX_BECH32_TYPES + }; + + virtual const std::vector& Base58Prefix(Base58Type type) const =0; + virtual const std::string& Bech32HRP(Bech32Type type) const =0; +}; + class FundingStream { private: @@ -123,6 +154,7 @@ public: static FundingStream ParseFundingStream( const Consensus::Params& params, + const Consensus::KeyInfo& keyInfo, const int startHeight, const int endHeight, const std::vector& strAddresses); @@ -209,6 +241,7 @@ struct Params { int nFundingPeriodLength; boost::optional vFundingStreams[MAX_FUNDING_STREAMS]; void AddZIP207FundingStream( + const Consensus::KeyInfo& keyInfo, FundingStreamIndex idx, int startHeight, int endHeight, diff --git a/src/core_write.cpp b/src/core_write.cpp index 89a545a99..a974f4fad 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -142,9 +142,10 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("reqSigs", nRequired); out.pushKV("type", GetTxnOutputType(type)); + KeyIO keyIO(Params()); UniValue a(UniValue::VARR); for (const CTxDestination& addr : addresses) { - a.push_back(EncodeDestination(addr)); + a.push_back(keyIO.EncodeDestination(addr)); } out.pushKV("addresses", a); } diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index b85b43136..3f7a7c106 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -42,6 +42,7 @@ TEST(FoundersRewardTest, create_testnet_2of3multisig) { pubkeys.resize(3); CPubKey newKey; std::vector addresses; + KeyIO keyIO(Params()); for (int i = 0; i < numKeys; i++) { ASSERT_TRUE(pWallet->GetKeyFromPool(newKey)); pubkeys[0] = newKey; @@ -61,7 +62,7 @@ TEST(FoundersRewardTest, create_testnet_2of3multisig) { pWallet->AddCScript(result); pWallet->SetAddressBook(innerID, "", "receive"); - std::string address = EncodeDestination(innerID); + std::string address = keyIO.EncodeDestination(innerID); addresses.push_back(address); } @@ -239,19 +240,22 @@ TEST(FundingStreamsRewardTest, Zip207Distribution) { int minHeight = GetLastFoundersRewardHeight(consensus) + 1; + KeyIO keyIO(Params()); auto sk = libzcash::SaplingSpendingKey(uint256()); for (int idx = Consensus::FIRST_FUNDING_STREAM; idx < Consensus::MAX_FUNDING_STREAMS; idx++) { // we can just use the same addresses for all streams, all we're trying to do here // is validate that the streams add up to the 20% of block reward. + auto shieldedAddr = keyIO.EncodePaymentAddress(sk.default_address()); UpdateFundingStreamParameters( (Consensus::FundingStreamIndex) idx, Consensus::FundingStream::ParseFundingStream( consensus, + Params(), minHeight, minHeight + 12, { "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", - EncodePaymentAddress(sk.default_address()) + shieldedAddr, } ) ); @@ -278,15 +282,18 @@ TEST(FundingStreamsRewardTest, ParseFundingStream) { int minHeight = GetLastFoundersRewardHeight(consensus) + 1; + KeyIO keyIO(Params()); auto sk = libzcash::SaplingSpendingKey(uint256()); + auto shieldedAddr = keyIO.EncodePaymentAddress(sk.default_address()); ASSERT_THROW( Consensus::FundingStream::ParseFundingStream( consensus, + Params(), minHeight, minHeight + 13, { "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", - EncodePaymentAddress(sk.default_address()) + shieldedAddr, } ), std::runtime_error diff --git a/src/gtest/test_keys.cpp b/src/gtest/test_keys.cpp index a74ef066d..eb2735a28 100644 --- a/src/gtest/test_keys.cpp +++ b/src/gtest/test_keys.cpp @@ -9,18 +9,19 @@ TEST(Keys, EncodeAndDecodeSapling) { SelectParams(CBaseChainParams::MAIN); + KeyIO keyIO(Params()); auto m = GetTestMasterSaplingSpendingKey(); for (uint32_t i = 0; i < 1000; i++) { auto sk = m.Derive(i); { - std::string sk_string = EncodeSpendingKey(sk); + std::string sk_string = keyIO.EncodeSpendingKey(sk); EXPECT_EQ( sk_string.substr(0, 24), Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)); - auto spendingkey2 = DecodeSpendingKey(sk_string); + auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string); EXPECT_TRUE(IsValidSpendingKey(spendingkey2)); ASSERT_TRUE(boost::get(&spendingkey2) != nullptr); @@ -29,12 +30,12 @@ TEST(Keys, EncodeAndDecodeSapling) } { auto extfvk = sk.ToXFVK(); - std::string vk_string = EncodeViewingKey(extfvk); + std::string vk_string = keyIO.EncodeViewingKey(extfvk); EXPECT_EQ( vk_string.substr(0, 7), Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK)); - auto viewingkey2 = DecodeViewingKey(vk_string); + auto viewingkey2 = keyIO.DecodeViewingKey(vk_string); EXPECT_TRUE(IsValidViewingKey(viewingkey2)); ASSERT_TRUE(boost::get(&viewingkey2) != nullptr); @@ -44,12 +45,12 @@ TEST(Keys, EncodeAndDecodeSapling) { auto addr = sk.DefaultAddress(); - std::string addr_string = EncodePaymentAddress(addr); + std::string addr_string = keyIO.EncodePaymentAddress(addr); EXPECT_EQ( addr_string.substr(0, 2), Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)); - auto paymentaddr2 = DecodePaymentAddress(addr_string); + auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string); EXPECT_TRUE(IsValidPaymentAddress(paymentaddr2)); ASSERT_TRUE(boost::get(&paymentaddr2) != nullptr); diff --git a/src/init.cpp b/src/init.cpp index 4634926f1..e1ab31852 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1039,12 +1039,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + KeyIO keyIO(chainparams); #ifdef ENABLE_MINING if (mapArgs.count("-mineraddress")) { - CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]); + CTxDestination addr = keyIO.DecodeDestination(mapArgs["-mineraddress"]); if (!IsValidDestination(addr)) { // Try a Sapling address - auto zaddr = DecodePaymentAddress(mapArgs["-mineraddress"]); + auto zaddr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]); if (!IsValidPaymentAddress(zaddr) || boost::get(&zaddr) == nullptr) { @@ -1127,7 +1128,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) std::vector vStreamAddrs; boost::split(vStreamAddrs, vStreamParams[3], boost::is_any_of(",")); - auto fs = Consensus::FundingStream::ParseFundingStream(Params().GetConsensus(), nStartHeight, nEndHeight, vStreamAddrs); + auto fs = Consensus::FundingStream::ParseFundingStream( + Params().GetConsensus(), Params(), nStartHeight, nEndHeight, vStreamAddrs); UpdateFundingStreamParameters((Consensus::FundingStreamIndex) nFundingStreamId, fs); } @@ -1586,12 +1588,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #ifdef ENABLE_WALLET bool minerAddressInLocalWallet = false; if (pwalletMain) { - CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]); + CTxDestination addr = keyIO.DecodeDestination(mapArgs["-mineraddress"]); if (IsValidDestination(addr)) { CKeyID keyID = boost::get(addr); minerAddressInLocalWallet = pwalletMain->HaveKey(keyID); } else { - auto zaddr = DecodePaymentAddress(mapArgs["-mineraddress"]); + auto zaddr = keyIO.DecodePaymentAddress(mapArgs["-mineraddress"]); minerAddressInLocalWallet = boost::apply_visitor( HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr); } diff --git a/src/key_io.cpp b/src/key_io.cpp index bc11197c9..9f3e9757b 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -22,21 +22,21 @@ namespace class DestinationEncoder : public boost::static_visitor { private: - const CChainParams& m_params; + const Consensus::KeyInfo& keyInfo; public: - DestinationEncoder(const CChainParams& params) : m_params(params) {} + DestinationEncoder(const Consensus::KeyInfo& keyInfo) : keyInfo(keyInfo) {} std::string operator()(const CKeyID& id) const { - std::vector data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); + std::vector data = keyInfo.Base58Prefix(Consensus::KeyInfo::PUBKEY_ADDRESS); data.insert(data.end(), id.begin(), id.end()); return EncodeBase58Check(data); } std::string operator()(const CScriptID& id) const { - std::vector data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); + std::vector data = keyInfo.Base58Prefix(Consensus::KeyInfo::SCRIPT_ADDRESS); data.insert(data.end(), id.begin(), id.end()); return EncodeBase58Check(data); } @@ -44,43 +44,19 @@ public: std::string operator()(const CNoDestination& no) const { return {}; } }; -CTxDestination DecodeDestination(const std::string& str, const CChainParams& params) -{ - std::vector 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& 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& 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(); -} - class PaymentAddressEncoder : public boost::static_visitor { private: - const CChainParams& m_params; + const Consensus::KeyInfo& keyInfo; public: - PaymentAddressEncoder(const CChainParams& params) : m_params(params) {} + PaymentAddressEncoder(const Consensus::KeyInfo& keyInfo) : keyInfo(keyInfo) {} std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << zaddr; - std::vector data = m_params.Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS); + std::vector data = keyInfo.Base58Prefix(Consensus::KeyInfo::ZCPAYMENT_ADDRRESS); data.insert(data.end(), ss.begin(), ss.end()); return EncodeBase58Check(data); } @@ -95,7 +71,7 @@ public: // See calculation comment below data.reserve((seraddr.size() * 8 + 4) / 5); ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, seraddr.begin(), seraddr.end()); - return bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS), data); + return bech32::Encode(keyInfo.Bech32HRP(Consensus::KeyInfo::SAPLING_PAYMENT_ADDRESS), data); } std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; } @@ -104,16 +80,16 @@ public: class ViewingKeyEncoder : public boost::static_visitor { private: - const CChainParams& m_params; + const Consensus::KeyInfo& keyInfo; public: - ViewingKeyEncoder(const CChainParams& params) : m_params(params) {} + ViewingKeyEncoder(const Consensus::KeyInfo& keyInfo) : keyInfo(keyInfo) {} std::string operator()(const libzcash::SproutViewingKey& vk) const { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << vk; - std::vector data = m_params.Base58Prefix(CChainParams::ZCVIEWING_KEY); + std::vector data = keyInfo.Base58Prefix(Consensus::KeyInfo::ZCVIEWING_KEY); data.insert(data.end(), ss.begin(), ss.end()); std::string ret = EncodeBase58Check(data); memory_cleanse(data.data(), data.size()); @@ -130,7 +106,7 @@ public: // See calculation comment below data.reserve((serkey.size() * 8 + 4) / 5); ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end()); - std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK), data); + std::string ret = bech32::Encode(keyInfo.Bech32HRP(Consensus::KeyInfo::SAPLING_EXTENDED_FVK), data); memory_cleanse(serkey.data(), serkey.size()); memory_cleanse(data.data(), data.size()); return ret; @@ -142,16 +118,16 @@ public: class SpendingKeyEncoder : public boost::static_visitor { private: - const CChainParams& m_params; + const Consensus::KeyInfo& keyInfo; public: - SpendingKeyEncoder(const CChainParams& params) : m_params(params) {} + SpendingKeyEncoder(const Consensus::KeyInfo& keyInfo) : keyInfo(keyInfo) {} std::string operator()(const libzcash::SproutSpendingKey& zkey) const { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << zkey; - std::vector data = m_params.Base58Prefix(CChainParams::ZCSPENDING_KEY); + std::vector data = keyInfo.Base58Prefix(Consensus::KeyInfo::ZCSPENDING_KEY); data.insert(data.end(), ss.begin(), ss.end()); std::string ret = EncodeBase58Check(data); memory_cleanse(data.data(), data.size()); @@ -168,7 +144,7 @@ public: // See calculation comment below data.reserve((serkey.size() * 8 + 4) / 5); ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end()); - std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY), data); + std::string ret = bech32::Encode(keyInfo.Bech32HRP(Consensus::KeyInfo::SAPLING_EXTENDED_SPEND_KEY), data); memory_cleanse(serkey.data(), serkey.size()); memory_cleanse(data.data(), data.size()); return ret; @@ -186,12 +162,36 @@ const size_t ConvertedSaplingExtendedFullViewingKeySize = (ZIP32_XFVK_SIZE * 8 + const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5; } // namespace -CKey DecodeSecret(const std::string& str) +CTxDestination KeyIO::DecodeDestination(const std::string& str) +{ + std::vector 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& pubkey_prefix = keyInfo.Base58Prefix(Consensus::KeyInfo::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& script_prefix = keyInfo.Base58Prefix(Consensus::KeyInfo::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(); +}; + +CKey KeyIO::DecodeSecret(const std::string& str) { CKey key; std::vector data; if (DecodeBase58Check(str, data)) { - const std::vector& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY); + const std::vector& privkey_prefix = keyInfo.Base58Prefix(Consensus::KeyInfo::SECRET_KEY); if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) && std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) { bool compressed = data.size() == 33 + privkey_prefix.size(); @@ -202,10 +202,10 @@ CKey DecodeSecret(const std::string& str) return key; } -std::string EncodeSecret(const CKey& key) +std::string KeyIO::EncodeSecret(const CKey& key) { assert(key.IsValid()); - std::vector data = Params().Base58Prefix(CChainParams::SECRET_KEY); + std::vector data = keyInfo.Base58Prefix(Consensus::KeyInfo::SECRET_KEY); data.insert(data.end(), key.begin(), key.end()); if (key.IsCompressed()) { data.push_back(1); @@ -215,12 +215,12 @@ std::string EncodeSecret(const CKey& key) return ret; } -CExtPubKey DecodeExtPubKey(const std::string& str) +CExtPubKey KeyIO::DecodeExtPubKey(const std::string& str) { CExtPubKey key; std::vector data; if (DecodeBase58Check(str, data)) { - const std::vector& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY); + const std::vector& prefix = keyInfo.Base58Prefix(Consensus::KeyInfo::EXT_PUBLIC_KEY); if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) { key.Decode(data.data() + prefix.size()); } @@ -228,9 +228,9 @@ CExtPubKey DecodeExtPubKey(const std::string& str) return key; } -std::string EncodeExtPubKey(const CExtPubKey& key) +std::string KeyIO::EncodeExtPubKey(const CExtPubKey& key) { - std::vector data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY); + std::vector data = keyInfo.Base58Prefix(Consensus::KeyInfo::EXT_PUBLIC_KEY); size_t size = data.size(); data.resize(size + BIP32_EXTKEY_SIZE); key.Encode(data.data() + size); @@ -238,12 +238,12 @@ std::string EncodeExtPubKey(const CExtPubKey& key) return ret; } -CExtKey DecodeExtKey(const std::string& str) +CExtKey KeyIO::DecodeExtKey(const std::string& str) { CExtKey key; std::vector data; if (DecodeBase58Check(str, data)) { - const std::vector& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY); + const std::vector& prefix = keyInfo.Base58Prefix(Consensus::KeyInfo::EXT_SECRET_KEY); if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) { key.Decode(data.data() + prefix.size()); } @@ -251,9 +251,9 @@ CExtKey DecodeExtKey(const std::string& str) return key; } -std::string EncodeExtKey(const CExtKey& key) +std::string KeyIO::EncodeExtKey(const CExtKey& key) { - std::vector data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY); + std::vector data = keyInfo.Base58Prefix(Consensus::KeyInfo::EXT_SECRET_KEY); size_t size = data.size(); data.resize(size + BIP32_EXTKEY_SIZE); key.Encode(data.data() + size); @@ -262,40 +262,31 @@ std::string EncodeExtKey(const CExtKey& key) return ret; } -std::string EncodeDestination(const CTxDestination& dest) +std::string KeyIO::EncodeDestination(const CTxDestination& dest) { - return boost::apply_visitor(DestinationEncoder(Params()), dest); + return boost::apply_visitor(DestinationEncoder(keyInfo), dest); } -CTxDestination DecodeDestination(const std::string& str) +bool KeyIO::IsValidDestinationString(const std::string& str) { - return DecodeDestination(str, Params()); + return IsValidDestination(DecodeDestination(str)); } -bool IsValidDestinationString(const std::string& str, const CChainParams& params) +std::string KeyIO::EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) { - return IsValidDestination(DecodeDestination(str, params)); -} - -bool IsValidDestinationString(const std::string& str) -{ - return IsValidDestinationString(str, Params()); -} - -std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) -{ - return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr); + return boost::apply_visitor(PaymentAddressEncoder(keyInfo), zaddr); } template T1 DecodeAny( + const Consensus::KeyInfo& keyInfo, const std::string& str, - std::pair sprout, - std::pair sapling) + std::pair sprout, + std::pair sapling) { std::vector data; if (DecodeBase58Check(str, data)) { - const std::vector& prefix = Params().Base58Prefix(sprout.first); + const std::vector& prefix = keyInfo.Base58Prefix(sprout.first); if ((data.size() == sprout.second + prefix.size()) && std::equal(prefix.begin(), prefix.end(), data.begin())) { CSerializeData serialized(data.begin() + prefix.size(), data.end()); @@ -310,7 +301,7 @@ T1 DecodeAny( data.clear(); auto bech = bech32::Decode(str); - if (bech.first == Params().Bech32HRP(sapling.first) && + if (bech.first == keyInfo.Bech32HRP(sapling.first) && bech.second.size() == sapling.second) { // Bech32 decoding data.reserve((bech.second.size() * 5) / 8); @@ -327,50 +318,53 @@ T1 DecodeAny( return libzcash::InvalidEncoding(); } -libzcash::PaymentAddress DecodePaymentAddress(const std::string& str) +libzcash::PaymentAddress KeyIO::DecodePaymentAddress(const std::string& str) { return DecodeAny( + keyInfo, str, - std::make_pair(CChainParams::ZCPAYMENT_ADDRRESS, libzcash::SerializedSproutPaymentAddressSize), - std::make_pair(CChainParams::SAPLING_PAYMENT_ADDRESS, ConvertedSaplingPaymentAddressSize) + std::make_pair(Consensus::KeyInfo::ZCPAYMENT_ADDRRESS, libzcash::SerializedSproutPaymentAddressSize), + std::make_pair(Consensus::KeyInfo::SAPLING_PAYMENT_ADDRESS, ConvertedSaplingPaymentAddressSize) ); } -bool IsValidPaymentAddressString(const std::string& str) { +bool KeyIO::IsValidPaymentAddressString(const std::string& str) { return IsValidPaymentAddress(DecodePaymentAddress(str)); } -std::string EncodeViewingKey(const libzcash::ViewingKey& vk) +std::string KeyIO::EncodeViewingKey(const libzcash::ViewingKey& vk) { - return boost::apply_visitor(ViewingKeyEncoder(Params()), vk); + return boost::apply_visitor(ViewingKeyEncoder(keyInfo), vk); } -libzcash::ViewingKey DecodeViewingKey(const std::string& str) +libzcash::ViewingKey KeyIO::DecodeViewingKey(const std::string& str) { return DecodeAny( + keyInfo, str, - std::make_pair(CChainParams::ZCVIEWING_KEY, libzcash::SerializedSproutViewingKeySize), - std::make_pair(CChainParams::SAPLING_EXTENDED_FVK, ConvertedSaplingExtendedFullViewingKeySize) + std::make_pair(Consensus::KeyInfo::ZCVIEWING_KEY, libzcash::SerializedSproutViewingKeySize), + std::make_pair(Consensus::KeyInfo::SAPLING_EXTENDED_FVK, ConvertedSaplingExtendedFullViewingKeySize) ); } -std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) +std::string KeyIO::EncodeSpendingKey(const libzcash::SpendingKey& zkey) { - return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey); + return boost::apply_visitor(SpendingKeyEncoder(keyInfo), zkey); } -libzcash::SpendingKey DecodeSpendingKey(const std::string& str) +libzcash::SpendingKey KeyIO::DecodeSpendingKey(const std::string& str) { return DecodeAny( + keyInfo, str, - std::make_pair(CChainParams::ZCSPENDING_KEY, libzcash::SerializedSproutSpendingKeySize), - std::make_pair(CChainParams::SAPLING_EXTENDED_SPEND_KEY, ConvertedSaplingExtendedSpendingKeySize) + std::make_pair(Consensus::KeyInfo::ZCSPENDING_KEY, libzcash::SerializedSproutSpendingKeySize), + std::make_pair(Consensus::KeyInfo::SAPLING_EXTENDED_SPEND_KEY, ConvertedSaplingExtendedSpendingKeySize) ); } diff --git a/src/key_io.h b/src/key_io.h index 64a26e979..68f538b5b 100644 --- a/src/key_io.h +++ b/src/key_io.h @@ -15,27 +15,35 @@ #include -CKey DecodeSecret(const std::string& str); -std::string EncodeSecret(const CKey& key); +class KeyIO { +private: + const Consensus::KeyInfo& keyInfo; -CExtKey DecodeExtKey(const std::string& str); -std::string EncodeExtKey(const CExtKey& extkey); -CExtPubKey DecodeExtPubKey(const std::string& str); -std::string EncodeExtPubKey(const CExtPubKey& extpubkey); +public: + KeyIO(const Consensus::KeyInfo& keyInfo): keyInfo(keyInfo) { } -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); + CKey DecodeSecret(const std::string& str); + std::string EncodeSecret(const CKey& key); -std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr); -libzcash::PaymentAddress DecodePaymentAddress(const std::string& str); -bool IsValidPaymentAddressString(const std::string& str); + CExtKey DecodeExtKey(const std::string& str); + std::string EncodeExtKey(const CExtKey& extkey); + CExtPubKey DecodeExtPubKey(const std::string& str); + std::string EncodeExtPubKey(const CExtPubKey& extpubkey); -std::string EncodeViewingKey(const libzcash::ViewingKey& vk); -libzcash::ViewingKey DecodeViewingKey(const std::string& str); + std::string EncodeDestination(const CTxDestination& dest); + CTxDestination DecodeDestination(const std::string& str); -std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey); -libzcash::SpendingKey DecodeSpendingKey(const std::string& str); + bool IsValidDestinationString(const std::string& str); + + std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr); + libzcash::PaymentAddress DecodePaymentAddress(const std::string& str); + bool IsValidPaymentAddressString(const std::string& str); + + std::string EncodeViewingKey(const libzcash::ViewingKey& vk); + libzcash::ViewingKey DecodeViewingKey(const std::string& str); + + std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey); + libzcash::SpendingKey DecodeSpendingKey(const std::string& str); +}; #endif // BITCOIN_KEYIO_H diff --git a/src/miner.cpp b/src/miner.cpp index 8897413e1..ef1651a6c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -645,9 +645,11 @@ class MinerAddressScript : public CReserveScript void GetMinerAddress(MinerAddress &minerAddress) { + KeyIO keyIO(Params()); + // Try a transparent address first auto mAddrArg = GetArg("-mineraddress", ""); - CTxDestination addr = DecodeDestination(mAddrArg); + CTxDestination addr = keyIO.DecodeDestination(mAddrArg); if (IsValidDestination(addr)) { boost::shared_ptr mAddr(new MinerAddressScript()); CKeyID keyID = boost::get(addr); @@ -656,7 +658,7 @@ void GetMinerAddress(MinerAddress &minerAddress) minerAddress = mAddr; } else { // Try a Sapling address - auto zaddr = DecodePaymentAddress(mAddrArg); + auto zaddr = keyIO.DecodePaymentAddress(mAddrArg); if (IsValidPaymentAddress(zaddr)) { if (boost::get(&zaddr) != nullptr) { minerAddress = boost::get(zaddr); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 9ae5a08a8..307572341 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -143,6 +143,7 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) result.pushKV("version", block.nVersion); result.pushKV("merkleroot", block.hashMerkleRoot.GetHex()); + KeyIO keyIO(Params()); UniValue deltas(UniValue::VARR); for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = block.vtx[i]; @@ -165,7 +166,7 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) } CTxDestination dest = DestFromAddressHash(spentInfo.addressType, spentInfo.addressHash); if (IsValidDestination(dest)) { - delta.pushKV("address", EncodeDestination(dest)); + delta.pushKV("address", keyIO.EncodeDestination(dest)); } delta.pushKV("satoshis", -1 * spentInfo.satoshis); delta.pushKV("index", (int)j); @@ -190,9 +191,9 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) dest = CKeyID(addrhash); } if (IsValidDestination(dest)) { - delta.pushKV("address", EncodeDestination(dest)); + delta.pushKV("address", keyIO.EncodeDestination(dest)); } - delta.pushKV("address", EncodeDestination(dest)); + delta.pushKV("address", keyIO.EncodeDestination(dest)); delta.pushKV("satoshis", out.nValue); delta.pushKV("index", (int)k); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index d3179ae13..51bf83a41 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -905,7 +905,7 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp) auto elems = Consensus::GetActiveFundingStreams(nHeight, consensus); for (auto elem : elems) { CAmount value = elem.Value(nBlockSubsidy); - fundingstreams.pushKV(elem.recipient, value); + fundingstreams.pushKV(elem.recipient, (double) value / COIN); nMinerReward -= value; } result.pushKV("fundingstreams", fundingstreams); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index a6fb58f7e..28d9a4780 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -127,6 +127,7 @@ public: } UniValue operator()(const CScriptID &scriptID) const { + KeyIO keyIO(Params()); UniValue obj(UniValue::VOBJ); CScript subscript; obj.pushKV("isscript", true); @@ -139,7 +140,7 @@ public: obj.pushKV("hex", HexStr(subscript.begin(), subscript.end())); UniValue a(UniValue::VARR); for (const CTxDestination& addr : addresses) { - a.push_back(EncodeDestination(addr)); + a.push_back(keyIO.EncodeDestination(addr)); } obj.pushKV("addresses", a); if (whichType == TX_MULTISIG) @@ -180,14 +181,15 @@ UniValue validateaddress(const UniValue& params, bool fHelp) LOCK(cs_main); #endif - CTxDestination dest = DecodeDestination(params[0].get_str()); + KeyIO keyIO(Params()); + CTxDestination dest = keyIO.DecodeDestination(params[0].get_str()); bool isValid = IsValidDestination(dest); UniValue ret(UniValue::VOBJ); ret.pushKV("isvalid", isValid); if (isValid) { - std::string currentAddress = EncodeDestination(dest); + std::string currentAddress = keyIO.EncodeDestination(dest); ret.pushKV("address", currentAddress); CScript scriptPubKey = GetScriptForDestination(dest); @@ -271,8 +273,9 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp) LOCK(cs_main); #endif + KeyIO keyIO(Params()); string strAddress = params[0].get_str(); - auto address = DecodePaymentAddress(strAddress); + auto address = keyIO.DecodePaymentAddress(strAddress); bool isValid = IsValidPaymentAddress(address); UniValue ret(UniValue::VOBJ); @@ -304,6 +307,9 @@ CScript _createmultisig_redeemScript(const UniValue& params) "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired)); if (keys.size() > 16) throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); + + KeyIO keyIO(Params()); + std::vector pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) @@ -311,7 +317,7 @@ CScript _createmultisig_redeemScript(const UniValue& params) const std::string& ks = keys[i].get_str(); #ifdef ENABLE_WALLET // Case 1: Bitcoin address and we have full public key: - CTxDestination dest = DecodeDestination(ks); + CTxDestination dest = keyIO.DecodeDestination(ks); if (pwalletMain && IsValidDestination(dest)) { const CKeyID *keyID = boost::get(&dest); if (!keyID) { @@ -385,8 +391,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp) CScript inner = _createmultisig_redeemScript(params); CScriptID innerID(inner); + KeyIO keyIO(Params()); UniValue result(UniValue::VOBJ); - result.pushKV("address", EncodeDestination(innerID)); + result.pushKV("address", keyIO.EncodeDestination(innerID)); result.pushKV("redeemScript", HexStr(inner.begin(), inner.end())); return result; @@ -421,7 +428,8 @@ UniValue verifymessage(const UniValue& params, bool fHelp) string strSign = params[1].get_str(); string strMessage = params[2].get_str(); - CTxDestination destination = DecodeDestination(strAddress); + KeyIO keyIO(Params()); + CTxDestination destination = keyIO.DecodeDestination(strAddress); if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } @@ -506,10 +514,11 @@ UniValue getexperimentalfeatures(const UniValue& params, bool fHelp) static bool getAddressFromIndex( int type, const uint160 &hash, std::string &address) { + KeyIO keyIO(Params()); if (type == CScript::P2SH) { - address = EncodeDestination(CScriptID(hash)); + address = keyIO.EncodeDestination(CScriptID(hash)); } else if (type == CScript::P2PKH) { - address = EncodeDestination(CKeyID(hash)); + address = keyIO.EncodeDestination(CKeyID(hash)); } else { return false; } @@ -560,8 +569,10 @@ static bool getAddressesFromParams( } else { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); } + + KeyIO keyIO(Params()); for (const auto& it : param_addresses) { - CTxDestination address = DecodeDestination(it); + CTxDestination address = keyIO.DecodeDestination(it); uint160 hashBytes; int type = 0; if (!getIndexKey(address, hashBytes, type)) { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 19543d1f4..b238a371e 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -51,9 +51,10 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud out.pushKV("reqSigs", nRequired); out.pushKV("type", GetTxnOutputType(type)); + KeyIO keyIO(Params()); UniValue a(UniValue::VARR); for (const CTxDestination& addr : addresses) { - a.push_back(EncodeDestination(addr)); + a.push_back(keyIO.EncodeDestination(addr)); } out.pushKV("addresses", a); } @@ -161,6 +162,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) if (tx.fOverwintered) { entry.pushKV("expiryheight", (int64_t)tx.nExpiryHeight); } + + KeyIO keyIO(Params()); UniValue vin(UniValue::VARR); BOOST_FOREACH(const CTxIn& txin, tx.vin) { UniValue in(UniValue::VOBJ); @@ -184,7 +187,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) CTxDestination dest = DestFromAddressHash(spentInfo.addressType, spentInfo.addressHash); if (IsValidDestination(dest)) { - in.pushKV("address", EncodeDestination(dest)); + in.pushKV("address", keyIO.EncodeDestination(dest)); } } } @@ -585,10 +588,11 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) rawTx.vin.push_back(in); } + KeyIO keyIO(Params()); std::set destinations; vector addrList = sendTo.getKeys(); for (const std::string& name_ : addrList) { - CTxDestination destination = DecodeDestination(name_); + CTxDestination destination = keyIO.DecodeDestination(name_); if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_); } @@ -740,7 +744,8 @@ UniValue decodescript(const UniValue& params, bool fHelp) } ScriptPubKeyToJSON(script, r, false); - r.pushKV("p2sh", EncodeDestination(CScriptID(script))); + KeyIO keyIO(Params()); + r.pushKV("p2sh", keyIO.EncodeDestination(CScriptID(script))); return r; } @@ -865,6 +870,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long } + KeyIO keyIO(Params()); + bool fGivenKeys = false; CBasicKeyStore tempKeystore; if (params.size() > 2 && !params[2].isNull()) { @@ -872,7 +879,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) UniValue keys = params[2].get_array(); for (size_t idx = 0; idx < keys.size(); idx++) { UniValue k = keys[idx]; - CKey key = DecodeSecret(k.get_str()); + CKey key = keyIO.DecodeSecret(k.get_str()); if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); tempKeystore.AddKey(key); diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index f7a6c9e39..8345c35e5 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -100,26 +100,28 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) } else { SelectParams(CBaseChainParams::MAIN); } + + KeyIO keyIO(Params()); if (isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); // Must be valid private key - privkey = DecodeSecret(exp_base58string); + privkey = keyIO.DecodeSecret(exp_base58string); BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest); BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest); 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 - destination = DecodeDestination(exp_base58string); + destination = keyIO.DecodeDestination(exp_base58string); BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest); } else { // Must be valid public key - destination = DecodeDestination(exp_base58string); + destination = keyIO.DecodeDestination(exp_base58string); CScript script = GetScriptForDestination(destination); BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest); BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload)); // Public key must be invalid private key - privkey = DecodeSecret(exp_base58string); + privkey = keyIO.DecodeSecret(exp_base58string); BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest); } } @@ -148,17 +150,19 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) } else { SelectParams(CBaseChainParams::MAIN); } + + KeyIO keyIO(Params()); if (isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); CKey key; key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); assert(key.IsValid()); - BOOST_CHECK_MESSAGE(EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest); + BOOST_CHECK_MESSAGE(keyIO.EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest); } else { CTxDestination dest; CScript exp_script(exp_payload.begin(), exp_payload.end()); ExtractDestination(exp_script, dest); - std::string address = EncodeDestination(dest); + std::string address = keyIO.EncodeDestination(dest); BOOST_CHECK_EQUAL(address, exp_base58string); } } @@ -173,6 +177,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) CKey privkey; CTxDestination destination; + KeyIO keyIO(Params()); for (size_t idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; std::string strTest = test.write(); @@ -184,9 +189,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) std::string exp_base58string = test[0].get_str(); // must be invalid as public and as private key - destination = DecodeDestination(exp_base58string); + destination = keyIO.DecodeDestination(exp_base58string); BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest); - privkey = DecodeSecret(exp_base58string); + privkey = keyIO.DecodeSecret(exp_base58string); BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey:" + strTest); } } diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 104173b19..3e3a00735 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -84,18 +84,19 @@ void RunTest(const TestVector &test) { CExtPubKey pubkey; key.SetMaster(&seed[0], seed.size()); pubkey = key.Neuter(); + KeyIO keyIO(Params()); BOOST_FOREACH(const TestDerivation &derive, test.vDerive) { unsigned char data[74]; key.Encode(data); pubkey.Encode(data); // Test private key - BOOST_CHECK(EncodeExtKey(key) == derive.prv); - BOOST_CHECK(DecodeExtKey(derive.prv) == key); //ensure a base58 decoded key also matches + BOOST_CHECK(keyIO.EncodeExtKey(key) == derive.prv); + BOOST_CHECK(keyIO.DecodeExtKey(derive.prv) == key); //ensure a base58 decoded key also matches // Test public key - BOOST_CHECK(EncodeExtPubKey(pubkey) == derive.pub); - BOOST_CHECK(DecodeExtPubKey(derive.pub) == pubkey); //ensure a base58 decoded pubkey also matches + BOOST_CHECK(keyIO.EncodeExtPubKey(pubkey) == derive.pub); + BOOST_CHECK(keyIO.DecodeExtPubKey(derive.pub) == pubkey); //ensure a base58 decoded pubkey also matches // Derive new keys CExtKey keyNew; diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index ef9c4cd28..377f5b614 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -86,8 +86,9 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) BOOST_AUTO_TEST_CASE(bloom_create_insert_key) { + KeyIO keyIO(Params()); std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); - CKey key = DecodeSecret(strSecret); + CKey key = keyIO.DecodeSecret(strSecret); CPubKey pubkey = key.GetPubKey(); vector vchPubKey(pubkey.begin(), pubkey.end()); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 6d28cd1b8..d87470b23 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -46,6 +46,7 @@ void dumpKeyInfo(uint256 privkey) memcpy(&sec[0], &secret[0], 32); printf(" * secret (hex): %s\n", HexStr(sec).c_str()); + KeyIO keyIO(Params()); for (int nCompressed=0; nCompressed<2; nCompressed++) { bool fCompressed = nCompressed == 1; @@ -57,7 +58,7 @@ void dumpKeyInfo(uint256 privkey) key.SetSecret(secret, fCompressed); vector vchPubKey = key.GetPubKey(); printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str()); - printf(" * address (base58): %s\n", EncodeDestination(vchPubKey).c_str()); + printf(" * address (base58): %s\n", keyIO.EncodeDestination(vchPubKey).c_str()); } } #endif @@ -67,15 +68,16 @@ BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(key_test1) { - CKey key1 = DecodeSecret(strSecret1); + KeyIO keyIO(Params()); + CKey key1 = keyIO.DecodeSecret(strSecret1); BOOST_CHECK(key1.IsValid() && !key1.IsCompressed()); - CKey key2 = DecodeSecret(strSecret2); + CKey key2 = keyIO.DecodeSecret(strSecret2); BOOST_CHECK(key2.IsValid() && !key2.IsCompressed()); - CKey key1C = DecodeSecret(strSecret1C); + CKey key1C = keyIO.DecodeSecret(strSecret1C); BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed()); - CKey key2C = DecodeSecret(strSecret2C); + CKey key2C = keyIO.DecodeSecret(strSecret2C); BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed()); - CKey bad_key = DecodeSecret(strAddressBad); + CKey bad_key = keyIO.DecodeSecret(strAddressBad); BOOST_CHECK(!bad_key.IsValid()); CPubKey pubkey1 = key1. GetPubKey(); @@ -103,10 +105,10 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(!key2C.VerifyPubKey(pubkey2)); BOOST_CHECK(key2C.VerifyPubKey(pubkey2C)); - 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())); + BOOST_CHECK(keyIO.DecodeDestination(addr1) == CTxDestination(pubkey1.GetID())); + BOOST_CHECK(keyIO.DecodeDestination(addr2) == CTxDestination(pubkey2.GetID())); + BOOST_CHECK(keyIO.DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID())); + BOOST_CHECK(keyIO.DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID())); for (int n=0; n<16; n++) { @@ -189,15 +191,16 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_AUTO_TEST_CASE(zc_address_test) { + KeyIO keyIO(Params()); for (size_t i = 0; i < 1000; i++) { auto sk = SproutSpendingKey::random(); { - string sk_string = EncodeSpendingKey(sk); + string sk_string = keyIO.EncodeSpendingKey(sk); BOOST_CHECK(sk_string[0] == 'S'); BOOST_CHECK(sk_string[1] == 'K'); - auto spendingkey2 = DecodeSpendingKey(sk_string); + auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string); BOOST_CHECK(IsValidSpendingKey(spendingkey2)); BOOST_ASSERT(boost::get(&spendingkey2) != nullptr); auto sk2 = boost::get(spendingkey2); @@ -206,12 +209,12 @@ BOOST_AUTO_TEST_CASE(zc_address_test) { auto addr = sk.address(); - std::string addr_string = EncodePaymentAddress(addr); + std::string addr_string = keyIO.EncodePaymentAddress(addr); BOOST_CHECK(addr_string[0] == 'z'); BOOST_CHECK(addr_string[1] == 'c'); - auto paymentaddr2 = DecodePaymentAddress(addr_string); + auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string); BOOST_ASSERT(IsValidPaymentAddress(paymentaddr2)); BOOST_ASSERT(boost::get(&paymentaddr2) != nullptr); @@ -228,13 +231,14 @@ BOOST_AUTO_TEST_CASE(zs_address_test) auto m = GetTestMasterSaplingSpendingKey(); + KeyIO keyIO(Params()); for (uint32_t i = 0; i < 1000; i++) { auto sk = m.Derive(i); { - std::string sk_string = EncodeSpendingKey(sk); + std::string sk_string = keyIO.EncodeSpendingKey(sk); BOOST_CHECK(sk_string.compare(0, 27, Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)) == 0); - auto spendingkey2 = DecodeSpendingKey(sk_string); + auto spendingkey2 = keyIO.DecodeSpendingKey(sk_string); BOOST_CHECK(IsValidSpendingKey(spendingkey2)); BOOST_ASSERT(boost::get(&spendingkey2) != nullptr); @@ -244,10 +248,10 @@ BOOST_AUTO_TEST_CASE(zs_address_test) { auto addr = sk.DefaultAddress(); - std::string addr_string = EncodePaymentAddress(addr); + std::string addr_string = keyIO.EncodePaymentAddress(addr); BOOST_CHECK(addr_string.compare(0, 15, Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)) == 0); - auto paymentaddr2 = DecodePaymentAddress(addr_string); + auto paymentaddr2 = keyIO.DecodePaymentAddress(addr_string); BOOST_CHECK(IsValidPaymentAddress(paymentaddr2)); BOOST_ASSERT(boost::get(&paymentaddr2) != nullptr); diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 24ac06a59..7dd79bdfe 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -286,7 +286,8 @@ libzcash::SaplingExtendedSpendingKey GetTestMasterSaplingSpendingKey() { } CKey AddTestCKeyToKeyStore(CBasicKeyStore& keyStore) { - CKey tsk = DecodeSecret(T_SECRET_REGTEST); + KeyIO keyIO(Params()); + CKey tsk = keyIO.DecodeSecret(T_SECRET_REGTEST); keyStore.AddKey(tsk); return tsk; } diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index 1f63b55e2..a10d425ff 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -91,12 +91,13 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress( builder_ = builder.get(); } - toTaddr_ = DecodeDestination(std::get<0>(recipient)); + KeyIO keyIO(Params()); + toTaddr_ = keyIO.DecodeDestination(std::get<0>(recipient)); isToTaddr_ = IsValidDestination(toTaddr_); isToZaddr_ = false; if (!isToTaddr_) { - auto address = DecodePaymentAddress(std::get<0>(recipient)); + auto address = keyIO.DecodePaymentAddress(std::get<0>(recipient)); if (IsValidPaymentAddress(address)) { isToZaddr_ = true; toPaymentAddress_ = address; @@ -866,6 +867,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit( arrOutputMap.push_back(static_cast(outputMap[i])); } + KeyIO keyIO(Params()); // !!! Payment disclosure START unsigned char buffer[32] = {0}; @@ -883,7 +885,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit( PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); + LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), keyIO.EncodePaymentAddress(zaddr)); } // !!! Payment disclosure END diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 991d167a7..596b97099 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -192,9 +192,10 @@ CAmount AsyncRPCOperation_saplingmigration::chooseAmount(const CAmount& availabl // Unless otherwise specified, the migration destination address is the address for Sapling account 0 libzcash::SaplingPaymentAddress AsyncRPCOperation_saplingmigration::getMigrationDestAddress(const HDSeed& seed) { + KeyIO keyIO(Params()); if (mapArgs.count("-migrationdestaddress")) { std::string migrationDestAddress = mapArgs["-migrationdestaddress"]; - auto address = DecodePaymentAddress(migrationDestAddress); + auto address = keyIO.DecodePaymentAddress(migrationDestAddress); auto saplingAddress = boost::get(&address); assert(saplingAddress != nullptr); // This is checked in init.cpp return *saplingAddress; diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index cdfa19d9d..e27fa2322 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -85,12 +85,14 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany( builder_ = builder.get(); } - fromtaddr_ = DecodeDestination(fromAddress); + KeyIO keyIO(Params()); + + fromtaddr_ = keyIO.DecodeDestination(fromAddress); isfromtaddr_ = IsValidDestination(fromtaddr_); isfromzaddr_ = false; if (!isfromtaddr_) { - auto address = DecodePaymentAddress(fromAddress); + auto address = keyIO.DecodePaymentAddress(fromAddress); if (IsValidPaymentAddress(address)) { // We don't need to lock on the wallet as spending key related methods are thread-safe if (!boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), address)) { @@ -343,6 +345,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total)); LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee)); + KeyIO keyIO(Params()); /** * SCENARIO #0 @@ -424,7 +427,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { auto value = r.amount; auto hexMemo = r.memo; - auto addr = DecodePaymentAddress(address); + auto addr = keyIO.DecodePaymentAddress(address); assert(boost::get(&addr) != nullptr); auto to = boost::get(addr); @@ -438,7 +441,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { auto outputAddress = r.address; auto amount = r.amount; - auto address = DecodeDestination(outputAddress); + auto address = keyIO.DecodeDestination(outputAddress); builder_.AddTransparentOutput(address, amount); } @@ -583,7 +586,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { std::string hexMemo = smr.memo; zOutputsDeque.pop_front(); - PaymentAddress pa = DecodePaymentAddress(address); + PaymentAddress pa = keyIO.DecodePaymentAddress(address); JSOutput jso = JSOutput(boost::get(pa), value); if (hexMemo.size() > 0) { jso.memo = get_memo_from_hex_string(hexMemo); @@ -845,7 +848,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { assert(value==0); info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new } else { - PaymentAddress pa = DecodePaymentAddress(address); + PaymentAddress pa = keyIO.DecodePaymentAddress(address); // If we are here, we know we have no Sapling outputs. JSOutput jso = JSOutput(boost::get(pa), value); if (hexMemo.size() > 0) { @@ -1145,6 +1148,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( arrOutputMap.push_back(static_cast(outputMap[i])); } + KeyIO keyIO(Params()); // !!! Payment disclosure START unsigned char buffer[32] = {0}; @@ -1162,7 +1166,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); + LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), keyIO.EncodePaymentAddress(zaddr)); } // !!! Payment disclosure END @@ -1179,11 +1183,13 @@ void AsyncRPCOperation_sendmany::add_taddr_outputs_to_tx() { CMutableTransaction rawTx(tx_); + KeyIO keyIO(Params()); + for (SendManyRecipient & r : t_outputs_) { std::string outputAddress = r.address; CAmount nAmount = r.amount; - CTxDestination address = DecodeDestination(outputAddress); + CTxDestination address = keyIO.DecodeDestination(outputAddress); if (!IsValidDestination(address)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid output address, not a valid taddr."); } diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 563061749..81e67c33f 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -74,7 +74,8 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase( } // Check the destination address is valid for this network i.e. not testnet being used on mainnet - auto address = DecodePaymentAddress(toAddress); + KeyIO keyIO(Params()); + auto address = keyIO.DecodePaymentAddress(toAddress); if (IsValidPaymentAddress(address)) { tozaddr_ = address; } else { @@ -386,6 +387,8 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf arrOutputMap.push_back(static_cast(outputMap[i])); } + KeyIO keyIO(Params()); + // !!! Payment disclosure START unsigned char buffer[32] = {0}; memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer @@ -402,7 +405,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); + LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), keyIO.EncodePaymentAddress(zaddr)); } // !!! Payment disclosure END diff --git a/src/wallet/paymentdisclosure.cpp b/src/wallet/paymentdisclosure.cpp index ddce48cc2..2512664da 100644 --- a/src/wallet/paymentdisclosure.cpp +++ b/src/wallet/paymentdisclosure.cpp @@ -8,8 +8,9 @@ #include "util.h" std::string PaymentDisclosureInfo::ToString() const { + KeyIO keyIO(Params()); return strprintf("PaymentDisclosureInfo(version=%d, esk=%s, joinSplitPrivKey=, address=%s)", - version, esk.ToString(), EncodePaymentAddress(zaddr)); + version, esk.ToString(), keyIO.EncodePaymentAddress(zaddr)); } std::string PaymentDisclosure::ToString() const { @@ -18,8 +19,9 @@ std::string PaymentDisclosure::ToString() const { } std::string PaymentDisclosurePayload::ToString() const { + KeyIO keyIO(Params()); return strprintf("PaymentDisclosurePayload(version=%d, esk=%s, txid=%s, js=%d, n=%d, address=%s, message=%s)", - version, esk.ToString(), txid.ToString(), js, n, EncodePaymentAddress(zaddr), message); + version, esk.ToString(), txid.ToString(), js, n, keyIO.EncodePaymentAddress(zaddr), message); } PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message) diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp index d8a5998c3..00370cf38 100644 --- a/src/wallet/rpcdisclosure.cpp +++ b/src/wallet/rpcdisclosure.cpp @@ -250,10 +250,12 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp) errs.push_back("Payment disclosure signature does not match transaction signature"); } + KeyIO keyIO(Params()); + // Check the payment address is valid SproutPaymentAddress zaddr = pd.payload.zaddr; { - o.pushKV("paymentAddress", EncodePaymentAddress(zaddr)); + o.pushKV("paymentAddress", keyIO.EncodePaymentAddress(zaddr)); try { // Decrypt the note to get value and memo field diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index dbbad1714..77d614926 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -116,7 +116,9 @@ UniValue importprivkey(const UniValue& params, bool fHelp) if (params.size() > 2) fRescan = params[2].get_bool(); - CKey key = DecodeSecret(strSecret); + KeyIO keyIO(Params()); + + CKey key = keyIO.DecodeSecret(strSecret); if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding"); CPubKey pubkey = key.GetPubKey(); @@ -128,7 +130,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp) // Don't throw error in case a key is already there if (pwalletMain->HaveKey(vchAddress)) { - return EncodeDestination(vchAddress); + return keyIO.EncodeDestination(vchAddress); } pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; @@ -144,7 +146,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp) } } - return EncodeDestination(vchAddress); + return keyIO.EncodeDestination(vchAddress); } void ImportAddress(const CTxDestination& dest, const string& strLabel); @@ -227,7 +229,8 @@ UniValue importaddress(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - CTxDestination dest = DecodeDestination(params[0].get_str()); + KeyIO keyIO(Params()); + CTxDestination dest = keyIO.DecodeDestination(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"); @@ -373,6 +376,8 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys) int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); file.seekg(0, file.beg); + KeyIO keyIO(Params()); + pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI while (file.good()) { pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100)))); @@ -388,7 +393,7 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys) // Let's see if the address is a valid Zcash spending key if (fImportZKeys) { - auto spendingkey = DecodeSpendingKey(vstr[0]); + auto spendingkey = keyIO.DecodeSpendingKey(vstr[0]); int64_t nTime = DecodeDumpTime(vstr[1]); // Only include hdKeypath and seedFpStr if we have both boost::optional hdKeypath = (vstr.size() > 3) ? boost::optional(vstr[2]) : boost::none; @@ -409,14 +414,14 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys) } } - CKey key = DecodeSecret(vstr[0]); + CKey key = keyIO.DecodeSecret(vstr[0]); if (!key.IsValid()) continue; CPubKey pubkey = key.GetPubKey(); assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); if (pwalletMain->HaveKey(keyid)) { - LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); + LogPrintf("Skipping import of %s (key already present)\n", keyIO.EncodeDestination(keyid)); continue; } int64_t nTime = DecodeDumpTime(vstr[1]); @@ -434,7 +439,7 @@ UniValue importwallet_impl(const UniValue& params, bool fImportZKeys) fLabel = true; } } - LogPrintf("Importing %s...\n", EncodeDestination(keyid)); + LogPrintf("Importing %s...\n", keyIO.EncodeDestination(keyid)); if (!pwalletMain->AddKeyPubKey(key, pubkey)) { fGood = false; continue; @@ -489,8 +494,10 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); + KeyIO keyIO(Params()); + std::string strAddress = params[0].get_str(); - CTxDestination dest = DecodeDestination(strAddress); + CTxDestination dest = keyIO.DecodeDestination(strAddress); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); } @@ -502,7 +509,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp) if (!pwalletMain->GetKey(*keyID, vchSecret)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); } - return EncodeSecret(vchSecret); + return keyIO.EncodeSecret(vchSecret); } @@ -593,6 +600,8 @@ UniValue dumpwallet_impl(const UniValue& params, bool fDumpZKeys) mapKeyBirth.clear(); std::sort(vKeyBirth.begin(), vKeyBirth.end()); + KeyIO keyIO(Params()); + // produce output file << strprintf("# Wallet dump created by Zcash %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime())); @@ -609,15 +618,15 @@ UniValue dumpwallet_impl(const UniValue& params, bool fDumpZKeys) 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 = EncodeDestination(keyid); + std::string strAddr = keyIO.EncodeDestination(keyid); CKey key; if (pwalletMain->GetKey(keyid, key)) { if (pwalletMain->mapAddressBook.count(keyid)) { - file << strprintf("%s %s label=%s # addr=%s\n", EncodeSecret(key), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr); + file << strprintf("%s %s label=%s # addr=%s\n", keyIO.EncodeSecret(key), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr); } else if (setKeyPool.count(keyid)) { - file << strprintf("%s %s reserve=1 # addr=%s\n", EncodeSecret(key), strTime, strAddr); + file << strprintf("%s %s reserve=1 # addr=%s\n", keyIO.EncodeSecret(key), strTime, strAddr); } else { - file << strprintf("%s %s change=1 # addr=%s\n", EncodeSecret(key), strTime, strAddr); + file << strprintf("%s %s change=1 # addr=%s\n", keyIO.EncodeSecret(key), strTime, strAddr); } } } @@ -633,7 +642,7 @@ UniValue dumpwallet_impl(const UniValue& params, bool fDumpZKeys) libzcash::SproutSpendingKey key; if (pwalletMain->GetSproutSpendingKey(addr, key)) { std::string strTime = EncodeDumpTime(pwalletMain->mapSproutZKeyMetadata[addr].nCreateTime); - file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(key), strTime, EncodePaymentAddress(addr)); + file << strprintf("%s %s # zaddr=%s\n", keyIO.EncodeSpendingKey(key), strTime, keyIO.EncodePaymentAddress(addr)); } } std::set saplingAddresses; @@ -649,9 +658,9 @@ UniValue dumpwallet_impl(const UniValue& params, bool fDumpZKeys) std::string strTime = EncodeDumpTime(keyMeta.nCreateTime); // Keys imported with z_importkey do not have zip32 metadata if (keyMeta.hdKeypath.empty() || keyMeta.seedFp.IsNull()) { - file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(extsk), strTime, EncodePaymentAddress(addr)); + file << strprintf("%s %s # zaddr=%s\n", keyIO.EncodeSpendingKey(extsk), strTime, keyIO.EncodePaymentAddress(addr)); } else { - file << strprintf("%s %s %s %s # zaddr=%s\n", EncodeSpendingKey(extsk), strTime, keyMeta.hdKeypath, keyMeta.seedFp.GetHex(), EncodePaymentAddress(addr)); + file << strprintf("%s %s %s %s # zaddr=%s\n", keyIO.EncodeSpendingKey(extsk), strTime, keyMeta.hdKeypath, keyMeta.seedFp.GetHex(), keyIO.EncodePaymentAddress(addr)); } } } @@ -737,8 +746,9 @@ UniValue z_importkey(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); } + KeyIO keyIO(Params()); string strSecret = params[0].get_str(); - auto spendingkey = DecodeSpendingKey(strSecret); + auto spendingkey = keyIO.DecodeSpendingKey(strSecret); if (!IsValidSpendingKey(spendingkey)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); } @@ -746,7 +756,7 @@ UniValue z_importkey(const UniValue& params, bool fHelp) auto addrInfo = boost::apply_visitor(libzcash::AddressInfoFromSpendingKey{}, spendingkey); UniValue result(UniValue::VOBJ); result.pushKV("type", addrInfo.first); - result.pushKV("address", EncodePaymentAddress(addrInfo.second)); + result.pushKV("address", keyIO.EncodePaymentAddress(addrInfo.second)); // Sapling support auto addResult = boost::apply_visitor(AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey); @@ -831,8 +841,9 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); } + KeyIO keyIO(Params()); string strVKey = params[0].get_str(); - auto viewingkey = DecodeViewingKey(strVKey); + auto viewingkey = keyIO.DecodeViewingKey(strVKey); if (!IsValidViewingKey(viewingkey)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key"); } @@ -840,7 +851,7 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) auto addrInfo = boost::apply_visitor(libzcash::AddressInfoFromViewingKey{}, viewingkey); UniValue result(UniValue::VOBJ); result.pushKV("type", addrInfo.first); - result.pushKV("address", EncodePaymentAddress(addrInfo.second)); + result.pushKV("address", keyIO.EncodePaymentAddress(addrInfo.second)); auto addResult = boost::apply_visitor(AddViewingKeyToWallet(pwalletMain), viewingkey); if (addResult == SpendingKeyExists) { @@ -889,7 +900,8 @@ UniValue z_exportkey(const UniValue& params, bool fHelp) string strAddress = params[0].get_str(); - auto address = DecodePaymentAddress(strAddress); + KeyIO keyIO(Params()); + auto address = keyIO.DecodePaymentAddress(strAddress); if (!IsValidPaymentAddress(address)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); } @@ -899,7 +911,7 @@ UniValue z_exportkey(const UniValue& params, bool fHelp) if (!sk) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr"); } - return EncodeSpendingKey(sk.get()); + return keyIO.EncodeSpendingKey(sk.get()); } UniValue z_exportviewingkey(const UniValue& params, bool fHelp) @@ -927,14 +939,15 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp) string strAddress = params[0].get_str(); - auto address = DecodePaymentAddress(strAddress); + KeyIO keyIO(Params()); + auto address = keyIO.DecodePaymentAddress(strAddress); if (!IsValidPaymentAddress(address)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); } auto vk = boost::apply_visitor(GetViewingKeyForPaymentAddress(pwalletMain), address); if (vk) { - return EncodeViewingKey(vk.get()); + return keyIO.EncodeViewingKey(vk.get()); } else { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr"); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 622a65ed1..27d491be2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -168,7 +168,8 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) pwalletMain->SetAddressBook(keyID, strAccount, "receive"); - return EncodeDestination(keyID); + KeyIO keyIO(Params()); + return keyIO.EncodeDestination(keyID); } @@ -236,7 +237,8 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp) UniValue ret(UniValue::VSTR); - ret = EncodeDestination(GetAccountAddress(strAccount)); + KeyIO keyIO(Params()); + ret = keyIO.EncodeDestination(GetAccountAddress(strAccount)); return ret; } @@ -272,7 +274,8 @@ UniValue getrawchangeaddress(const UniValue& params, bool fHelp) CKeyID keyID = vchPubKey.GetID(); - return EncodeDestination(keyID); + KeyIO keyIO(Params()); + return keyIO.EncodeDestination(keyID); } @@ -295,7 +298,8 @@ UniValue setaccount(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - CTxDestination dest = DecodeDestination(params[0].get_str()); + KeyIO keyIO(Params()); + CTxDestination dest = keyIO.DecodeDestination(params[0].get_str()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); } @@ -342,7 +346,8 @@ UniValue getaccount(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - CTxDestination dest = DecodeDestination(params[0].get_str()); + KeyIO keyIO(Params()); + CTxDestination dest = keyIO.DecodeDestination(params[0].get_str()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); } @@ -381,13 +386,14 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) string strAccount = AccountFromValue(params[0]); + KeyIO keyIO(Params()); // Find all addresses that have the given account UniValue ret(UniValue::VARR); for (const std::pair& item : pwalletMain->mapAddressBook) { const CTxDestination& dest = item.first; const std::string& strName = item.second.name; if (strName == strAccount) { - ret.push_back(EncodeDestination(dest)); + ret.push_back(keyIO.EncodeDestination(dest)); } } return ret; @@ -455,7 +461,8 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - CTxDestination dest = DecodeDestination(params[0].get_str()); + KeyIO keyIO(Params()); + CTxDestination dest = keyIO.DecodeDestination(params[0].get_str()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); } @@ -513,6 +520,7 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + KeyIO keyIO(Params()); UniValue jsonGroupings(UniValue::VARR); std::map balances = pwalletMain->GetAddressBalances(); for (const std::set& grouping : pwalletMain->GetAddressGroupings()) { @@ -520,7 +528,7 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp) for (const CTxDestination& address : grouping) { UniValue addressInfo(UniValue::VARR); - addressInfo.push_back(EncodeDestination(address)); + addressInfo.push_back(keyIO.EncodeDestination(address)); addressInfo.push_back(ValueFromAmount(balances[address])); { if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end()) { @@ -567,7 +575,8 @@ UniValue signmessage(const UniValue& params, bool fHelp) string strAddress = params[0].get_str(); string strMessage = params[1].get_str(); - CTxDestination dest = DecodeDestination(strAddress); + KeyIO keyIO(Params()); + CTxDestination dest = keyIO.DecodeDestination(strAddress); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } @@ -621,8 +630,9 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + KeyIO keyIO(Params()); // Bitcoin address - CTxDestination dest = DecodeDestination(params[0].get_str()); + CTxDestination dest = keyIO.DecodeDestination(params[0].get_str()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); } @@ -960,8 +970,9 @@ UniValue sendfrom(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + KeyIO keyIO(Params()); std::string strAccount = AccountFromValue(params[0]); - CTxDestination dest = DecodeDestination(params[1].get_str()); + CTxDestination dest = keyIO.DecodeDestination(params[1].get_str()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); } @@ -1053,10 +1064,11 @@ UniValue sendmany(const UniValue& params, bool fHelp) std::set destinations; std::vector vecSend; + KeyIO keyIO(Params()); CAmount totalAmount = 0; std::vector keys = sendTo.getKeys(); for (const std::string& name_ : keys) { - CTxDestination dest = DecodeDestination(name_); + CTxDestination dest = keyIO.DecodeDestination(name_); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_); } @@ -1152,7 +1164,8 @@ UniValue addmultisigaddress(const UniValue& params, bool fHelp) pwalletMain->AddCScript(inner); pwalletMain->SetAddressBook(innerID, strAccount, "send"); - return EncodeDestination(innerID); + KeyIO keyIO(Params()); + return keyIO.EncodeDestination(innerID); } @@ -1218,6 +1231,8 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) } } + KeyIO keyIO(Params()); + // Reply UniValue ret(UniValue::VARR); std::map mapAccountTally; @@ -1250,7 +1265,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) UniValue obj(UniValue::VOBJ); if(fIsWatchonly) obj.pushKV("involvesWatchonly", true); - obj.pushKV("address", EncodeDestination(dest)); + obj.pushKV("address", keyIO.EncodeDestination(dest)); obj.pushKV("account", strAccount); obj.pushKV("amount", ValueFromAmount(nAmount)); obj.pushKV("amountZat", nAmount); @@ -1366,7 +1381,8 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) { if (IsValidDestination(dest)) { - entry.pushKV("address", EncodeDestination(dest)); + KeyIO keyIO(Params()); + entry.pushKV("address", keyIO.EncodeDestination(dest)); } } @@ -2440,12 +2456,13 @@ UniValue listunspent(const UniValue& params, bool fHelp) if (params.size() > 1) nMaxDepth = params[1].get_int(); + KeyIO keyIO(Params()); std::set destinations; if (params.size() > 2) { UniValue inputs = params[2].get_array(); for (size_t idx = 0; idx < inputs.size(); idx++) { const UniValue& input = inputs[idx]; - CTxDestination dest = DecodeDestination(input.get_str()); + CTxDestination dest = keyIO.DecodeDestination(input.get_str()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + input.get_str()); } @@ -2477,7 +2494,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) entry.pushKV("generated", out.tx->IsCoinBase()); if (fValidAddress) { - entry.pushKV("address", EncodeDestination(address)); + entry.pushKV("address", keyIO.EncodeDestination(address)); if (pwalletMain->mapAddressBook.count(address)) entry.pushKV("account", pwalletMain->mapAddressBook[address].name); @@ -2575,6 +2592,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + KeyIO keyIO(Params()); // User has supplied zaddrs to filter on if (params.size() > 3) { UniValue addresses = params[3].get_array(); @@ -2590,7 +2608,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string"); } string address = o.get_str(); - auto zaddr = DecodePaymentAddress(address); + auto zaddr = keyIO.DecodePaymentAddress(address); if (!IsValidPaymentAddress(zaddr)) { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address); } @@ -2635,7 +2653,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) obj.pushKV("confirmations", entry.confirmations); bool hasSproutSpendingKey = HaveSpendingKeyForPaymentAddress(pwalletMain)(entry.address); obj.pushKV("spendable", hasSproutSpendingKey); - obj.pushKV("address", EncodePaymentAddress(entry.address)); + obj.pushKV("address", keyIO.EncodePaymentAddress(entry.address)); obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); std::string data(entry.memo.begin(), entry.memo.end()); obj.pushKV("memo", HexStr(data)); @@ -2652,7 +2670,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) obj.pushKV("confirmations", entry.confirmations); bool hasSaplingSpendingKey = HaveSpendingKeyForPaymentAddress(pwalletMain)(entry.address); obj.pushKV("spendable", hasSaplingSpendingKey); - obj.pushKV("address", EncodePaymentAddress(entry.address)); + obj.pushKV("address", keyIO.EncodePaymentAddress(entry.address)); obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value() obj.pushKV("memo", HexStr(entry.memo)); if (hasSaplingSpendingKey) { @@ -2914,7 +2932,8 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp) LOCK(cs_main); - auto spendingkey = DecodeSpendingKey(params[0].get_str()); + KeyIO keyIO(Params()); + auto spendingkey = keyIO.DecodeSpendingKey(params[0].get_str()); if (!IsValidSpendingKey(spendingkey)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); } @@ -3037,8 +3056,9 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) std::vector keys; std::vector commitments; + KeyIO keyIO(Params()); for (const string& name_ : inputs.getKeys()) { - auto spendingkey = DecodeSpendingKey(inputs[name_].get_str()); + auto spendingkey = keyIO.DecodeSpendingKey(inputs[name_].get_str()); if (!IsValidSpendingKey(spendingkey)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); } @@ -3086,7 +3106,7 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) } for (const string& name_ : outputs.getKeys()) { - auto addrTo = DecodePaymentAddress(name_); + auto addrTo = keyIO.DecodePaymentAddress(name_); if (!IsValidPaymentAddress(addrTo)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address."); } @@ -3206,10 +3226,11 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp) auto addr = k.address(); auto viewing_key = k.viewing_key(); + KeyIO keyIO(Params()); UniValue result(UniValue::VOBJ); - result.pushKV("zcaddress", EncodePaymentAddress(addr)); - result.pushKV("zcsecretkey", EncodeSpendingKey(k)); - result.pushKV("zcviewingkey", EncodeViewingKey(viewing_key)); + result.pushKV("zcaddress", keyIO.EncodePaymentAddress(addr)); + result.pushKV("zcsecretkey", keyIO.EncodeSpendingKey(k)); + result.pushKV("zcviewingkey", keyIO.EncodeViewingKey(viewing_key)); return result; } @@ -3246,10 +3267,11 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp) addrType = params[0].get_str(); } + KeyIO keyIO(Params()); if (addrType == ADDR_TYPE_SPROUT) { - return EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey()); + return keyIO.EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey()); } else if (addrType == ADDR_TYPE_SAPLING) { - return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey()); + return keyIO.EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey()); } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type"); } @@ -3284,13 +3306,14 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp) fIncludeWatchonly = params[0].get_bool(); } + KeyIO keyIO(Params()); UniValue ret(UniValue::VARR); { std::set addresses; pwalletMain->GetSproutPaymentAddresses(addresses); for (auto addr : addresses) { if (fIncludeWatchonly || HaveSpendingKeyForPaymentAddress(pwalletMain)(addr)) { - ret.push_back(EncodePaymentAddress(addr)); + ret.push_back(keyIO.EncodePaymentAddress(addr)); } } } @@ -3299,7 +3322,7 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp) pwalletMain->GetSaplingPaymentAddresses(addresses); for (auto addr : addresses) { if (fIncludeWatchonly || HaveSpendingKeyForPaymentAddress(pwalletMain)(addr)) { - ret.push_back(EncodePaymentAddress(addr)); + ret.push_back(keyIO.EncodePaymentAddress(addr)); } } } @@ -3311,8 +3334,9 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ign vector vecOutputs; CAmount balance = 0; + KeyIO keyIO(Params()); if (transparentAddress.length() > 0) { - CTxDestination taddr = DecodeDestination(transparentAddress); + CTxDestination taddr = keyIO.DecodeDestination(transparentAddress); if (!IsValidDestination(taddr)) { throw std::runtime_error("invalid transparent address"); } @@ -3427,7 +3451,8 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) // Check that the from address is valid. auto fromaddress = params[0].get_str(); - auto zaddr = DecodePaymentAddress(fromaddress); + KeyIO keyIO(Params()); + auto zaddr = keyIO.DecodePaymentAddress(fromaddress); if (!IsValidPaymentAddress(zaddr)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr."); } @@ -3530,13 +3555,14 @@ UniValue z_getbalance(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0"); } + KeyIO keyIO(Params()); // Check that the from address is valid. auto fromaddress = params[0].get_str(); bool fromTaddr = false; - CTxDestination taddr = DecodeDestination(fromaddress); + CTxDestination taddr = keyIO.DecodeDestination(fromaddress); fromTaddr = IsValidDestination(taddr); if (!fromTaddr) { - auto res = DecodePaymentAddress(fromaddress); + auto res = keyIO.DecodePaymentAddress(fromaddress); if (!IsValidPaymentAddress(res)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr."); } @@ -3705,6 +3731,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp) } }; + KeyIO keyIO(Params()); // Sprout spends for (size_t i = 0; i < wtx.vJoinSplit.size(); ++i) { for (size_t j = 0; j < wtx.vJoinSplit[i].nullifiers.size(); ++j) { @@ -3729,7 +3756,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp) entry.pushKV("txidPrev", jsop.hash.GetHex()); entry.pushKV("jsPrev", (int)jsop.js); entry.pushKV("jsOutputPrev", (int)jsop.n); - entry.pushKV("address", EncodePaymentAddress(pa)); + entry.pushKV("address", keyIO.EncodePaymentAddress(pa)); entry.pushKV("value", ValueFromAmount(notePt.value())); entry.pushKV("valueZat", notePt.value()); spends.push_back(entry); @@ -3749,7 +3776,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp) entry.pushKV("type", ADDR_TYPE_SPROUT); entry.pushKV("js", (int)jsop.js); entry.pushKV("jsOutput", (int)jsop.n); - entry.pushKV("address", EncodePaymentAddress(pa)); + entry.pushKV("address", keyIO.EncodePaymentAddress(pa)); entry.pushKV("value", ValueFromAmount(notePt.value())); entry.pushKV("valueZat", notePt.value()); addMemo(entry, memo); @@ -3792,7 +3819,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp) entry.pushKV("spend", (int)i); entry.pushKV("txidPrev", op.hash.GetHex()); entry.pushKV("outputPrev", (int)op.n); - entry.pushKV("address", EncodePaymentAddress(pa)); + entry.pushKV("address", keyIO.EncodePaymentAddress(pa)); entry.pushKV("value", ValueFromAmount(notePt.value())); entry.pushKV("valueZat", notePt.value()); spends.push_back(entry); @@ -3831,7 +3858,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp) entry.pushKV("type", ADDR_TYPE_SAPLING); entry.pushKV("output", (int)op.n); entry.pushKV("outgoing", isOutgoing); - entry.pushKV("address", EncodePaymentAddress(pa)); + entry.pushKV("address", keyIO.EncodePaymentAddress(pa)); entry.pushKV("value", ValueFromAmount(notePt.value())); entry.pushKV("valueZat", notePt.value()); addMemo(entry, memo); @@ -3997,10 +4024,11 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) auto fromaddress = params[0].get_str(); bool fromTaddr = false; bool fromSapling = false; - CTxDestination taddr = DecodeDestination(fromaddress); + KeyIO keyIO(Params()); + CTxDestination taddr = keyIO.DecodeDestination(fromaddress); fromTaddr = IsValidDestination(taddr); if (!fromTaddr) { - auto res = DecodePaymentAddress(fromaddress); + auto res = keyIO.DecodePaymentAddress(fromaddress); if (!IsValidPaymentAddress(res)) { // invalid throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr."); @@ -4049,9 +4077,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) string address = find_value(o, "address").get_str(); bool isZaddr = false; - CTxDestination taddr = DecodeDestination(address); + CTxDestination taddr = keyIO.DecodeDestination(address); if (!IsValidDestination(taddr)) { - auto res = DecodePaymentAddress(address); + auto res = keyIO.DecodePaymentAddress(address); if (IsValidPaymentAddress(res)) { isZaddr = true; @@ -4153,7 +4181,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) size_t txsize = 0; for (int i = 0; i < zaddrRecipients.size(); i++) { auto address = zaddrRecipients[i].address; - auto res = DecodePaymentAddress(address); + auto res = keyIO.DecodePaymentAddress(address); bool toSapling = boost::get(&res) != nullptr; if (toSapling) { mtx.vShieldedOutput.push_back(OutputDescription()); @@ -4302,7 +4330,8 @@ UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) { // parameter is not set and no default address has yet been generated. // Note: The following function may return the default address even if it has not been added to the wallet auto destinationAddress = AsyncRPCOperation_saplingmigration::getMigrationDestAddress(pwalletMain->GetHDSeedForRPC()); - migrationStatus.pushKV("destination_address", EncodePaymentAddress(destinationAddress)); + KeyIO keyIO(Params()); + migrationStatus.pushKV("destination_address", keyIO.EncodePaymentAddress(destinationAddress)); // The values of "unmigrated_amount" and "migrated_amount" MUST take into // account failed transactions, that were not mined within their expiration // height. @@ -4431,9 +4460,10 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) // Validate the from address auto fromaddress = params[0].get_str(); bool isFromWildcard = fromaddress == "*"; + KeyIO keyIO(Params()); CTxDestination taddr; if (!isFromWildcard) { - taddr = DecodeDestination(fromaddress); + taddr = keyIO.DecodeDestination(fromaddress); if (!IsValidDestination(taddr)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\"."); } @@ -4441,7 +4471,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) // Validate the destination address auto destaddress = params[1].get_str(); - if (!IsValidPaymentAddressString(destaddress)) { + if (!keyIO.IsValidPaymentAddressString(destaddress)) { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); } @@ -4449,7 +4479,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) const bool canopyActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_CANOPY); if (canopyActive) { - auto decodeAddr = DecodePaymentAddress(destaddress); + auto decodeAddr = keyIO.DecodePaymentAddress(destaddress); bool isToSproutZaddr = (boost::get(&decodeAddr) != nullptr); if (isToSproutZaddr) { @@ -4678,6 +4708,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) bool isFromNonSprout = false; + KeyIO keyIO(Params()); // Sources for (const UniValue& o : addresses.getValues()) { if (!o.isStr()) @@ -4694,12 +4725,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) useAnySapling = true; isFromNonSprout = true; } else { - CTxDestination taddr = DecodeDestination(address); + CTxDestination taddr = keyIO.DecodeDestination(address); if (IsValidDestination(taddr)) { taddrs.insert(taddr); isFromNonSprout = true; } else { - auto zaddr = DecodePaymentAddress(address); + auto zaddr = keyIO.DecodePaymentAddress(address); if (IsValidPaymentAddress(zaddr)) { zaddrs.insert(zaddr); if (boost::get(&zaddr) != nullptr) { @@ -4732,9 +4763,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) auto destaddress = params[1].get_str(); bool isToSproutZaddr = false; bool isToSaplingZaddr = false; - CTxDestination taddr = DecodeDestination(destaddress); + CTxDestination taddr = keyIO.DecodeDestination(destaddress); if (!IsValidDestination(taddr)) { - auto decodeAddr = DecodePaymentAddress(destaddress); + auto decodeAddr = keyIO.DecodePaymentAddress(destaddress); if (IsValidPaymentAddress(decodeAddr)) { if (boost::get(&decodeAddr) != nullptr) { isToSaplingZaddr = true; diff --git a/src/wallet/test/rpc_wallet_tests.cpp b/src/wallet/test/rpc_wallet_tests.cpp index c2ccd4bce..3c5f536ee 100644 --- a/src/wallet/test/rpc_wallet_tests.cpp +++ b/src/wallet/test/rpc_wallet_tests.cpp @@ -68,18 +68,19 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig) // new, compressed: const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4"; + KeyIO keyIO(Params()); UniValue v; CTxDestination address; BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false)); - address = DecodeDestination(v.get_str()); + address = keyIO.DecodeDestination(v.get_str()); BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address)); BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false)); - address = DecodeDestination(v.get_str()); + address = keyIO.DecodeDestination(v.get_str()); BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address)); BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false)); - address = DecodeDestination(v.get_str()); + address = keyIO.DecodeDestination(v.get_str()); BOOST_CHECK(IsValidDestination(address) && IsScriptDestination(address)); BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error); @@ -122,9 +123,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) /********************************* * setaccount *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("setaccount " + EncodeDestination(setaccountDemoAddress) + " \"\"")); + KeyIO keyIO(Params()); + BOOST_CHECK_NO_THROW(CallRPC("setaccount " + keyIO.EncodeDestination(setaccountDemoAddress) + " \"\"")); /* Accounts are disabled */ - BOOST_CHECK_THROW(CallRPC("setaccount " + EncodeDestination(setaccountDemoAddress) + " nullaccount"), runtime_error); + BOOST_CHECK_THROW(CallRPC("setaccount " + keyIO.EncodeDestination(setaccountDemoAddress) + " nullaccount"), runtime_error); /* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV is not owned by the test wallet. */ BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV nullaccount"), runtime_error); BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error); @@ -136,7 +138,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) * getbalance *********************************/ BOOST_CHECK_NO_THROW(CallRPC("getbalance")); - BOOST_CHECK_THROW(CallRPC("getbalance " + EncodeDestination(demoAddress)), runtime_error); + BOOST_CHECK_THROW(CallRPC("getbalance " + keyIO.EncodeDestination(demoAddress)), runtime_error); /********************************* * listunspent @@ -178,10 +180,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) * listtransactions *********************************/ BOOST_CHECK_NO_THROW(CallRPC("listtransactions")); - BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress))); - BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " 20")); - BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " 20 0")); - BOOST_CHECK_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " not_int"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress))); + BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " 20")); + BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " 20 0")); + BOOST_CHECK_THROW(CallRPC("listtransactions " + keyIO.EncodeDestination(demoAddress) + " not_int"), runtime_error); /********************************* * listlockunspent @@ -218,33 +220,33 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) /* Accounts are deprecated */ BOOST_CHECK_THROW(CallRPC("getaccountaddress accountThatDoesntExists"), runtime_error); BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount)); - BOOST_CHECK(DecodeDestination(retValue.get_str()) == demoAddress); + BOOST_CHECK(keyIO.DecodeDestination(retValue.get_str()) == demoAddress); /********************************* * getaccount *********************************/ BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC("getaccount " + EncodeDestination(demoAddress))); + BOOST_CHECK_NO_THROW(CallRPC("getaccount " + keyIO.EncodeDestination(demoAddress))); /********************************* * signmessage + verifymessage *********************************/ - BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + EncodeDestination(demoAddress) + " mymessage")); + BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + keyIO.EncodeDestination(demoAddress) + " mymessage")); BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error); /* Should throw error because this address is not loaded in the wallet */ BOOST_CHECK_THROW(CallRPC("signmessage t1h8SqgtM3QM5e2M8EzhhT1yL2PXXtA6oqe mymessage"), runtime_error); /* missing arguments */ - BOOST_CHECK_THROW(CallRPC("verifymessage " + EncodeDestination(demoAddress)), runtime_error); - BOOST_CHECK_THROW(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str()), runtime_error); + BOOST_CHECK_THROW(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress)), runtime_error); + BOOST_CHECK_THROW(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress) + " " + retValue.get_str()), runtime_error); /* Illegal address */ BOOST_CHECK_THROW(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg " + retValue.get_str() + " mymessage"), runtime_error); /* wrong address */ BOOST_CHECK(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV " + retValue.get_str() + " mymessage").get_bool() == false); /* Correct address and signature but wrong message */ - BOOST_CHECK(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str() + " wrongmessage").get_bool() == false); + BOOST_CHECK(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress) + " " + retValue.get_str() + " wrongmessage").get_bool() == false); /* Correct address, message and signature*/ - BOOST_CHECK(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str() + " mymessage").get_bool() == true); + BOOST_CHECK(CallRPC("verifymessage " + keyIO.EncodeDestination(demoAddress) + " " + retValue.get_str() + " mymessage").get_bool() == true); /********************************* * getaddressesbyaccount @@ -255,7 +257,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_EQUAL(4, arr.size()); bool notFound = true; for (auto a : arr.getValues()) { - notFound &= DecodeDestination(a.get_str()) != demoAddress; + notFound &= keyIO.DecodeDestination(a.get_str()) != demoAddress; } BOOST_CHECK(!notFound); @@ -516,8 +518,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet) libzcash::SproutSpendingKey key; BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, key)); - std::string s1 = EncodePaymentAddress(addr); - std::string s2 = EncodeSpendingKey(key); + KeyIO keyIO(Params()); + std::string s1 = keyIO.EncodePaymentAddress(addr); + std::string s2 = keyIO.EncodeSpendingKey(key); // There's no way to really delete a private key so we will read in the // exported wallet file and search for the spending key and payment address. @@ -557,11 +560,12 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) // error if too many args BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error); + KeyIO keyIO(Params()); // create a random key locally auto testSpendingKey = libzcash::SproutSpendingKey::random(); auto testPaymentAddress = testSpendingKey.address(); - std::string testAddr = EncodePaymentAddress(testPaymentAddress); - std::string testKey = EncodeSpendingKey(testSpendingKey); + std::string testAddr = keyIO.EncodePaymentAddress(testPaymentAddress); + std::string testKey = keyIO.EncodeSpendingKey(testSpendingKey); // create test data using the random key std::string format_str = "# Wallet dump created by Zcash v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n" @@ -599,7 +603,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) BOOST_CHECK(addrs.size()==1); // check that we have the spending key for the address - auto address = DecodePaymentAddress(testAddr); + auto address = keyIO.DecodePaymentAddress(testAddr); BOOST_CHECK(IsValidPaymentAddress(address)); BOOST_ASSERT(boost::get(&address) != nullptr); auto addr = boost::get(address); @@ -608,7 +612,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) // Verify the spending key is the same as the test data libzcash::SproutSpendingKey k; BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, k)); - BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k)); + BOOST_CHECK_EQUAL(testKey, keyIO.EncodeSpendingKey(k)); } @@ -631,8 +635,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) BOOST_CHECK_THROW(CallRPC("z_exportkey toomany args"), runtime_error); // error if invalid args + KeyIO keyIO(Params()); auto sk = libzcash::SproutSpendingKey::random(); - std::string prefix = std::string("z_importkey ") + EncodeSpendingKey(sk) + " yes "; + std::string prefix = std::string("z_importkey ") + keyIO.EncodeSpendingKey(sk) + " yes "; BOOST_CHECK_THROW(CallRPC(prefix + "-1"), runtime_error); BOOST_CHECK_THROW(CallRPC(prefix + "2147483647"), runtime_error); // allowed, but > height of active chain tip BOOST_CHECK_THROW(CallRPC(prefix + "2147483648"), runtime_error); // not allowed, > int32 used for nHeight @@ -653,8 +658,8 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) // create a random Sprout key locally auto testSpendingKey = libzcash::SproutSpendingKey::random(); auto testPaymentAddress = testSpendingKey.address(); - std::string testAddr = EncodePaymentAddress(testPaymentAddress); - std::string testKey = EncodeSpendingKey(testSpendingKey); + std::string testAddr = keyIO.EncodePaymentAddress(testPaymentAddress); + std::string testKey = keyIO.EncodeSpendingKey(testSpendingKey); BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey)); BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr)); BOOST_CHECK_EQUAL(retValue.get_str(), testKey); @@ -662,8 +667,8 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) // create a random Sapling key locally auto testSaplingSpendingKey = m.Derive(i); auto testSaplingPaymentAddress = testSaplingSpendingKey.DefaultAddress(); - std::string testSaplingAddr = EncodePaymentAddress(testSaplingPaymentAddress); - std::string testSaplingKey = EncodeSpendingKey(testSaplingSpendingKey); + std::string testSaplingAddr = keyIO.EncodePaymentAddress(testSaplingPaymentAddress); + std::string testSaplingKey = keyIO.EncodeSpendingKey(testSaplingSpendingKey); BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testSaplingKey)); BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testSaplingAddr)); BOOST_CHECK_EQUAL(retValue.get_str(), testSaplingKey); @@ -682,7 +687,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) // Make new addresses for the set for (int i=0; iGenerateNewSproutZKey())); + myaddrs.insert(keyIO.EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey())); } // Verify number of addresses stored in wallet is n1+n2 @@ -729,17 +734,18 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_getnewaddress) { pwalletMain->GenerateNewSeed(); } + KeyIO keyIO(Params()); // No parameter defaults to sapling address addr = CallRPC("z_getnewaddress"); - CheckHaveAddr(DecodePaymentAddress(addr.get_str())); + CheckHaveAddr(keyIO.DecodePaymentAddress(addr.get_str())); // Passing 'sapling' should also work addr = CallRPC("z_getnewaddress sapling"); - CheckHaveAddr(DecodePaymentAddress(addr.get_str())); + CheckHaveAddr(keyIO.DecodePaymentAddress(addr.get_str())); // Should also support sprout addr = CallRPC("z_getnewaddress sprout"); - CheckHaveAddr(DecodePaymentAddress(addr.get_str())); + CheckHaveAddr(keyIO.DecodePaymentAddress(addr.get_str())); // Should throw on invalid argument CheckRPCThrows("z_getnewaddress garbage", "Invalid address type"); @@ -1062,7 +1068,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters) std::fill(v.begin(),v.end(), 'A'); std::string badmemo(v.begin(), v.end()); auto pa = pwalletMain->GenerateNewSproutZKey(); - std::string zaddr1 = EncodePaymentAddress(pa); + KeyIO keyIO(Params()); + std::string zaddr1 = keyIO.EncodePaymentAddress(pa); BOOST_CHECK_THROW(CallRPC(string("z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ ") + "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error); @@ -1153,7 +1160,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals) BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress")); std::string taddr1 = retValue.get_str(); auto pa = pwalletMain->GenerateNewSproutZKey(); - std::string zaddr1 = EncodePaymentAddress(pa); + KeyIO keyIO(Params()); + std::string zaddr1 = keyIO.EncodePaymentAddress(pa); // there are no utxos to spend { @@ -1351,11 +1359,12 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_taddr_to_sapling) UniValue retValue; + KeyIO keyIO(Params()); // add keys manually auto taddr = pwalletMain->GenerateNewKey().GetID(); - std::string taddr1 = EncodeDestination(taddr); + std::string taddr1 = keyIO.EncodeDestination(taddr); auto pa = pwalletMain->GenerateNewSaplingZKey(); - std::string zaddr1 = EncodePaymentAddress(pa); + std::string zaddr1 = keyIO.EncodePaymentAddress(pa); auto consensusParams = Params().GetConsensus(); retValue = CallRPC("getblockcount"); @@ -1700,8 +1709,9 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals) CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight + 1); // Add keys manually + KeyIO keyIO(Params()); auto pa = pwalletMain->GenerateNewSproutZKey(); - std::string zaddr = EncodePaymentAddress(pa); + std::string zaddr = keyIO.EncodePaymentAddress(pa); // Insufficient funds { @@ -1908,7 +1918,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals) BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress")); MergeToAddressRecipient taddr1(retValue.get_str(), ""); auto pa = pwalletMain->GenerateNewSproutZKey(); - MergeToAddressRecipient zaddr1(EncodePaymentAddress(pa), "DEADBEEF"); + KeyIO keyIO(Params()); + MergeToAddressRecipient zaddr1(keyIO.EncodePaymentAddress(pa), "DEADBEEF"); // Insufficient funds { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6e20ae6d4..4e953ceca 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -465,9 +465,10 @@ bool CWallet::LoadCScript(const CScript& redeemScript) /* A sanity check was added in pull #3843 to avoid adding redeemScripts * that never can be redeemed. However, old wallets may still contain * these. Do not add them to the wallet and warn. */ + KeyIO keyIO(Params()); if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { - std::string strAddr = EncodeDestination(CScriptID(redeemScript)); + std::string strAddr = keyIO.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; @@ -2271,13 +2272,14 @@ std::pair CWalletTx::DecryptSproutNot auto nd = this->mapSproutNoteData.at(jsop); SproutPaymentAddress pa = nd.address; + KeyIO keyIO(Params()); // Get cached decryptor ZCNoteDecryption decryptor; if (!pwallet->GetNoteDecryptor(pa, decryptor)) { // Note decryptors are created when the wallet is loaded, so it should always exist throw std::runtime_error(strprintf( "Could not find note decryptor for payment address %s", - EncodePaymentAddress(pa))); + keyIO.EncodePaymentAddress(pa))); } auto hSig = this->vJoinSplit[jsop.js].h_sig(this->joinSplitPubKey); @@ -2294,12 +2296,12 @@ std::pair CWalletTx::DecryptSproutNot // Couldn't decrypt with this spending key throw std::runtime_error(strprintf( "Could not decrypt note for payment address %s", - EncodePaymentAddress(pa))); + keyIO.EncodePaymentAddress(pa))); } catch (const std::exception &exc) { // Unexpected failure throw std::runtime_error(strprintf( "Error while decrypting note for payment address %s: %s", - EncodePaymentAddress(pa), exc.what())); + keyIO.EncodePaymentAddress(pa), exc.what())); } } @@ -3955,22 +3957,24 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam } NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO, strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) ); + KeyIO keyIO(Params()); if (!fFileBacked) return false; - if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(EncodeDestination(address), strPurpose)) + if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(keyIO.EncodeDestination(address), strPurpose)) return false; - return CWalletDB(strWalletFile).WriteName(EncodeDestination(address), strName); + return CWalletDB(strWalletFile).WriteName(keyIO.EncodeDestination(address), strName); } bool CWallet::DelAddressBook(const CTxDestination& address) { + KeyIO keyIO(Params()); { LOCK(cs_wallet); // mapAddressBook if(fFileBacked) { // Delete destdata tuples associated with address - std::string strAddress = EncodeDestination(address); + std::string strAddress = keyIO.EncodeDestination(address); BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata) { CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); @@ -3983,8 +3987,8 @@ bool CWallet::DelAddressBook(const CTxDestination& address) if (!fFileBacked) return false; - CWalletDB(strWalletFile).ErasePurpose(EncodeDestination(address)); - return CWalletDB(strWalletFile).EraseName(EncodeDestination(address)); + CWalletDB(strWalletFile).ErasePurpose(keyIO.EncodeDestination(address)); + return CWalletDB(strWalletFile).EraseName(keyIO.EncodeDestination(address)); } bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) @@ -4558,7 +4562,8 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); if (!fFileBacked) return true; - return CWalletDB(strWalletFile).WriteDestData(EncodeDestination(dest), key, value); + KeyIO keyIO(Params()); + return CWalletDB(strWalletFile).WriteDestData(keyIO.EncodeDestination(dest), key, value); } bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key) @@ -4567,7 +4572,8 @@ bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key) return false; if (!fFileBacked) return true; - return CWalletDB(strWalletFile).EraseDestData(EncodeDestination(dest), key); + KeyIO keyIO(Params()); + return CWalletDB(strWalletFile).EraseDestData(keyIO.EncodeDestination(dest), key); } bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) @@ -4842,10 +4848,11 @@ bool CWallet::ParameterInteraction() bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS); + KeyIO keyIO(Params()); // Check Sapling migration address if set and is a valid Sapling address if (mapArgs.count("-migrationdestaddress")) { std::string migrationDestAddress = mapArgs["-migrationdestaddress"]; - libzcash::PaymentAddress address = DecodePaymentAddress(migrationDestAddress); + libzcash::PaymentAddress address = keyIO.DecodePaymentAddress(migrationDestAddress); if (boost::get(&address) == nullptr) { return UIError(_("-migrationdestaddress must be a valid Sapling address.")); } @@ -4957,8 +4964,9 @@ void CWallet::GetFilteredNotes( { std::set filterAddresses; + KeyIO keyIO(Params()); if (address.length() > 0) { - filterAddresses.insert(DecodePaymentAddress(address)); + filterAddresses.insert(keyIO.DecodePaymentAddress(address)); } GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey); @@ -4981,6 +4989,7 @@ void CWallet::GetFilteredNotes( { LOCK2(cs_main, cs_wallet); + KeyIO keyIO(Params()); for (auto & p : mapWallet) { CWalletTx wtx = p.second; @@ -5028,7 +5037,7 @@ void CWallet::GetFilteredNotes( ZCNoteDecryption decryptor; if (!GetNoteDecryptor(pa, decryptor)) { // Note decryptors are created when the wallet is loaded, so it should always exist - throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa))); + throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", keyIO.EncodePaymentAddress(pa))); } // determine amount of funds in the note @@ -5046,10 +5055,10 @@ void CWallet::GetFilteredNotes( } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key - throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa))); + throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", keyIO.EncodePaymentAddress(pa))); } catch (const std::exception &exc) { // Unexpected failure - throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what())); + throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", keyIO.EncodePaymentAddress(pa), exc.what())); } } @@ -5236,8 +5245,9 @@ KeyAddResult AddViewingKeyToWallet::operator()(const libzcash::InvalidEncoding& KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKey &sk) const { auto addr = sk.address(); + KeyIO keyIO(Params()); if (log){ - LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr)); + LogPrint("zrpc", "Importing zaddr %s...\n", keyIO.EncodePaymentAddress(addr)); } if (m_wallet->HaveSproutSpendingKey(addr)) { return KeyAlreadyExists; @@ -5252,9 +5262,10 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKe KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const { auto extfvk = sk.ToXFVK(); auto ivk = extfvk.fvk.in_viewing_key(); + KeyIO keyIO(Params()); { if (log){ - LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(sk.DefaultAddress())); + LogPrint("zrpc", "Importing zaddr %s...\n", keyIO.EncodePaymentAddress(sk.DefaultAddress())); } // Don't throw error in case a key is already there if (m_wallet->HaveSaplingSpendingKey(extfvk)) { diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index af35606ee..da7d9756f 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -458,6 +458,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CWalletScanState &wss, string& strType, string& strErr) { try { + KeyIO keyIO(Params()); + // Unserialize // Taking advantage of the fact that pair serialization // is just the two items serialized one after the other @@ -466,13 +468,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { string strAddress; ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name; + ssValue >> pwallet->mapAddressBook[keyIO.DecodeDestination(strAddress)].name; } else if (strType == "purpose") { string strAddress; ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose; + ssValue >> pwallet->mapAddressBook[keyIO.DecodeDestination(strAddress)].purpose; } else if (strType == "tx") { @@ -829,7 +831,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssKey >> strAddress; ssKey >> strKey; ssValue >> strValue; - if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue)) + if (!pwallet->LoadDestData(keyIO.DecodeDestination(strAddress), strKey, strValue)) { strErr = "Error reading wallet database: LoadDestData failed"; return false;