Move parsing of unified addresses to UnifiedAddress.
In cases where we want to be able to decode a string that is known to be a unified address, it doesn't make sense to have to route through KeyIO::DecodePaymentAddress and then return an error depending upon the result type, when it's possible to provide unified address parsing more directly. KeyIO::DecodePaymentAddress has been modified to delegate to UnifiedAddress::Parse
This commit is contained in:
parent
73a75a37fe
commit
d08c992b5e
|
@ -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<unsigned char> 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<unsigned char> 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<unsigned char> 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<unsigned char> 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<unsigned char> 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<unsigned char> 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<unsigned char> 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<T1> DecodeAny(
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* `raw` MUST be 43 bytes.
|
||||
*/
|
||||
static bool AddSaplingReceiver(void* ua, const unsigned char* raw)
|
||||
{
|
||||
CDataStream ss(
|
||||
reinterpret_cast<const char*>(raw),
|
||||
reinterpret_cast<const char*>(raw + 43),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
libzcash::SaplingPaymentAddress receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* `raw` MUST be 20 bytes.
|
||||
*/
|
||||
static bool AddP2SHReceiver(void* ua, const unsigned char* raw)
|
||||
{
|
||||
CDataStream ss(
|
||||
reinterpret_cast<const char*>(raw),
|
||||
reinterpret_cast<const char*>(raw + 20),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
CScriptID receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* `raw` MUST be 20 bytes.
|
||||
*/
|
||||
static bool AddP2PKHReceiver(void* ua, const unsigned char* raw)
|
||||
{
|
||||
CDataStream ss(
|
||||
reinterpret_cast<const char*>(raw),
|
||||
reinterpret_cast<const char*>(raw + 20),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
CKeyID receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(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<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
||||
std::optional<libzcash::PaymentAddress> KeyIO::DecodePaymentAddress(const std::string& str)
|
||||
std::optional<libzcash::PaymentAddress> 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<libzcash::PaymentAddress> 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<libzcash::ViewingKey> KeyIO::DecodeViewingKey(const std::string& str)
|
||||
std::optional<libzcash::ViewingKey> 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<libzcash::ViewingKey> 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<libzcash::SpendingKey> KeyIO::DecodeSpendingKey(const std::string& str)
|
||||
std::optional<libzcash::SpendingKey> KeyIO::DecodeSpendingKey(const std::string& str) const
|
||||
{
|
||||
|
||||
return DecodeAny<libzcash::SpendingKey,
|
||||
|
|
32
src/key_io.h
32
src/key_io.h
|
@ -23,28 +23,28 @@ private:
|
|||
public:
|
||||
KeyIO(const KeyConstants& keyConstants): keyConstants(keyConstants) { }
|
||||
|
||||
CKey DecodeSecret(const std::string& str);
|
||||
std::string EncodeSecret(const CKey& key);
|
||||
CKey DecodeSecret(const std::string& str) const;
|
||||
std::string EncodeSecret(const CKey& key) const;
|
||||
|
||||
CExtKey DecodeExtKey(const std::string& str);
|
||||
std::string EncodeExtKey(const CExtKey& extkey);
|
||||
CExtPubKey DecodeExtPubKey(const std::string& str);
|
||||
std::string EncodeExtPubKey(const CExtPubKey& extpubkey);
|
||||
CExtKey DecodeExtKey(const std::string& str) const;
|
||||
std::string EncodeExtKey(const CExtKey& extkey) const;
|
||||
CExtPubKey DecodeExtPubKey(const std::string& str) const;
|
||||
std::string EncodeExtPubKey(const CExtPubKey& extpubkey) const;
|
||||
|
||||
std::string EncodeDestination(const CTxDestination& dest);
|
||||
CTxDestination DecodeDestination(const std::string& str);
|
||||
std::string EncodeDestination(const CTxDestination& dest) const;
|
||||
CTxDestination DecodeDestination(const std::string& str) const;
|
||||
|
||||
bool IsValidDestinationString(const std::string& str);
|
||||
bool IsValidDestinationString(const std::string& str) const;
|
||||
|
||||
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr);
|
||||
std::optional<libzcash::PaymentAddress> DecodePaymentAddress(const std::string& str);
|
||||
bool IsValidPaymentAddressString(const std::string& str);
|
||||
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) const;
|
||||
std::optional<libzcash::PaymentAddress> DecodePaymentAddress(const std::string& str) const;
|
||||
bool IsValidPaymentAddressString(const std::string& str) const;
|
||||
|
||||
std::string EncodeViewingKey(const libzcash::ViewingKey& vk);
|
||||
std::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str);
|
||||
std::string EncodeViewingKey(const libzcash::ViewingKey& vk) const;
|
||||
std::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str) const;
|
||||
|
||||
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey);
|
||||
std::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str);
|
||||
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) const;
|
||||
std::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_KEY_IO_H
|
||||
|
|
|
@ -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<libzcash::UnifiedAddress>(&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;
|
||||
|
|
|
@ -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<const char*>(raw),
|
||||
reinterpret_cast<const char*>(raw + 43),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
libzcash::SaplingPaymentAddress receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* `raw` MUST be 20 bytes.
|
||||
*/
|
||||
static bool AddP2SHReceiver(void* ua, const unsigned char* raw)
|
||||
{
|
||||
CDataStream ss(
|
||||
reinterpret_cast<const char*>(raw),
|
||||
reinterpret_cast<const char*>(raw + 20),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
CScriptID receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* `raw` MUST be 20 bytes.
|
||||
*/
|
||||
static bool AddP2PKHReceiver(void* ua, const unsigned char* raw)
|
||||
{
|
||||
CDataStream ss(
|
||||
reinterpret_cast<const char*>(raw),
|
||||
reinterpret_cast<const char*>(raw + 20),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
CKeyID receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(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<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
||||
std::optional<UnifiedAddress> 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<const Receiver*> UnifiedAddress::GetSorted() const {
|
||||
std::vector<const libzcash::Receiver*> sorted;
|
||||
for (const auto& receiver : receivers) {
|
||||
|
|
|
@ -66,6 +66,8 @@ class UnifiedAddress {
|
|||
public:
|
||||
UnifiedAddress() {}
|
||||
|
||||
static std::optional<UnifiedAddress> Parse(const KeyConstants& keyConstants, const std::string& str);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
|
|
Loading…
Reference in New Issue