diff --git a/src/key_io.cpp b/src/key_io.cpp index b1c5daf95..76eef0800 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -247,7 +247,7 @@ const size_t ConvertedSaplingExtendedFullViewingKeySize = (ZIP32_XFVK_SIZE * 8 + const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5; } // namespace -CTxDestination KeyIO::DecodeDestination(const std::string& str) +CTxDestination KeyIO::DecodeDestination(const std::string& str) const { std::vector data; uint160 hash; @@ -271,7 +271,7 @@ CTxDestination KeyIO::DecodeDestination(const std::string& str) return CNoDestination(); }; -CKey KeyIO::DecodeSecret(const std::string& str) +CKey KeyIO::DecodeSecret(const std::string& str) const { CKey key; std::vector data; @@ -287,7 +287,7 @@ CKey KeyIO::DecodeSecret(const std::string& str) return key; } -std::string KeyIO::EncodeSecret(const CKey& key) +std::string KeyIO::EncodeSecret(const CKey& key) const { assert(key.IsValid()); std::vector data = keyConstants.Base58Prefix(KeyConstants::SECRET_KEY); @@ -300,7 +300,7 @@ std::string KeyIO::EncodeSecret(const CKey& key) return ret; } -CExtPubKey KeyIO::DecodeExtPubKey(const std::string& str) +CExtPubKey KeyIO::DecodeExtPubKey(const std::string& str) const { CExtPubKey key; std::vector data; @@ -313,7 +313,7 @@ CExtPubKey KeyIO::DecodeExtPubKey(const std::string& str) return key; } -std::string KeyIO::EncodeExtPubKey(const CExtPubKey& key) +std::string KeyIO::EncodeExtPubKey(const CExtPubKey& key) const { std::vector data = keyConstants.Base58Prefix(KeyConstants::EXT_PUBLIC_KEY); size_t size = data.size(); @@ -323,7 +323,7 @@ std::string KeyIO::EncodeExtPubKey(const CExtPubKey& key) return ret; } -CExtKey KeyIO::DecodeExtKey(const std::string& str) +CExtKey KeyIO::DecodeExtKey(const std::string& str) const { CExtKey key; std::vector data; @@ -336,7 +336,7 @@ CExtKey KeyIO::DecodeExtKey(const std::string& str) return key; } -std::string KeyIO::EncodeExtKey(const CExtKey& key) +std::string KeyIO::EncodeExtKey(const CExtKey& key) const { std::vector data = keyConstants.Base58Prefix(KeyConstants::EXT_SECRET_KEY); size_t size = data.size(); @@ -347,17 +347,17 @@ std::string KeyIO::EncodeExtKey(const CExtKey& key) return ret; } -std::string KeyIO::EncodeDestination(const CTxDestination& dest) +std::string KeyIO::EncodeDestination(const CTxDestination& dest) const { return std::visit(DestinationEncoder(keyConstants), dest); } -bool KeyIO::IsValidDestinationString(const std::string& str) +bool KeyIO::IsValidDestinationString(const std::string& str) const { return IsValidDestination(DecodeDestination(str)); } -std::string KeyIO::EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) +std::string KeyIO::EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) const { return std::visit(PaymentAddressEncoder(keyConstants), zaddr); } @@ -433,71 +433,12 @@ std::optional DecodeAny( return std::nullopt; } -/** - * `raw` MUST be 43 bytes. - */ -static bool AddSaplingReceiver(void* ua, const unsigned char* raw) -{ - CDataStream ss( - reinterpret_cast(raw), - reinterpret_cast(raw + 43), - SER_NETWORK, - PROTOCOL_VERSION); - libzcash::SaplingPaymentAddress receiver; - ss >> receiver; - return reinterpret_cast(ua)->AddReceiver(receiver); -} - -/** - * `raw` MUST be 20 bytes. - */ -static bool AddP2SHReceiver(void* ua, const unsigned char* raw) -{ - CDataStream ss( - reinterpret_cast(raw), - reinterpret_cast(raw + 20), - SER_NETWORK, - PROTOCOL_VERSION); - CScriptID receiver; - ss >> receiver; - return reinterpret_cast(ua)->AddReceiver(receiver); -} - -/** - * `raw` MUST be 20 bytes. - */ -static bool AddP2PKHReceiver(void* ua, const unsigned char* raw) -{ - CDataStream ss( - reinterpret_cast(raw), - reinterpret_cast(raw + 20), - SER_NETWORK, - PROTOCOL_VERSION); - CKeyID receiver; - ss >> receiver; - return reinterpret_cast(ua)->AddReceiver(receiver); -} - -static bool AddUnknownReceiver(void* ua, uint32_t typecode, const unsigned char* data, size_t len) -{ - libzcash::UnknownReceiver receiver(typecode, std::vector(data, data + len)); - return reinterpret_cast(ua)->AddReceiver(receiver); -} - -std::optional KeyIO::DecodePaymentAddress(const std::string& str) +std::optional KeyIO::DecodePaymentAddress(const std::string& str) const { // Try parsing as a Unified Address. - libzcash::UnifiedAddress ua; - if (zcash_address_parse_unified( - str.c_str(), - keyConstants.NetworkIDString().c_str(), - &ua, - AddSaplingReceiver, - AddP2SHReceiver, - AddP2PKHReceiver, - AddUnknownReceiver) - ) { - return ua; + auto ua = libzcash::UnifiedAddress::Parse(keyConstants, str); + if (ua.has_value()) { + return ua.value(); } // Try parsing as a Sapling address @@ -535,16 +476,17 @@ std::optional KeyIO::DecodePaymentAddress(const std::s }, DecodeDestination(str)); } -bool KeyIO::IsValidPaymentAddressString(const std::string& str) { +bool KeyIO::IsValidPaymentAddressString(const std::string& str) const +{ return DecodePaymentAddress(str).has_value(); } -std::string KeyIO::EncodeViewingKey(const libzcash::ViewingKey& vk) +std::string KeyIO::EncodeViewingKey(const libzcash::ViewingKey& vk) const { return std::visit(ViewingKeyEncoder(keyConstants), vk); } -std::optional KeyIO::DecodeViewingKey(const std::string& str) +std::optional KeyIO::DecodeViewingKey(const std::string& str) const { // Try parsing as a Unified full viewing key auto ufvk = libzcash::UnifiedFullViewingKey::Decode(str, keyConstants); @@ -563,12 +505,12 @@ std::optional KeyIO::DecodeViewingKey(const std::string& s ); } -std::string KeyIO::EncodeSpendingKey(const libzcash::SpendingKey& zkey) +std::string KeyIO::EncodeSpendingKey(const libzcash::SpendingKey& zkey) const { return std::visit(SpendingKeyEncoder(keyConstants), zkey); } -std::optional KeyIO::DecodeSpendingKey(const std::string& str) +std::optional KeyIO::DecodeSpendingKey(const std::string& str) const { return DecodeAny DecodePaymentAddress(const std::string& str); - bool IsValidPaymentAddressString(const std::string& str); + std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) const; + std::optional DecodePaymentAddress(const std::string& str) const; + bool IsValidPaymentAddressString(const std::string& str) const; - std::string EncodeViewingKey(const libzcash::ViewingKey& vk); - std::optional DecodeViewingKey(const std::string& str); + std::string EncodeViewingKey(const libzcash::ViewingKey& vk) const; + std::optional DecodeViewingKey(const std::string& str) const; - std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey); - std::optional DecodeSpendingKey(const std::string& str); + std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) const; + std::optional DecodeSpendingKey(const std::string& str) const; }; #endif // BITCOIN_KEY_IO_H diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 7c1fa7344..b870124ad 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -864,16 +864,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssKey >> recipient; ssValue >> rawUa; - auto pa = keyIO.DecodePaymentAddress(rawUa); - if (!pa.has_value()) { + auto ua = libzcash::UnifiedAddress::Parse(Params(), rawUa); + if (!ua.has_value()) { strErr = "Error in wallet database: non-UnifiedAddress in recipientmapping"; return false; } - auto uaPtr = std::get_if(&pa.value()); - if (uaPtr == nullptr) { - strErr = "Error in wallet database: failed to deserialize unified address"; - return false; - } libzcash::Receiver recipientReceiver; std::visit(match { @@ -883,7 +878,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, }, recipient.recipient); bool found = false; - for (const auto& receiver : uaPtr->GetReceiversAsParsed()) { + for (const auto& receiver : ua.value().GetReceiversAsParsed()) { if (receiver == recipientReceiver) { found = true; break; diff --git a/src/zcash/Address.cpp b/src/zcash/Address.cpp index bef1ca439..490c6507d 100644 --- a/src/zcash/Address.cpp +++ b/src/zcash/Address.cpp @@ -16,6 +16,74 @@ namespace libzcash { // Unified Addresses // +/** + * `raw` MUST be 43 bytes. + */ +static bool AddSaplingReceiver(void* ua, const unsigned char* raw) +{ + CDataStream ss( + reinterpret_cast(raw), + reinterpret_cast(raw + 43), + SER_NETWORK, + PROTOCOL_VERSION); + libzcash::SaplingPaymentAddress receiver; + ss >> receiver; + return reinterpret_cast(ua)->AddReceiver(receiver); +} + +/** + * `raw` MUST be 20 bytes. + */ +static bool AddP2SHReceiver(void* ua, const unsigned char* raw) +{ + CDataStream ss( + reinterpret_cast(raw), + reinterpret_cast(raw + 20), + SER_NETWORK, + PROTOCOL_VERSION); + CScriptID receiver; + ss >> receiver; + return reinterpret_cast(ua)->AddReceiver(receiver); +} + +/** + * `raw` MUST be 20 bytes. + */ +static bool AddP2PKHReceiver(void* ua, const unsigned char* raw) +{ + CDataStream ss( + reinterpret_cast(raw), + reinterpret_cast(raw + 20), + SER_NETWORK, + PROTOCOL_VERSION); + CKeyID receiver; + ss >> receiver; + return reinterpret_cast(ua)->AddReceiver(receiver); +} + +static bool AddUnknownReceiver(void* ua, uint32_t typecode, const unsigned char* data, size_t len) +{ + libzcash::UnknownReceiver receiver(typecode, std::vector(data, data + len)); + return reinterpret_cast(ua)->AddReceiver(receiver); +} + +std::optional UnifiedAddress::Parse(const KeyConstants& keyConstants, const std::string& str) { + libzcash::UnifiedAddress ua; + if (zcash_address_parse_unified( + str.c_str(), + keyConstants.NetworkIDString().c_str(), + &ua, + AddSaplingReceiver, + AddP2SHReceiver, + AddP2PKHReceiver, + AddUnknownReceiver) + ) { + return ua; + } else { + return std::nullopt; + } +} + std::vector UnifiedAddress::GetSorted() const { std::vector sorted; for (const auto& receiver : receivers) { diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index eb4bbab65..a230d51b9 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -66,6 +66,8 @@ class UnifiedAddress { public: UnifiedAddress() {} + static std::optional Parse(const KeyConstants& keyConstants, const std::string& str); + ADD_SERIALIZE_METHODS; template